This is an automated email from the ASF dual-hosted git repository.
iffyio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 486b29ff Add support for `CREATE/ALTER/DROP CONNECTOR` syntax (#1701)
486b29ff is described below
commit 486b29ffab6092d01807fee84701e397bcd73bd9
Author: wugeer <[email protected]>
AuthorDate: Wed Feb 5 01:33:12 2025 +0800
Add support for `CREATE/ALTER/DROP CONNECTOR` syntax (#1701)
---
src/ast/ddl.rs | 83 +++++++++++++++++++++--
src/ast/mod.rs | 71 ++++++++++++++++---
src/ast/spans.rs | 3 +
src/dialect/mod.rs | 1 +
src/keywords.rs | 2 +
src/parser/alter.rs | 45 +++++++++++-
src/parser/mod.rs | 61 ++++++++++++++++-
tests/sqlparser_common.rs | 169 ++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 420 insertions(+), 15 deletions(-)
diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs
index 1b5ccda2..35e01e61 100644
--- a/src/ast/ddl.rs
+++ b/src/ast/ddl.rs
@@ -30,10 +30,10 @@ use sqlparser_derive::{Visit, VisitMut};
use crate::ast::value::escape_single_quote_string;
use crate::ast::{
- display_comma_separated, display_separated, CreateFunctionBody,
CreateFunctionUsing, DataType,
- Expr, FunctionBehavior, FunctionCalledOnNull,
FunctionDeterminismSpecifier, FunctionParallel,
- Ident, MySQLColumnPosition, ObjectName, OperateFunctionArg, OrderByExpr,
ProjectionSelect,
- SequenceOptions, SqlOption, Tag, Value,
+ display_comma_separated, display_separated, CommentDef, CreateFunctionBody,
+ CreateFunctionUsing, DataType, Expr, FunctionBehavior,
FunctionCalledOnNull,
+ FunctionDeterminismSpecifier, FunctionParallel, Ident,
MySQLColumnPosition, ObjectName,
+ OperateFunctionArg, OrderByExpr, ProjectionSelect, SequenceOptions,
SqlOption, Tag, Value,
};
use crate::keywords::Keyword;
use crate::tokenizer::Token;
@@ -338,6 +338,23 @@ impl fmt::Display for Owner {
}
}
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum AlterConnectorOwner {
+ User(Ident),
+ Role(Ident),
+}
+
+impl fmt::Display for AlterConnectorOwner {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ AlterConnectorOwner::User(ident) => write!(f, "USER {ident}"),
+ AlterConnectorOwner::Role(ident) => write!(f, "ROLE {ident}"),
+ }
+ }
+}
+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
@@ -2055,3 +2072,61 @@ impl fmt::Display for CreateFunction {
Ok(())
}
}
+
+/// ```sql
+/// CREATE CONNECTOR [IF NOT EXISTS] connector_name
+/// [TYPE datasource_type]
+/// [URL datasource_url]
+/// [COMMENT connector_comment]
+/// [WITH DCPROPERTIES(property_name=property_value, ...)]
+/// ```
+///
+///
[Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct CreateConnector {
+ pub name: Ident,
+ pub if_not_exists: bool,
+ pub connector_type: Option<String>,
+ pub url: Option<String>,
+ pub comment: Option<CommentDef>,
+ pub with_dcproperties: Option<Vec<SqlOption>>,
+}
+
+impl fmt::Display for CreateConnector {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "CREATE CONNECTOR {if_not_exists}{name}",
+ if_not_exists = if self.if_not_exists {
+ "IF NOT EXISTS "
+ } else {
+ ""
+ },
+ name = self.name,
+ )?;
+
+ if let Some(connector_type) = &self.connector_type {
+ write!(f, " TYPE '{connector_type}'")?;
+ }
+
+ if let Some(url) = &self.url {
+ write!(f, " URL '{url}'")?;
+ }
+
+ if let Some(comment) = &self.comment {
+ write!(f, " COMMENT = '{comment}'")?;
+ }
+
+ if let Some(with_dcproperties) = &self.with_dcproperties {
+ write!(
+ f,
+ " WITH DCPROPERTIES({})",
+ display_comma_separated(with_dcproperties)
+ )?;
+ }
+
+ Ok(())
+ }
+}
diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index 17b5276a..35c6dcc1 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -47,14 +47,14 @@ pub use self::dcl::{
AlterRoleOperation, ResetConfig, RoleOption, SecondaryRoles,
SetConfigValue, Use,
};
pub use self::ddl::{
- AlterColumnOperation, AlterIndexOperation, AlterPolicyOperation,
AlterTableOperation,
- ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnPolicy,
ColumnPolicyProperty,
- ConstraintCharacteristics, CreateFunction, Deduplicate, DeferrableInitial,
DropBehavior,
- GeneratedAs, GeneratedExpressionMode, IdentityParameters, IdentityProperty,
- IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder,
IndexOption,
- IndexType, KeyOrIndexDisplay, NullsDistinctOption, Owner, Partition,
ProcedureParam,
- ReferentialAction, TableConstraint, TagsColumnOption,
UserDefinedTypeCompositeAttributeDef,
- UserDefinedTypeRepresentation, ViewColumnDef,
+ AlterColumnOperation, AlterConnectorOwner, AlterIndexOperation,
AlterPolicyOperation,
+ AlterTableOperation, ClusteredBy, ColumnDef, ColumnOption,
ColumnOptionDef, ColumnPolicy,
+ ColumnPolicyProperty, ConstraintCharacteristics, CreateConnector,
CreateFunction, Deduplicate,
+ DeferrableInitial, DropBehavior, GeneratedAs, GeneratedExpressionMode,
IdentityParameters,
+ IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind,
IdentityPropertyOrder,
+ IndexOption, IndexType, KeyOrIndexDisplay, NullsDistinctOption, Owner,
Partition,
+ ProcedureParam, ReferentialAction, TableConstraint, TagsColumnOption,
+ UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation,
ViewColumnDef,
};
pub use self::dml::{CreateIndex, CreateTable, Delete, Insert};
pub use self::operator::{BinaryOperator, UnaryOperator};
@@ -2646,6 +2646,11 @@ pub enum Statement {
with_check: Option<Expr>,
},
/// ```sql
+ /// CREATE CONNECTOR
+ /// ```
+ /// See
[Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
+ CreateConnector(CreateConnector),
+ /// ```sql
/// ALTER TABLE
/// ```
AlterTable {
@@ -2697,6 +2702,20 @@ pub enum Statement {
operation: AlterPolicyOperation,
},
/// ```sql
+ /// ALTER CONNECTOR connector_name SET
DCPROPERTIES(property_name=property_value, ...);
+ /// or
+ /// ALTER CONNECTOR connector_name SET URL new_url;
+ /// or
+ /// ALTER CONNECTOR connector_name SET OWNER [USER|ROLE] user_or_role;
+ /// ```
+ /// (Hive-specific)
+ AlterConnector {
+ name: Ident,
+ properties: Option<Vec<SqlOption>>,
+ url: Option<String>,
+ owner: Option<ddl::AlterConnectorOwner>,
+ },
+ /// ```sql
/// ATTACH DATABASE 'path/to/file' AS alias
/// ```
/// (SQLite-specific)
@@ -2795,6 +2814,11 @@ pub enum Statement {
drop_behavior: Option<DropBehavior>,
},
/// ```sql
+ /// DROP CONNECTOR
+ /// ```
+ /// See
[Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-DropConnector)
+ DropConnector { if_exists: bool, name: Ident },
+ /// ```sql
/// DECLARE
/// ```
/// Declare Cursor Variables
@@ -4354,6 +4378,7 @@ impl fmt::Display for Statement {
Ok(())
}
+ Statement::CreateConnector(create_connector) =>
create_connector.fmt(f),
Statement::AlterTable {
name,
if_exists,
@@ -4411,6 +4436,28 @@ impl fmt::Display for Statement {
} => {
write!(f, "ALTER POLICY {name} ON {table_name}{operation}")
}
+ Statement::AlterConnector {
+ name,
+ properties,
+ url,
+ owner,
+ } => {
+ write!(f, "ALTER CONNECTOR {name}")?;
+ if let Some(properties) = properties {
+ write!(
+ f,
+ " SET DCPROPERTIES({})",
+ display_comma_separated(properties)
+ )?;
+ }
+ if let Some(url) = url {
+ write!(f, " SET URL '{url}'")?;
+ }
+ if let Some(owner) = owner {
+ write!(f, " SET OWNER {owner}")?;
+ }
+ Ok(())
+ }
Statement::Drop {
object_type,
if_exists,
@@ -4498,6 +4545,14 @@ impl fmt::Display for Statement {
}
Ok(())
}
+ Statement::DropConnector { if_exists, name } => {
+ write!(
+ f,
+ "DROP CONNECTOR {if_exists}{name}",
+ if_exists = if *if_exists { "IF EXISTS " } else { "" }
+ )?;
+ Ok(())
+ }
Statement::Discard { object_type } => {
write!(f, "DISCARD {object_type}")?;
Ok(())
diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index f37c0194..b2690085 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -398,6 +398,7 @@ impl Spanned for Statement {
Statement::CreateIndex(create_index) => create_index.span(),
Statement::CreateRole { .. } => Span::empty(),
Statement::CreateSecret { .. } => Span::empty(),
+ Statement::CreateConnector { .. } => Span::empty(),
Statement::AlterTable {
name,
if_exists: _,
@@ -487,7 +488,9 @@ impl Spanned for Statement {
Statement::OptimizeTable { .. } => Span::empty(),
Statement::CreatePolicy { .. } => Span::empty(),
Statement::AlterPolicy { .. } => Span::empty(),
+ Statement::AlterConnector { .. } => Span::empty(),
Statement::DropPolicy { .. } => Span::empty(),
+ Statement::DropConnector { .. } => Span::empty(),
Statement::ShowDatabases { .. } => Span::empty(),
Statement::ShowSchemas { .. } => Span::empty(),
Statement::ShowViews { .. } => Span::empty(),
diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs
index b648869d..205395f6 100644
--- a/src/dialect/mod.rs
+++ b/src/dialect/mod.rs
@@ -876,6 +876,7 @@ pub trait Dialect: Debug + Any {
fn supports_string_escape_constant(&self) -> bool {
false
}
+
/// Returns true if the dialect supports the table hints in the `FROM`
clause.
fn supports_table_hints(&self) -> bool {
false
diff --git a/src/keywords.rs b/src/keywords.rs
index 5937d775..5f36fa73 100644
--- a/src/keywords.rs
+++ b/src/keywords.rs
@@ -201,6 +201,7 @@ define_keywords!(
CONFLICT,
CONNECT,
CONNECTION,
+ CONNECTOR,
CONSTRAINT,
CONTAINS,
CONTINUE,
@@ -246,6 +247,7 @@ define_keywords!(
DAYOFWEEK,
DAYOFYEAR,
DAYS,
+ DCPROPERTIES,
DEALLOCATE,
DEC,
DECADE,
diff --git a/src/parser/alter.rs b/src/parser/alter.rs
index bb6782c1..bff462ee 100644
--- a/src/parser/alter.rs
+++ b/src/parser/alter.rs
@@ -18,8 +18,8 @@ use alloc::vec;
use super::{Parser, ParserError};
use crate::{
ast::{
- AlterPolicyOperation, AlterRoleOperation, Expr, Password, ResetConfig,
RoleOption,
- SetConfigValue, Statement,
+ AlterConnectorOwner, AlterPolicyOperation, AlterRoleOperation, Expr,
Password, ResetConfig,
+ RoleOption, SetConfigValue, Statement,
},
dialect::{MsSqlDialect, PostgreSqlDialect},
keywords::Keyword,
@@ -99,6 +99,47 @@ impl Parser<'_> {
}
}
+ /// Parse an `ALTER CONNECTOR` statement
+ /// ```sql
+ /// ALTER CONNECTOR connector_name SET
DCPROPERTIES(property_name=property_value, ...);
+ ///
+ /// ALTER CONNECTOR connector_name SET URL new_url;
+ ///
+ /// ALTER CONNECTOR connector_name SET OWNER [USER|ROLE] user_or_role;
+ /// ```
+ pub fn parse_alter_connector(&mut self) -> Result<Statement, ParserError> {
+ let name = self.parse_identifier()?;
+ self.expect_keyword_is(Keyword::SET)?;
+
+ let properties = match
self.parse_options_with_keywords(&[Keyword::DCPROPERTIES])? {
+ properties if !properties.is_empty() => Some(properties),
+ _ => None,
+ };
+
+ let url = if self.parse_keyword(Keyword::URL) {
+ Some(self.parse_literal_string()?)
+ } else {
+ None
+ };
+
+ let owner = if self.parse_keywords(&[Keyword::OWNER, Keyword::USER]) {
+ let owner = self.parse_identifier()?;
+ Some(AlterConnectorOwner::User(owner))
+ } else if self.parse_keywords(&[Keyword::OWNER, Keyword::ROLE]) {
+ let owner = self.parse_identifier()?;
+ Some(AlterConnectorOwner::Role(owner))
+ } else {
+ None
+ };
+
+ Ok(Statement::AlterConnector {
+ name,
+ properties,
+ url,
+ owner,
+ })
+ }
+
fn parse_mssql_alter_role(&mut self) -> Result<Statement, ParserError> {
let role_name = self.parse_identifier()?;
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 28cba039..6d84ff84 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -4268,6 +4268,8 @@ impl<'a> Parser<'a> {
self.parse_create_type()
} else if self.parse_keyword(Keyword::PROCEDURE) {
self.parse_create_procedure(or_alter)
+ } else if self.parse_keyword(Keyword::CONNECTOR) {
+ self.parse_create_connector()
} else {
self.expected("an object type after CREATE", self.peek_token())
}
@@ -5580,6 +5582,49 @@ impl<'a> Parser<'a> {
})
}
+ /// ```sql
+ /// CREATE CONNECTOR [IF NOT EXISTS] connector_name
+ /// [TYPE datasource_type]
+ /// [URL datasource_url]
+ /// [COMMENT connector_comment]
+ /// [WITH DCPROPERTIES(property_name=property_value, ...)]
+ /// ```
+ ///
+ /// [Hive
Documentation](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
+ pub fn parse_create_connector(&mut self) -> Result<Statement, ParserError>
{
+ let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT,
Keyword::EXISTS]);
+ let name = self.parse_identifier()?;
+
+ let connector_type = if self.parse_keyword(Keyword::TYPE) {
+ Some(self.parse_literal_string()?)
+ } else {
+ None
+ };
+
+ let url = if self.parse_keyword(Keyword::URL) {
+ Some(self.parse_literal_string()?)
+ } else {
+ None
+ };
+
+ let comment = self.parse_optional_inline_comment()?;
+
+ let with_dcproperties =
+ match self.parse_options_with_keywords(&[Keyword::WITH,
Keyword::DCPROPERTIES])? {
+ properties if !properties.is_empty() => Some(properties),
+ _ => None,
+ };
+
+ Ok(Statement::CreateConnector(CreateConnector {
+ name,
+ if_not_exists,
+ connector_type,
+ url,
+ comment,
+ with_dcproperties,
+ }))
+ }
+
pub fn parse_drop(&mut self) -> Result<Statement, ParserError> {
// MySQL dialect supports `TEMPORARY`
let temporary = dialect_of!(self is MySqlDialect | GenericDialect |
DuckDbDialect)
@@ -5609,6 +5654,8 @@ impl<'a> Parser<'a> {
return self.parse_drop_function();
} else if self.parse_keyword(Keyword::POLICY) {
return self.parse_drop_policy();
+ } else if self.parse_keyword(Keyword::CONNECTOR) {
+ return self.parse_drop_connector();
} else if self.parse_keyword(Keyword::PROCEDURE) {
return self.parse_drop_procedure();
} else if self.parse_keyword(Keyword::SECRET) {
@@ -5619,7 +5666,7 @@ impl<'a> Parser<'a> {
return self.parse_drop_extension();
} else {
return self.expected(
- "DATABASE, EXTENSION, FUNCTION, INDEX, POLICY, PROCEDURE,
ROLE, SCHEMA, SECRET, SEQUENCE, STAGE, TABLE, TRIGGER, TYPE, or VIEW after
DROP",
+ "CONNECTOR, DATABASE, EXTENSION, FUNCTION, INDEX, POLICY,
PROCEDURE, ROLE, SCHEMA, SECRET, SEQUENCE, STAGE, TABLE, TRIGGER, TYPE, or VIEW
after DROP",
self.peek_token(),
);
};
@@ -5693,6 +5740,16 @@ impl<'a> Parser<'a> {
drop_behavior,
})
}
+ /// ```sql
+ /// DROP CONNECTOR [IF EXISTS] name
+ /// ```
+ ///
+ /// See
[Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-DropConnector)
+ fn parse_drop_connector(&mut self) -> Result<Statement, ParserError> {
+ let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
+ let name = self.parse_identifier()?;
+ Ok(Statement::DropConnector { if_exists, name })
+ }
/// ```sql
/// DROP PROCEDURE [ IF EXISTS ] name [ ( [ [ argmode ] [ argname ]
argtype [, ...] ] ) ] [, ...]
@@ -7989,6 +8046,7 @@ impl<'a> Parser<'a> {
Keyword::INDEX,
Keyword::ROLE,
Keyword::POLICY,
+ Keyword::CONNECTOR,
])?;
match object_type {
Keyword::VIEW => self.parse_alter_view(),
@@ -8041,6 +8099,7 @@ impl<'a> Parser<'a> {
}
Keyword::ROLE => self.parse_alter_role(),
Keyword::POLICY => self.parse_alter_policy(),
+ Keyword::CONNECTOR => self.parse_alter_connector(),
// unreachable because expect_one_of_keywords used above
_ => unreachable!(),
}
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 4fcb37b6..3a6183a1 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -12289,6 +12289,175 @@ fn test_alter_policy() {
);
}
+#[test]
+fn test_create_connector() {
+ let sql = "CREATE CONNECTOR my_connector \
+ TYPE 'jdbc' \
+ URL 'jdbc:mysql://localhost:3306/mydb' \
+ WITH DCPROPERTIES('user' = 'root', 'password' = 'password')";
+ let dialects = all_dialects();
+ match dialects.verified_stmt(sql) {
+ Statement::CreateConnector(CreateConnector {
+ name,
+ connector_type,
+ url,
+ with_dcproperties,
+ ..
+ }) => {
+ assert_eq!(name.to_string(), "my_connector");
+ assert_eq!(connector_type, Some("jdbc".to_string()));
+ assert_eq!(url,
Some("jdbc:mysql://localhost:3306/mydb".to_string()));
+ assert_eq!(
+ with_dcproperties,
+ Some(vec![
+ SqlOption::KeyValue {
+ key: Ident::with_quote('\'', "user"),
+ value:
Expr::Value(Value::SingleQuotedString("root".to_string()))
+ },
+ SqlOption::KeyValue {
+ key: Ident::with_quote('\'', "password"),
+ value:
Expr::Value(Value::SingleQuotedString("password".to_string()))
+ }
+ ])
+ );
+ }
+ _ => unreachable!(),
+ }
+
+ // omit IF NOT EXISTS/TYPE/URL/COMMENT/WITH DCPROPERTIES clauses is allowed
+ dialects.verified_stmt("CREATE CONNECTOR my_connector");
+
+ // missing connector name
+ assert_eq!(
+ dialects
+ .parse_sql_statements("CREATE CONNECTOR")
+ .unwrap_err()
+ .to_string(),
+ "sql parser error: Expected: identifier, found: EOF"
+ );
+}
+
+#[test]
+fn test_drop_connector() {
+ let dialects = all_dialects();
+ match dialects.verified_stmt("DROP CONNECTOR IF EXISTS my_connector") {
+ Statement::DropConnector { if_exists, name } => {
+ assert_eq!(if_exists, true);
+ assert_eq!(name.to_string(), "my_connector");
+ }
+ _ => unreachable!(),
+ }
+
+ // omit IF EXISTS is allowed
+ dialects.verified_stmt("DROP CONNECTOR my_connector");
+
+ // missing connector name
+ assert_eq!(
+ dialects
+ .parse_sql_statements("DROP CONNECTOR")
+ .unwrap_err()
+ .to_string(),
+ "sql parser error: Expected: identifier, found: EOF"
+ );
+}
+
+#[test]
+fn test_alter_connector() {
+ let dialects = all_dialects();
+ match dialects.verified_stmt(
+ "ALTER CONNECTOR my_connector SET DCPROPERTIES('user' = 'root',
'password' = 'password')",
+ ) {
+ Statement::AlterConnector {
+ name,
+ properties,
+ url,
+ owner,
+ } => {
+ assert_eq!(name.to_string(), "my_connector");
+ assert_eq!(
+ properties,
+ Some(vec![
+ SqlOption::KeyValue {
+ key: Ident::with_quote('\'', "user"),
+ value:
Expr::Value(Value::SingleQuotedString("root".to_string()))
+ },
+ SqlOption::KeyValue {
+ key: Ident::with_quote('\'', "password"),
+ value:
Expr::Value(Value::SingleQuotedString("password".to_string()))
+ }
+ ])
+ );
+ assert_eq!(url, None);
+ assert_eq!(owner, None);
+ }
+ _ => unreachable!(),
+ }
+
+ match dialects
+ .verified_stmt("ALTER CONNECTOR my_connector SET URL
'jdbc:mysql://localhost:3306/mydb'")
+ {
+ Statement::AlterConnector {
+ name,
+ properties,
+ url,
+ owner,
+ } => {
+ assert_eq!(name.to_string(), "my_connector");
+ assert_eq!(properties, None);
+ assert_eq!(url,
Some("jdbc:mysql://localhost:3306/mydb".to_string()));
+ assert_eq!(owner, None);
+ }
+ _ => unreachable!(),
+ }
+
+ match dialects.verified_stmt("ALTER CONNECTOR my_connector SET OWNER USER
'root'") {
+ Statement::AlterConnector {
+ name,
+ properties,
+ url,
+ owner,
+ } => {
+ assert_eq!(name.to_string(), "my_connector");
+ assert_eq!(properties, None);
+ assert_eq!(url, None);
+ assert_eq!(
+ owner,
+ Some(AlterConnectorOwner::User(Ident::with_quote('\'',
"root")))
+ );
+ }
+ _ => unreachable!(),
+ }
+
+ match dialects.verified_stmt("ALTER CONNECTOR my_connector SET OWNER ROLE
'admin'") {
+ Statement::AlterConnector {
+ name,
+ properties,
+ url,
+ owner,
+ } => {
+ assert_eq!(name.to_string(), "my_connector");
+ assert_eq!(properties, None);
+ assert_eq!(url, None);
+ assert_eq!(
+ owner,
+ Some(AlterConnectorOwner::Role(Ident::with_quote('\'',
"admin")))
+ );
+ }
+ _ => unreachable!(),
+ }
+
+ // Wrong option name
+ assert_eq!(
+ dialects
+ .parse_sql_statements(
+ "ALTER CONNECTOR my_connector SET WRONG
'jdbc:mysql://localhost:3306/mydb'"
+ )
+ .unwrap_err()
+ .to_string(),
+ "sql parser error: Expected: end of statement, found: WRONG"
+ );
+}
+
#[test]
fn test_select_where_with_like_or_ilike_any() {
verified_stmt(r#"SELECT * FROM x WHERE a ILIKE ANY '%abc%'"#);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]