mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-08 01:15:00 +00:00
Support for Postgres CREATE SERVER
(#1914)
Some checks failed
license / Release Audit Tool (RAT) (push) Has been cancelled
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (beta) (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
Some checks failed
license / Release Audit Tool (RAT) (push) Has been cancelled
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (beta) (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
This commit is contained in:
parent
9020385c02
commit
239e30a97c
5 changed files with 196 additions and 0 deletions
|
@ -3318,6 +3318,8 @@ pub enum Statement {
|
||||||
secret_type: Ident,
|
secret_type: Ident,
|
||||||
options: Vec<SecretOption>,
|
options: Vec<SecretOption>,
|
||||||
},
|
},
|
||||||
|
/// A `CREATE SERVER` statement.
|
||||||
|
CreateServer(CreateServerStatement),
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// CREATE POLICY
|
/// CREATE POLICY
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -5178,6 +5180,9 @@ impl fmt::Display for Statement {
|
||||||
write!(f, " )")?;
|
write!(f, " )")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Statement::CreateServer(stmt) => {
|
||||||
|
write!(f, "{stmt}")
|
||||||
|
}
|
||||||
Statement::CreatePolicy {
|
Statement::CreatePolicy {
|
||||||
name,
|
name,
|
||||||
table_name,
|
table_name,
|
||||||
|
@ -7976,6 +7981,70 @@ impl fmt::Display for SecretOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A `CREATE SERVER` statement.
|
||||||
|
///
|
||||||
|
/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-createserver.html)
|
||||||
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
|
pub struct CreateServerStatement {
|
||||||
|
pub name: ObjectName,
|
||||||
|
pub if_not_exists: bool,
|
||||||
|
pub server_type: Option<Ident>,
|
||||||
|
pub version: Option<Ident>,
|
||||||
|
pub foreign_data_wrapper: ObjectName,
|
||||||
|
pub options: Option<Vec<CreateServerOption>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for CreateServerStatement {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let CreateServerStatement {
|
||||||
|
name,
|
||||||
|
if_not_exists,
|
||||||
|
server_type,
|
||||||
|
version,
|
||||||
|
foreign_data_wrapper,
|
||||||
|
options,
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"CREATE SERVER {if_not_exists}{name} ",
|
||||||
|
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if let Some(st) = server_type {
|
||||||
|
write!(f, "TYPE {st} ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = version {
|
||||||
|
write!(f, "VERSION {v} ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, "FOREIGN DATA WRAPPER {foreign_data_wrapper}")?;
|
||||||
|
|
||||||
|
if let Some(o) = options {
|
||||||
|
write!(f, " OPTIONS ({o})", o = display_comma_separated(o))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
|
pub struct CreateServerOption {
|
||||||
|
pub key: Ident,
|
||||||
|
pub value: Ident,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for CreateServerOption {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{} {}", self.key, self.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
|
|
|
@ -423,6 +423,7 @@ impl Spanned for Statement {
|
||||||
Statement::CreateIndex(create_index) => create_index.span(),
|
Statement::CreateIndex(create_index) => create_index.span(),
|
||||||
Statement::CreateRole { .. } => Span::empty(),
|
Statement::CreateRole { .. } => Span::empty(),
|
||||||
Statement::CreateSecret { .. } => Span::empty(),
|
Statement::CreateSecret { .. } => Span::empty(),
|
||||||
|
Statement::CreateServer { .. } => Span::empty(),
|
||||||
Statement::CreateConnector { .. } => Span::empty(),
|
Statement::CreateConnector { .. } => Span::empty(),
|
||||||
Statement::AlterTable {
|
Statement::AlterTable {
|
||||||
name,
|
name,
|
||||||
|
|
|
@ -816,6 +816,7 @@ define_keywords!(
|
||||||
SERDE,
|
SERDE,
|
||||||
SERDEPROPERTIES,
|
SERDEPROPERTIES,
|
||||||
SERIALIZABLE,
|
SERIALIZABLE,
|
||||||
|
SERVER,
|
||||||
SERVICE,
|
SERVICE,
|
||||||
SESSION,
|
SESSION,
|
||||||
SESSION_USER,
|
SESSION_USER,
|
||||||
|
@ -1017,6 +1018,7 @@ define_keywords!(
|
||||||
WITHOUT,
|
WITHOUT,
|
||||||
WITHOUT_ARRAY_WRAPPER,
|
WITHOUT_ARRAY_WRAPPER,
|
||||||
WORK,
|
WORK,
|
||||||
|
WRAPPER,
|
||||||
WRITE,
|
WRITE,
|
||||||
XML,
|
XML,
|
||||||
XMLNAMESPACES,
|
XMLNAMESPACES,
|
||||||
|
|
|
@ -4674,6 +4674,8 @@ impl<'a> Parser<'a> {
|
||||||
self.parse_create_procedure(or_alter)
|
self.parse_create_procedure(or_alter)
|
||||||
} else if self.parse_keyword(Keyword::CONNECTOR) {
|
} else if self.parse_keyword(Keyword::CONNECTOR) {
|
||||||
self.parse_create_connector()
|
self.parse_create_connector()
|
||||||
|
} else if self.parse_keyword(Keyword::SERVER) {
|
||||||
|
self.parse_pg_create_server()
|
||||||
} else {
|
} else {
|
||||||
self.expected("an object type after CREATE", self.peek_token())
|
self.expected("an object type after CREATE", self.peek_token())
|
||||||
}
|
}
|
||||||
|
@ -16009,6 +16011,49 @@ impl<'a> Parser<'a> {
|
||||||
Ok(sequence_options)
|
Ok(sequence_options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a `CREATE SERVER` statement.
|
||||||
|
///
|
||||||
|
/// See [Statement::CreateServer]
|
||||||
|
pub fn parse_pg_create_server(&mut self) -> Result<Statement, ParserError> {
|
||||||
|
let ine = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
|
||||||
|
let name = self.parse_object_name(false)?;
|
||||||
|
|
||||||
|
let server_type = if self.parse_keyword(Keyword::TYPE) {
|
||||||
|
Some(self.parse_identifier()?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let version = if self.parse_keyword(Keyword::VERSION) {
|
||||||
|
Some(self.parse_identifier()?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
self.expect_keywords(&[Keyword::FOREIGN, Keyword::DATA, Keyword::WRAPPER])?;
|
||||||
|
let foreign_data_wrapper = self.parse_object_name(false)?;
|
||||||
|
|
||||||
|
let mut options = None;
|
||||||
|
if self.parse_keyword(Keyword::OPTIONS) {
|
||||||
|
self.expect_token(&Token::LParen)?;
|
||||||
|
options = Some(self.parse_comma_separated(|p| {
|
||||||
|
let key = p.parse_identifier()?;
|
||||||
|
let value = p.parse_identifier()?;
|
||||||
|
Ok(CreateServerOption { key, value })
|
||||||
|
})?);
|
||||||
|
self.expect_token(&Token::RParen)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Statement::CreateServer(CreateServerStatement {
|
||||||
|
name,
|
||||||
|
if_not_exists: ine,
|
||||||
|
server_type,
|
||||||
|
version,
|
||||||
|
foreign_data_wrapper,
|
||||||
|
options,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
/// The index of the first unprocessed token.
|
/// The index of the first unprocessed token.
|
||||||
pub fn index(&self) -> usize {
|
pub fn index(&self) -> usize {
|
||||||
self.index
|
self.index
|
||||||
|
|
|
@ -6273,3 +6273,82 @@ fn parse_alter_table_validate_constraint() {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_create_server() {
|
||||||
|
let test_cases = vec![
|
||||||
|
(
|
||||||
|
"CREATE SERVER myserver FOREIGN DATA WRAPPER postgres_fdw",
|
||||||
|
CreateServerStatement {
|
||||||
|
name: ObjectName::from(vec!["myserver".into()]),
|
||||||
|
if_not_exists: false,
|
||||||
|
server_type: None,
|
||||||
|
version: None,
|
||||||
|
foreign_data_wrapper: ObjectName::from(vec!["postgres_fdw".into()]),
|
||||||
|
options: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"CREATE SERVER IF NOT EXISTS myserver TYPE 'server_type' VERSION 'server_version' FOREIGN DATA WRAPPER postgres_fdw",
|
||||||
|
CreateServerStatement {
|
||||||
|
name: ObjectName::from(vec!["myserver".into()]),
|
||||||
|
if_not_exists: true,
|
||||||
|
server_type: Some(Ident {
|
||||||
|
value: "server_type".to_string(),
|
||||||
|
quote_style: Some('\''),
|
||||||
|
span: Span::empty(),
|
||||||
|
}),
|
||||||
|
version: Some(Ident {
|
||||||
|
value: "server_version".to_string(),
|
||||||
|
quote_style: Some('\''),
|
||||||
|
span: Span::empty(),
|
||||||
|
}),
|
||||||
|
foreign_data_wrapper: ObjectName::from(vec!["postgres_fdw".into()]),
|
||||||
|
options: None,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"CREATE SERVER myserver2 FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host 'foo', dbname 'foodb', port '5432')",
|
||||||
|
CreateServerStatement {
|
||||||
|
name: ObjectName::from(vec!["myserver2".into()]),
|
||||||
|
if_not_exists: false,
|
||||||
|
server_type: None,
|
||||||
|
version: None,
|
||||||
|
foreign_data_wrapper: ObjectName::from(vec!["postgres_fdw".into()]),
|
||||||
|
options: Some(vec![
|
||||||
|
CreateServerOption {
|
||||||
|
key: "host".into(),
|
||||||
|
value: Ident {
|
||||||
|
value: "foo".to_string(),
|
||||||
|
quote_style: Some('\''),
|
||||||
|
span: Span::empty(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CreateServerOption {
|
||||||
|
key: "dbname".into(),
|
||||||
|
value: Ident {
|
||||||
|
value: "foodb".to_string(),
|
||||||
|
quote_style: Some('\''),
|
||||||
|
span: Span::empty(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CreateServerOption {
|
||||||
|
key: "port".into(),
|
||||||
|
value: Ident {
|
||||||
|
value: "5432".to_string(),
|
||||||
|
quote_style: Some('\''),
|
||||||
|
span: Span::empty(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
for (sql, expected) in test_cases {
|
||||||
|
let Statement::CreateServer(stmt) = pg_and_generic().verified_stmt(sql) else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
assert_eq!(stmt, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue