Skip to content

Commit 486b29f

Browse files
authored
Add support for CREATE/ALTER/DROP CONNECTOR syntax (#1701)
1 parent ec948ea commit 486b29f

File tree

8 files changed

+420
-15
lines changed

8 files changed

+420
-15
lines changed

src/ast/ddl.rs

+79-4
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ use sqlparser_derive::{Visit, VisitMut};
3030

3131
use crate::ast::value::escape_single_quote_string;
3232
use crate::ast::{
33-
display_comma_separated, display_separated, CreateFunctionBody, CreateFunctionUsing, DataType,
34-
Expr, FunctionBehavior, FunctionCalledOnNull, FunctionDeterminismSpecifier, FunctionParallel,
35-
Ident, MySQLColumnPosition, ObjectName, OperateFunctionArg, OrderByExpr, ProjectionSelect,
36-
SequenceOptions, SqlOption, Tag, Value,
33+
display_comma_separated, display_separated, CommentDef, CreateFunctionBody,
34+
CreateFunctionUsing, DataType, Expr, FunctionBehavior, FunctionCalledOnNull,
35+
FunctionDeterminismSpecifier, FunctionParallel, Ident, MySQLColumnPosition, ObjectName,
36+
OperateFunctionArg, OrderByExpr, ProjectionSelect, SequenceOptions, SqlOption, Tag, Value,
3737
};
3838
use crate::keywords::Keyword;
3939
use crate::tokenizer::Token;
@@ -338,6 +338,23 @@ impl fmt::Display for Owner {
338338
}
339339
}
340340

341+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
342+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
343+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
344+
pub enum AlterConnectorOwner {
345+
User(Ident),
346+
Role(Ident),
347+
}
348+
349+
impl fmt::Display for AlterConnectorOwner {
350+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
351+
match self {
352+
AlterConnectorOwner::User(ident) => write!(f, "USER {ident}"),
353+
AlterConnectorOwner::Role(ident) => write!(f, "ROLE {ident}"),
354+
}
355+
}
356+
}
357+
341358
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
342359
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
343360
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
@@ -2055,3 +2072,61 @@ impl fmt::Display for CreateFunction {
20552072
Ok(())
20562073
}
20572074
}
2075+
2076+
/// ```sql
2077+
/// CREATE CONNECTOR [IF NOT EXISTS] connector_name
2078+
/// [TYPE datasource_type]
2079+
/// [URL datasource_url]
2080+
/// [COMMENT connector_comment]
2081+
/// [WITH DCPROPERTIES(property_name=property_value, ...)]
2082+
/// ```
2083+
///
2084+
/// [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
2085+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2086+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2087+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2088+
pub struct CreateConnector {
2089+
pub name: Ident,
2090+
pub if_not_exists: bool,
2091+
pub connector_type: Option<String>,
2092+
pub url: Option<String>,
2093+
pub comment: Option<CommentDef>,
2094+
pub with_dcproperties: Option<Vec<SqlOption>>,
2095+
}
2096+
2097+
impl fmt::Display for CreateConnector {
2098+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2099+
write!(
2100+
f,
2101+
"CREATE CONNECTOR {if_not_exists}{name}",
2102+
if_not_exists = if self.if_not_exists {
2103+
"IF NOT EXISTS "
2104+
} else {
2105+
""
2106+
},
2107+
name = self.name,
2108+
)?;
2109+
2110+
if let Some(connector_type) = &self.connector_type {
2111+
write!(f, " TYPE '{connector_type}'")?;
2112+
}
2113+
2114+
if let Some(url) = &self.url {
2115+
write!(f, " URL '{url}'")?;
2116+
}
2117+
2118+
if let Some(comment) = &self.comment {
2119+
write!(f, " COMMENT = '{comment}'")?;
2120+
}
2121+
2122+
if let Some(with_dcproperties) = &self.with_dcproperties {
2123+
write!(
2124+
f,
2125+
" WITH DCPROPERTIES({})",
2126+
display_comma_separated(with_dcproperties)
2127+
)?;
2128+
}
2129+
2130+
Ok(())
2131+
}
2132+
}

src/ast/mod.rs

