Skip to content

Commit

Permalink
Add support for CREATE/ALTER/DROP CONNECTOR syntax (#1701)
Browse files Browse the repository at this point in the history
  • Loading branch information
wugeer authored Feb 4, 2025
1 parent ec948ea commit 486b29f
Show file tree
Hide file tree
Showing 8 changed files with 420 additions and 15 deletions.
83 changes: 79 additions & 4 deletions src/ast/ddl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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))]
Expand Down Expand Up @@ -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(())
}
}
71 changes: 63 additions & 8 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -4354,6 +4378,7 @@ impl fmt::Display for Statement {

Ok(())
}
Statement::CreateConnector(create_connector) => create_connector.fmt(f),
Statement::AlterTable {
name,
if_exists,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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(())
Expand Down
3 changes: 3 additions & 0 deletions src/ast/spans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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: _,
Expand Down Expand Up @@ -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(),
Expand Down
1 change: 1 addition & 0 deletions src/dialect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/keywords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ define_keywords!(
CONFLICT,
CONNECT,
CONNECTION,
CONNECTOR,
CONSTRAINT,
CONTAINS,
CONTINUE,
Expand Down Expand Up @@ -246,6 +247,7 @@ define_keywords!(
DAYOFWEEK,
DAYOFYEAR,
DAYS,
DCPROPERTIES,
DEALLOCATE,
DEC,
DECADE,
Expand Down
45 changes: 43 additions & 2 deletions src/parser/alter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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()?;

Expand Down
Loading

0 comments on commit 486b29f

Please sign in to comment.