mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-07 17:04:59 +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,
|
||||
options: Vec<SecretOption>,
|
||||
},
|
||||
/// A `CREATE SERVER` statement.
|
||||
CreateServer(CreateServerStatement),
|
||||
/// ```sql
|
||||
/// CREATE POLICY
|
||||
/// ```
|
||||
|
@ -5178,6 +5180,9 @@ impl fmt::Display for Statement {
|
|||
write!(f, " )")?;
|
||||
Ok(())
|
||||
}
|
||||
Statement::CreateServer(stmt) => {
|
||||
write!(f, "{stmt}")
|
||||
}
|
||||
Statement::CreatePolicy {
|
||||
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)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
|
|
|
@ -423,6 +423,7 @@ impl Spanned for Statement {
|
|||
Statement::CreateIndex(create_index) => create_index.span(),
|
||||
Statement::CreateRole { .. } => Span::empty(),
|
||||
Statement::CreateSecret { .. } => Span::empty(),
|
||||
Statement::CreateServer { .. } => Span::empty(),
|
||||
Statement::CreateConnector { .. } => Span::empty(),
|
||||
Statement::AlterTable {
|
||||
name,
|
||||
|
|
|
@ -816,6 +816,7 @@ define_keywords!(
|
|||
SERDE,
|
||||
SERDEPROPERTIES,
|
||||
SERIALIZABLE,
|
||||
SERVER,
|
||||
SERVICE,
|
||||
SESSION,
|
||||
SESSION_USER,
|
||||
|
@ -1017,6 +1018,7 @@ define_keywords!(
|
|||
WITHOUT,
|
||||
WITHOUT_ARRAY_WRAPPER,
|
||||
WORK,
|
||||
WRAPPER,
|
||||
WRITE,
|
||||
XML,
|
||||
XMLNAMESPACES,
|
||||
|
|
|
@ -4674,6 +4674,8 @@ impl<'a> Parser<'a> {
|
|||
self.parse_create_procedure(or_alter)
|
||||
} else if self.parse_keyword(Keyword::CONNECTOR) {
|
||||
self.parse_create_connector()
|
||||
} else if self.parse_keyword(Keyword::SERVER) {
|
||||
self.parse_pg_create_server()
|
||||
} else {
|
||||
self.expected("an object type after CREATE", self.peek_token())
|
||||
}
|
||||
|
@ -16009,6 +16011,49 @@ impl<'a> Parser<'a> {
|
|||
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.
|
||||
pub fn index(&self) -> usize {
|
||||
self.index
|
||||
|
|
|
@ -6273,3 +6273,82 @@ fn parse_alter_table_validate_constraint() {
|
|||
_ => 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