Skip to content

Commit b67b0dd

Browse files
committed
Snowflake: CREATE USER
1 parent 6506814 commit b67b0dd

File tree

6 files changed

+220
-85
lines changed

6 files changed

+220
-85
lines changed

src/ast/helpers/key_value_options.rs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,22 @@ use serde::{Deserialize, Serialize};
3131
#[cfg(feature = "visitor")]
3232
use sqlparser_derive::{Visit, VisitMut};
3333

34+
use crate::ast::display_separated;
35+
3436
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3537
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3638
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3739
pub struct KeyValueOptions {
3840
pub options: Vec<KeyValueOption>,
41+
pub delimiter: KeyValueOptionsDelimiter,
42+
}
43+
44+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
45+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
46+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
47+
pub enum KeyValueOptionsDelimiter {
48+
Space,
49+
Comma,
3950
}
4051

4152
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -59,18 +70,11 @@ pub struct KeyValueOption {
5970

6071
impl fmt::Display for KeyValueOptions {
6172
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
62-
if !self.options.is_empty() {
63-
let mut first = false;
64-
for option in &self.options {
65-
if !first {
66-
first = true;
67-
} else {
68-
f.write_str(" ")?;
69-
}
70-
write!(f, "{option}")?;
71-
}
72-
}
73-
Ok(())
73+
let sep = match self.delimiter {
74+
KeyValueOptionsDelimiter::Space => " ",
75+
KeyValueOptionsDelimiter::Comma => ", ",
76+
};
77+
write!(f, "{}", display_separated(&self.options, sep))
7478
}
7579
}
7680

src/ast/mod.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4339,6 +4339,11 @@ pub enum Statement {
43394339
///
43404340
/// See [ReturnStatement]
43414341
Return(ReturnStatement),
4342+
/// ```sql
4343+
/// CREATE [OR REPLACE] USER <user> [IF NOT EXISTS]
4344+
/// ```
4345+
/// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/create-user)
4346+
CreateUser(CreateUser),
43424347
}
43434348

43444349
/// ```sql
@@ -6169,6 +6174,7 @@ impl fmt::Display for Statement {
61696174
Statement::Return(r) => write!(f, "{r}"),
61706175
Statement::List(command) => write!(f, "LIST {command}"),
61716176
Statement::Remove(command) => write!(f, "REMOVE {command}"),
6177+
Statement::CreateUser(s) => write!(f, "{s}"),
61726178
}
61736179
}
61746180
}
@@ -10074,6 +10080,42 @@ impl fmt::Display for MemberOf {
1007410080
}
1007510081
}
1007610082

10083+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
10084+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10085+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
10086+
pub struct CreateUser {
10087+
pub or_replace: bool,
10088+
pub if_not_exists: bool,
10089+
pub name: Ident,
10090+
pub options: KeyValueOptions,
10091+
pub with_tags: bool,
10092+
pub tags: KeyValueOptions,
10093+
}
10094+
10095+
impl fmt::Display for CreateUser {
10096+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
10097+
write!(f, "CREATE")?;
10098+
if self.or_replace {
10099+
write!(f, " OR REPLACE")?;
10100+
}
10101+
write!(f, " USER")?;
10102+
if self.if_not_exists {
10103+
write!(f, " IF NOT EXISTS")?;
10104+
}
10105+
write!(f, " {}", self.name)?;
10106+
if !self.options.options.is_empty() {
10107+
write!(f, " {}", self.options)?;
10108+
}
10109+
if !self.tags.options.is_empty() {
10110+
if self.with_tags {
10111+
write!(f, " WITH")?;
10112+
}
10113+
write!(f, " TAG ({})", self.tags)?;
10114+
}
10115+
Ok(())
10116+
}
10117+
}
10118+
1007710119
#[cfg(test)]
1007810120
mod tests {
1007910121
use crate::tokenizer::Location;

src/ast/spans.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ impl Spanned for Statement {
531531
Statement::Print { .. } => Span::empty(),
532532
Statement::Return { .. } => Span::empty(),
533533
Statement::List(..) | Statement::Remove(..) => Span::empty(),
534+
Statement::CreateUser(..) => Span::empty(),
534535
}
535536
}
536537
}

src/dialect/snowflake.rs