+63-8
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,14 @@ pub use self::dcl::{
4747
AlterRoleOperation, ResetConfig, RoleOption, SecondaryRoles, SetConfigValue, Use,
4848
};
4949
pub use self::ddl::{
50-
AlterColumnOperation, AlterIndexOperation, AlterPolicyOperation, AlterTableOperation,
51-
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnPolicy, ColumnPolicyProperty,
52-
ConstraintCharacteristics, CreateFunction, Deduplicate, DeferrableInitial, DropBehavior,
53-
GeneratedAs, GeneratedExpressionMode, IdentityParameters, IdentityProperty,
54-
IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, IndexOption,
55-
IndexType, KeyOrIndexDisplay, NullsDistinctOption, Owner, Partition, ProcedureParam,
56-
ReferentialAction, TableConstraint, TagsColumnOption, UserDefinedTypeCompositeAttributeDef,
57-
UserDefinedTypeRepresentation, ViewColumnDef,
50+
AlterColumnOperation, AlterConnectorOwner, AlterIndexOperation, AlterPolicyOperation,
51+
AlterTableOperation, ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnPolicy,
52+
ColumnPolicyProperty, ConstraintCharacteristics, CreateConnector, CreateFunction, Deduplicate,
53+
DeferrableInitial, DropBehavior, GeneratedAs, GeneratedExpressionMode, IdentityParameters,
54+
IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder,
55+
IndexOption, IndexType, KeyOrIndexDisplay, NullsDistinctOption, Owner, Partition,
56+
ProcedureParam, ReferentialAction, TableConstraint, TagsColumnOption,
57+
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation, ViewColumnDef,
5858
};
5959
pub use self::dml::{CreateIndex, CreateTable, Delete, Insert};
6060
pub use self::operator::{BinaryOperator, UnaryOperator};
@@ -2646,6 +2646,11 @@ pub enum Statement {
26462646
with_check: Option<Expr>,
26472647
},
26482648
/// ```sql
2649+
/// CREATE CONNECTOR
2650+
/// ```
2651+
/// See [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
2652+
CreateConnector(CreateConnector),
2653+
/// ```sql
26492654
/// ALTER TABLE
26502655
/// ```
26512656
AlterTable {
@@ -2697,6 +2702,20 @@ pub enum Statement {
26972702
operation: AlterPolicyOperation,
26982703
},
26992704
/// ```sql
2705+
/// ALTER CONNECTOR connector_name SET DCPROPERTIES(property_name=property_value, ...);
2706+
/// or
2707+
/// ALTER CONNECTOR connector_name SET URL new_url;
2708+
/// or
2709+
/// ALTER CONNECTOR connector_name SET OWNER [USER|ROLE] user_or_role;
2710+
/// ```
2711+
/// (Hive-specific)
2712+
AlterConnector {
2713+
name: Ident,
2714+
properties: Option<Vec<SqlOption>>,
2715+
url: Option<String>,
2716+
owner: Option<ddl::AlterConnectorOwner>,
2717+
},
2718+
/// ```sql
27002719
/// ATTACH DATABASE 'path/to/file' AS alias
27012720
/// ```
27022721
/// (SQLite-specific)
@@ -2795,6 +2814,11 @@ pub enum Statement {
27952814
drop_behavior: Option<DropBehavior>,
27962815
},
27972816
/// ```sql
2817+
/// DROP CONNECTOR
2818+
/// ```
2819+
/// See [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-DropConnector)
2820+
DropConnector { if_exists: bool, name: Ident },
2821+
/// ```sql
27982822
/// DECLARE
27992823
/// ```
28002824
/// Declare Cursor Variables
@@ -4354,6 +4378,7 @@ impl fmt::Display for Statement {
43544378

43554379
Ok(())
43564380
}
4381+
Statement::CreateConnector(create_connector) => create_connector.fmt(f),
43574382
Statement::AlterTable {
43584383
name,
43594384
if_exists,
@@ -4411,6 +4436,28 @@ impl fmt::Display for Statement {
44114436
} => {
44124437
write!(f, "ALTER POLICY {name} ON {table_name}{operation}")
44134438
}
4439+
Statement::AlterConnector {
4440+
name,
4441+
properties,
4442+
url,
4443+
owner,
4444+
} => {
4445+
write!(f, "ALTER CONNECTOR {name}")?;
4446+
if let Some(properties) = properties {
4447+
write!(
4448+
f,
4449+
" SET DCPROPERTIES({})",
4450+
display_comma_separated(properties)
4451+
)?;
4452+
}
4453+
if let Some(url) = url {
4454+
write!(f, " SET URL '{url}'")?;
4455+
}
4456+
if let Some(owner) = owner {
4457+
write!(f, " SET OWNER {owner}")?;
4458+
}
4459+
Ok(())
4460+
}
44144461
Statement::Drop {
44154462
object_type,
44164463
if_exists,
@@ -4498,6 +4545,14 @@ impl fmt::Display for Statement {
44984545
}
44994546
Ok(())
45004547
}
4548+
Statement::DropConnector { if_exists, name } => {
4549+
write!(
4550+
f,
4551+
"DROP CONNECTOR {if_exists}{name}",
4552+
if_exists = if *if_exists { "IF EXISTS " } else { "" }
4553+
)?;
4554+
Ok(())
4555+
}
45014556
Statement::Discard { object_type } => {
45024557
write!(f, "DISCARD {object_type}")?;
45034558
Ok(())

src/ast/spans.rs

+3
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ impl Spanned for Statement {
398398
Statement::CreateIndex(create_index) => create_index.span(),
399399
Statement::CreateRole { .. } => Span::empty(),
400400
Statement::CreateSecret { .. } => Span::empty(),
401+
Statement::CreateConnector { .. } => Span::empty(),
401402
Statement::AlterTable {
402403
name,
403404
if_exists: _,
@@ -487,7 +488,9 @@ impl Spanned for Statement {
487488
Statement::OptimizeTable { .. } => Span::empty(),
488489
Statement::CreatePolicy { .. } => Span::empty(),
489490
Statement::AlterPolicy { .. } => Span::empty(),
491+
Statement::AlterConnector { .. } => Span::empty(),
490492
Statement::DropPolicy { .. } => Span::empty(),
493+
Statement::DropConnector { .. } => Span::empty(),
491494
Statement::ShowDatabases { .. } => Span::empty(),
492495
Statement::ShowSchemas { .. } => Span::empty(),
493496
Statement::ShowViews { .. } => Span::empty(),

src/dialect/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,7 @@ pub trait Dialect: Debug + Any {
876876
fn supports_string_escape_constant(&self) -> bool {
877877
false
878878
}
879+
879880
/// Returns true if the dialect supports the table hints in the `FROM` clause.
880881
fn supports_table_hints(&self) -> bool {
881882
false

src/keywords.rs

+2
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ define_keywords!(
201201
CONFLICT,
202202
CONNECT,
203203
CONNECTION,
204+
CONNECTOR,
204205
CONSTRAINT,
205206
CONTAINS,
206207
CONTINUE,
@@ -246,6 +247,7 @@ define_keywords!(
246247
DAYOFWEEK,
247248
DAYOFYEAR,
248249
DAYS,
250+
DCPROPERTIES,
249251
DEALLOCATE,
250252
DEC,
251253
DECADE,

src/parser/alter.rs

+43-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ use alloc::vec;
1818
use super::{Parser, ParserError};
1919
use crate::{
2020
ast::{
21-
AlterPolicyOperation, AlterRoleOperation, Expr, Password, ResetConfig, RoleOption,
22-
SetConfigValue, Statement,
21+
AlterConnectorOwner, AlterPolicyOperation, AlterRoleOperation, Expr, Password, ResetConfig,
22+
RoleOption, SetConfigValue, Statement,
2323
},
2424
dialect::{MsSqlDialect, PostgreSqlDialect},
2525
keywords::Keyword,
@@ -99,6 +99,47 @@ impl Parser<'_> {
9999
}
100100
}
101101

102+
/// Parse an `ALTER CONNECTOR` statement
103+
/// ```sql
104+
/// ALTER CONNECTOR connector_name SET DCPROPERTIES(property_name=property_value, ...);
105+
///
106+
/// ALTER CONNECTOR connector_name SET URL new_url;
107+
///
108+
/// ALTER CONNECTOR connector_name SET OWNER [USER|ROLE] user_or_role;
109+
/// ```
110+
pub fn parse_alter_connector(&mut self) -> Result<Statement, ParserError> {
111+
let name = self.parse_identifier()?;
112+
self.expect_keyword_is(Keyword::SET)?;
113+
114+
let properties = match self.parse_options_with_keywords(&[Keyword::DCPROPERTIES])? {
115+
properties if !properties.is_empty() => Some(properties),
116+
_ => None,
117+
};
118+
119+
let url = if self.parse_keyword(Keyword::URL) {
120+
Some(self.parse_literal_string()?)
121+
} else {
122+
None
123+
};
124+
125+
let owner = if self.parse_keywords(&[Keyword::OWNER, Keyword::USER]) {
126+
let owner = self.parse_identifier()?;
127+
Some(AlterConnectorOwner::User(owner))
128+
} else if self.parse_keywords(&[Keyword::OWNER, Keyword::ROLE]) {
129+
let owner = self.parse_identifier()?;
130+
Some(AlterConnectorOwner::Role(owner))
131+
} else {
132+
None
133+
};
134+
135+
Ok(Statement::AlterConnector {
136+
name,
137+
properties,
138+
url,
139+
owner,
140+
})
141+
}
142+
102143
fn parse_mssql_alter_role(&mut self) -> Result<Statement, ParserError> {
103144
let role_name = self.parse_identifier()?;
104145

0 commit comments

Comments
 (0)