Skip to content

Commit 64b3525

Browse files
wugeerayman-sigma
authored andcommitted
Add support for CREATE/ALTER/DROP CONNECTOR syntax (apache#1701)
1 parent bc94b9a commit 64b3525

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};
@@ -2664,6 +2664,11 @@ pub enum Statement {
26642664
with_check: Option<Expr>,
26652665
},
26662666
/// ```sql
2667+
/// CREATE CONNECTOR
2668+
/// ```
2669+
/// See [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
2670+
CreateConnector(CreateConnector),
2671+
/// ```sql
26672672
/// ALTER TABLE
26682673
/// ```
26692674
AlterTable {
@@ -2715,6 +2720,20 @@ pub enum Statement {
27152720
operation: AlterPolicyOperation,
27162721
},
27172722
/// ```sql
2723+
/// ALTER CONNECTOR connector_name SET DCPROPERTIES(property_name=property_value, ...);
2724+
/// or
2725+
/// ALTER CONNECTOR connector_name SET URL new_url;
2726+
/// or
2727+
/// ALTER CONNECTOR connector_name SET OWNER [USER|ROLE] user_or_role;
2728+
/// ```
2729+
/// (Hive-specific)
2730+
AlterConnector {
2731+
name: Ident,
2732+
properties: Option<Vec<SqlOption>>,
2733+
url: Option<String>,
2734+
owner: Option<ddl::AlterConnectorOwner>,
2735+
},
2736+
/// ```sql
27182737
/// ATTACH DATABASE 'path/to/file' AS alias
27192738
/// ```
27202739
/// (SQLite-specific)
@@ -2813,6 +2832,11 @@ pub enum Statement {
28132832
drop_behavior: Option<DropBehavior>,
28142833
},
28152834
/// ```sql
2835+
/// DROP CONNECTOR
2836+
/// ```
2837+
/// See [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-DropConnector)
2838+
DropConnector { if_exists: bool, name: Ident },
2839+
/// ```sql
28162840
/// DECLARE
28172841
/// ```
28182842
/// Declare Cursor Variables
@@ -4372,6 +4396,7 @@ impl fmt::Display for Statement {
43724396

43734397
Ok(())
43744398
}
4399+
Statement::CreateConnector(create_connector) => create_connector.fmt(f),
43754400
Statement::AlterTable {
43764401
name,
43774402
if_exists,
@@ -4429,6 +4454,28 @@ impl fmt::Display for Statement {
44294454
} => {
44304455
write!(f, "ALTER POLICY {name} ON {table_name}{operation}")
44314456
}
4457+
Statement::AlterConnector {
4458+
name,
4459+
properties,
4460+
url,
4461+
owner,
4462+
} => {
4463+
write!(f, "ALTER CONNECTOR {name}")?;
4464+
if let Some(properties) = properties {
4465+
write!(
4466+
f,
4467+
" SET DCPROPERTIES({})",
4468+
display_comma_separated(properties)
4469+
)?;
4470+
}
4471+
if let Some(url) = url {
4472+
write!(f, " SET URL '{url}'")?;
4473+
}
4474+
if let Some(owner) = owner {
4475+
write!(f, " SET OWNER {owner}")?;
4476+
}
4477+
Ok(())
4478+
}
44324479
Statement::Drop {
44334480
object_type,
44344481
if_exists,
@@ -4516,6 +4563,14 @@ impl fmt::Display for Statement {
45164563
}
45174564
Ok(())
45184565
}
4566+
Statement::DropConnector { if_exists, name } => {
4567+
write!(
4568+
f,
4569+
"DROP CONNECTOR {if_exists}{name}",
4570+
if_exists = if *if_exists { "IF EXISTS " } else { "" }
4571+
)?;
4572+
Ok(())
4573+
}
45194574
Statement::Discard { object_type } => {
45204575
write!(f, "DISCARD {object_type}")?;
45214576
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)