Lines changed: 37 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
#[cfg(not(feature = "std"))]
1919
use crate::alloc::string::ToString;
20-
use crate::ast::helpers::key_value_options::{KeyValueOption, KeyValueOptionType, KeyValueOptions};
20+
use crate::ast::helpers::key_value_options::{
21+
KeyValueOption, KeyValueOptionType, KeyValueOptions, KeyValueOptionsDelimiter,
22+
};
2123
use crate::ast::helpers::stmt_create_table::CreateTableBuilder;
2224
use crate::ast::helpers::stmt_data_loading::{
2325
FileStagingCommand, StageLoadSelectItem, StageLoadSelectItemKind, StageParamsObject,
@@ -31,7 +33,7 @@ use crate::ast::{
3133
use crate::dialect::{Dialect, Precedence};
3234
use crate::keywords::Keyword;
3335
use crate::parser::{IsOptional, Parser, ParserError};
34-
use crate::tokenizer::{Token, Word};
36+
use crate::tokenizer::Token;
3537
#[cfg(not(feature = "std"))]
3638
use alloc::boxed::Box;
3739
#[cfg(not(feature = "std"))]
@@ -500,6 +502,7 @@ fn parse_alter_session(parser: &mut Parser, set: bool) -> Result<Statement, Pars
500502
set,
501503
session_params: KeyValueOptions {
502504
options: session_options,
505+
delimiter: KeyValueOptionsDelimiter::Space,
503506
},
504507
})
505508
}
@@ -761,19 +764,19 @@ pub fn parse_create_stage(
761764
// [ directoryTableParams ]
762765
if parser.parse_keyword(Keyword::DIRECTORY) {
763766
parser.expect_token(&Token::Eq)?;
764-
directory_table_params = parse_parentheses_options(parser)?;
767+
directory_table_params = parser.parse_key_value_options(true, &[])?;
765768
}
766769

767770
// [ file_format]
768771
if parser.parse_keyword(Keyword::FILE_FORMAT) {
769772
parser.expect_token(&Token::Eq)?;
770-
file_format = parse_parentheses_options(parser)?;
773+
file_format = parser.parse_key_value_options(true, &[])?;
771774
}
772775

773776
// [ copy_options ]
774777
if parser.parse_keyword(Keyword::COPY_OPTIONS) {
775778
parser.expect_token(&Token::Eq)?;
776-
copy_options = parse_parentheses_options(parser)?;
779+
copy_options = parser.parse_key_value_options(true, &[])?;
777780
}
778781

779782
// [ comment ]
@@ -790,12 +793,15 @@ pub fn parse_create_stage(
790793
stage_params,
791794
directory_table_params: KeyValueOptions {
792795
options: directory_table_params,
796+
delimiter: KeyValueOptionsDelimiter::Space,
793797
},
794798
file_format: KeyValueOptions {
795799
options: file_format,
800+
delimiter: KeyValueOptionsDelimiter::Space,
796801
},
797802
copy_options: KeyValueOptions {
798803
options: copy_options,
804+
delimiter: KeyValueOptionsDelimiter::Space,
799805
},
800806
comment,
801807
})
@@ -863,10 +869,16 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
863869
let mut from_stage = None;
864870
let mut stage_params = StageParamsObject {
865871
url: None,
866-
encryption: KeyValueOptions { options: vec![] },
872+
encryption: KeyValueOptions {
873+
options: vec![],
874+
delimiter: KeyValueOptionsDelimiter::Space,
875+
},
867876
endpoint: None,
868877
storage_integration: None,
869-
credentials: KeyValueOptions { options: vec![] },
878+
credentials: KeyValueOptions {
879+
options: vec![],
880+
delimiter: KeyValueOptionsDelimiter::Space,
881+
},
870882
};
871883
let mut from_query = None;
872884
let mut partition = None;
@@ -928,7 +940,7 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
928940
// FILE_FORMAT
929941
if parser.parse_keyword(Keyword::FILE_FORMAT) {
930942
parser.expect_token(&Token::Eq)?;
931-
file_format = parse_parentheses_options(parser)?;
943+
file_format = parser.parse_key_value_options(true, &[])?;
932944
// PARTITION BY
933945
} else if parser.parse_keywords(&[Keyword::PARTITION, Keyword::BY]) {
934946
partition = Some(Box::new(parser.parse_expr()?))
@@ -966,14 +978,14 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
966978
// COPY OPTIONS
967979
} else if parser.parse_keyword(Keyword::COPY_OPTIONS) {
968980
parser.expect_token(&Token::Eq)?;
969-
copy_options = parse_parentheses_options(parser)?;
981+
copy_options = parser.parse_key_value_options(true, &[])?;
970982
} else {
971983
match parser.next_token().token {
972984
Token::SemiColon | Token::EOF => break,
973985
Token::Comma => continue,
974986
// In `COPY INTO <location>` the copy options do not have a shared key
975987
// like in `COPY INTO <table>`
976-
Token::Word(key) => copy_options.push(parse_option(parser, key)?),
988+
Token::Word(key) => copy_options.push(parser.parse_key_value_option(key)?),
977989
_ => return parser.expected("another copy option, ; or EOF'", parser.peek_token()),
978990
}
979991
}
@@ -992,9 +1004,11 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
9921004
pattern,
9931005
file_format: KeyValueOptions {
9941006
options: file_format,
1007+
delimiter: KeyValueOptionsDelimiter::Space,
9951008
},
9961009
copy_options: KeyValueOptions {
9971010
options: copy_options,
1011+
delimiter: KeyValueOptionsDelimiter::Space,
9981012
},
9991013
validation_mode,
10001014
partition,
@@ -1094,8 +1108,14 @@ fn parse_select_item_for_data_load(
10941108

10951109
fn parse_stage_params(parser: &mut Parser) -> Result<StageParamsObject, ParserError> {
10961110
let (mut url, mut storage_integration, mut endpoint) = (None, None, None);
1097-
let mut encryption: KeyValueOptions = KeyValueOptions { options: vec![] };
1098-
let mut credentials: KeyValueOptions = KeyValueOptions { options: vec![] };
1111+
let mut encryption: KeyValueOptions = KeyValueOptions {
1112+
options: vec![],
1113+
delimiter: KeyValueOptionsDelimiter::Space,
1114+
};
1115+
let mut credentials: KeyValueOptions = KeyValueOptions {
1116+
options: vec![],
1117+
delimiter: KeyValueOptionsDelimiter::Space,
1118+
};
10991119

11001120
// URL
11011121
if parser.parse_keyword(Keyword::URL) {
@@ -1125,15 +1145,17 @@ fn parse_stage_params(parser: &mut Parser) -> Result<StageParamsObject, ParserEr
11251145
if parser.parse_keyword(Keyword::CREDENTIALS) {
11261146
parser.expect_token(&Token::Eq)?;
11271147
credentials = KeyValueOptions {
1128-
options: parse_parentheses_options(parser)?,
1148+
options: parser.parse_key_value_options(true, &[])?,
1149+
delimiter: KeyValueOptionsDelimiter::Space,
11291150
};
11301151
}
11311152

11321153
// ENCRYPTION
11331154
if parser.parse_keyword(Keyword::ENCRYPTION) {
11341155
parser.expect_token(&Token::Eq)?;
11351156
encryption = KeyValueOptions {
1136-
options: parse_parentheses_options(parser)?,
1157+
options: parser.parse_key_value_options(true, &[])?,
1158+
delimiter: KeyValueOptionsDelimiter::Space,
11371159
};
11381160
}
11391161

@@ -1167,7 +1189,7 @@ fn parse_session_options(
11671189
Token::Word(key) => {
11681190
parser.advance_token();
11691191
if set {
1170-
let option = parse_option(parser, key)?;
1192+
let option = parser.parse_key_value_option(key)?;
11711193
options.push(option);
11721194
} else {
11731195
options.push(KeyValueOption {
@@ -1191,63 +1213,6 @@ fn parse_session_options(
11911213
}
11921214
}
11931215

1194-
/// Parses options provided within parentheses like:
1195-
/// ( ENABLE = { TRUE | FALSE }
1196-
/// [ AUTO_REFRESH = { TRUE | FALSE } ]
1197-
/// [ REFRESH_ON_CREATE = { TRUE | FALSE } ]
1198-
/// [ NOTIFICATION_INTEGRATION = '<notification_integration_name>' ] )
1199-
///
1200-
fn parse_parentheses_options(parser: &mut Parser) -> Result<Vec<KeyValueOption>, ParserError> {
1201-
let mut options: Vec<KeyValueOption> = Vec::new();
1202-
parser.expect_token(&Token::LParen)?;
1203-
loop {
1204-
match parser.next_token().token {
1205-
Token::RParen => break,
1206-
Token::Comma => continue,
1207-
Token::Word(key) => options.push(parse_option(parser, key)?),
1208-
_ => return parser.expected("another option or ')'", parser.peek_token()),
1209-
};
1210-
}
1211-
Ok(options)
1212-
}
1213-
1214-
/// Parses a `KEY = VALUE` construct based on the specified key
1215-
fn parse_option(parser: &mut Parser, key: Word) -> Result<KeyValueOption, ParserError> {
1216-
parser.expect_token(&Token::Eq)?;
1217-
if parser.parse_keyword(Keyword::TRUE) {
1218-
Ok(KeyValueOption {
1219-
option_name: key.value,
1220-
option_type: KeyValueOptionType::BOOLEAN,
1221-
value: "TRUE".to_string(),
1222-
})
1223-
} else if parser.parse_keyword(Keyword::FALSE) {
1224-
Ok(KeyValueOption {
1225-
option_name: key.value,
1226-
option_type: KeyValueOptionType::BOOLEAN,
1227-
value: "FALSE".to_string(),
1228-
})
1229-
} else {
1230-
match parser.next_token().token {
1231-
Token::SingleQuotedString(value) => Ok(KeyValueOption {
1232-
option_name: key.value,
1233-
option_type: KeyValueOptionType::STRING,
1234-
value,
1235-
}),
1236-
Token::Word(word) => Ok(KeyValueOption {
1237-
option_name: key.value,
1238-
option_type: KeyValueOptionType::ENUM,
1239-
value: word.value,
1240-
}),
1241-
Token::Number(n, _) => Ok(KeyValueOption {
1242-
option_name: key.value,
1243-
option_type: KeyValueOptionType::NUMBER,
1244-
value: n,
1245-
}),
1246-
_ => parser.expected("expected option value", parser.peek_token()),
1247-
}
1248-
}
1249-
}
1250-
12511216
/// Parsing a property of identity or autoincrement column option
12521217
/// Syntax:
12531218
/// ```sql

0 commit comments

Comments
 (0)