1#[cfg(not(feature = "std"))]
19use crate::alloc::string::ToString;
20use crate::ast::helpers::attached_token::AttachedToken;
21use crate::ast::helpers::key_value_options::{
22 KeyValueOption, KeyValueOptionKind, KeyValueOptions, KeyValueOptionsDelimiter,
23};
24use crate::ast::helpers::stmt_create_database::CreateDatabaseBuilder;
25use crate::ast::helpers::stmt_create_table::CreateTableBuilder;
26use crate::ast::helpers::stmt_data_loading::{
27 FileStagingCommand, StageLoadSelectItem, StageLoadSelectItemKind, StageParamsObject,
28};
29use crate::ast::{
30 AlterTable, AlterTableOperation, AlterTableType, CatalogSyncNamespaceMode, ColumnOption,
31 ColumnPolicy, ColumnPolicyProperty, ContactEntry, CopyIntoSnowflakeKind, CreateTableLikeKind,
32 DollarQuotedString, Ident, IdentityParameters, IdentityProperty, IdentityPropertyFormatKind,
33 IdentityPropertyKind, IdentityPropertyOrder, InitializeKind, ObjectName, ObjectNamePart,
34 RefreshModeKind, RowAccessPolicy, ShowObjects, SqlOption, Statement,
35 StorageSerializationPolicy, TagsColumnOption, Value, WrappedCollection,
36};
37use crate::dialect::{Dialect, Precedence};
38use crate::keywords::Keyword;
39use crate::parser::{IsOptional, Parser, ParserError};
40use crate::tokenizer::Token;
41#[cfg(not(feature = "std"))]
42use alloc::boxed::Box;
43#[cfg(not(feature = "std"))]
44use alloc::string::String;
45#[cfg(not(feature = "std"))]
46use alloc::vec::Vec;
47#[cfg(not(feature = "std"))]
48use alloc::{format, vec};
49
50use super::keywords::RESERVED_FOR_IDENTIFIER;
51
52const RESERVED_KEYWORDS_FOR_SELECT_ITEM_OPERATOR: [Keyword; 1] = [Keyword::CONNECT_BY_ROOT];
53
54const RESERVED_KEYWORDS_FOR_TABLE_FACTOR: &[Keyword] = &[
56 Keyword::ALL,
57 Keyword::ALTER,
58 Keyword::AND,
59 Keyword::ANY,
60 Keyword::AS,
61 Keyword::BETWEEN,
62 Keyword::BY,
63 Keyword::CHECK,
64 Keyword::COLUMN,
65 Keyword::CONNECT,
66 Keyword::CREATE,
67 Keyword::CROSS,
68 Keyword::CURRENT,
69 Keyword::DELETE,
70 Keyword::DISTINCT,
71 Keyword::DROP,
72 Keyword::ELSE,
73 Keyword::EXISTS,
74 Keyword::FOLLOWING,
75 Keyword::FOR,
76 Keyword::FROM,
77 Keyword::FULL,
78 Keyword::GRANT,
79 Keyword::GROUP,
80 Keyword::HAVING,
81 Keyword::ILIKE,
82 Keyword::IN,
83 Keyword::INCREMENT,
84 Keyword::INNER,
85 Keyword::INSERT,
86 Keyword::INTERSECT,
87 Keyword::INTO,
88 Keyword::IS,
89 Keyword::JOIN,
90 Keyword::LEFT,
91 Keyword::LIKE,
92 Keyword::MINUS,
93 Keyword::NATURAL,
94 Keyword::NOT,
95 Keyword::NULL,
96 Keyword::OF,
97 Keyword::ON,
98 Keyword::OR,
99 Keyword::ORDER,
100 Keyword::QUALIFY,
101 Keyword::REGEXP,
102 Keyword::REVOKE,
103 Keyword::RIGHT,
104 Keyword::RLIKE,
105 Keyword::ROW,
106 Keyword::ROWS,
107 Keyword::SAMPLE,
108 Keyword::SELECT,
109 Keyword::SET,
110 Keyword::SOME,
111 Keyword::START,
112 Keyword::TABLE,
113 Keyword::TABLESAMPLE,
114 Keyword::THEN,
115 Keyword::TO,
116 Keyword::TRIGGER,
117 Keyword::UNION,
118 Keyword::UNIQUE,
119 Keyword::UPDATE,
120 Keyword::USING,
121 Keyword::VALUES,
122 Keyword::WHEN,
123 Keyword::WHENEVER,
124 Keyword::WHERE,
125 Keyword::WINDOW,
126 Keyword::WITH,
127];
128
129#[derive(Debug, Default)]
131pub struct SnowflakeDialect;
132
133impl Dialect for SnowflakeDialect {
134 fn is_identifier_start(&self, ch: char) -> bool {
136 ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch == '_'
137 }
138
139 fn supports_projection_trailing_commas(&self) -> bool {
140 true
141 }
142
143 fn supports_from_trailing_commas(&self) -> bool {
144 true
145 }
146
147 fn supports_object_name_double_dot_notation(&self) -> bool {
152 true
153 }
154
155 fn is_identifier_part(&self, ch: char) -> bool {
156 ch.is_ascii_lowercase()
157 || ch.is_ascii_uppercase()
158 || ch.is_ascii_digit()
159 || ch == '$'
160 || ch == '_'
161 }
162
163 fn supports_string_literal_backslash_escape(&self) -> bool {
165 true
166 }
167
168 fn supports_within_after_array_aggregation(&self) -> bool {
169 true
170 }
171
172 fn supports_outer_join_operator(&self) -> bool {
174 true
175 }
176
177 fn supports_connect_by(&self) -> bool {
178 true
179 }
180
181 fn supports_execute_immediate(&self) -> bool {
183 true
184 }
185
186 fn supports_match_recognize(&self) -> bool {
187 true
188 }
189
190 fn supports_dictionary_syntax(&self) -> bool {
195 true
196 }
197
198 fn supports_window_function_null_treatment_arg(&self) -> bool {
201 true
202 }
203
204 fn supports_parenthesized_set_variables(&self) -> bool {
206 true
207 }
208
209 fn supports_comment_on(&self) -> bool {
211 true
212 }
213
214 fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
215 if parser.parse_keyword(Keyword::BEGIN) {
216 return Some(parser.parse_begin_exception_end());
217 }
218
219 if parser.parse_keywords(&[Keyword::ALTER, Keyword::DYNAMIC, Keyword::TABLE]) {
220 return Some(parse_alter_dynamic_table(parser));
222 }
223
224 if parser.parse_keywords(&[Keyword::ALTER, Keyword::SESSION]) {
225 let set = match parser.parse_one_of_keywords(&[Keyword::SET, Keyword::UNSET]) {
227 Some(Keyword::SET) => true,
228 Some(Keyword::UNSET) => false,
229 _ => return Some(parser.expected("SET or UNSET", parser.peek_token())),
230 };
231 return Some(parse_alter_session(parser, set));
232 }
233
234 if parser.parse_keyword(Keyword::CREATE) {
235 let or_replace = parser.parse_keywords(&[Keyword::OR, Keyword::REPLACE]);
238 let global = match parser.parse_one_of_keywords(&[Keyword::LOCAL, Keyword::GLOBAL]) {
240 Some(Keyword::LOCAL) => Some(false),
241 Some(Keyword::GLOBAL) => Some(true),
242 _ => None,
243 };
244
245 let dynamic = parser.parse_keyword(Keyword::DYNAMIC);
246
247 let mut temporary = false;
248 let mut volatile = false;
249 let mut transient = false;
250 let mut iceberg = false;
251
252 match parser.parse_one_of_keywords(&[
253 Keyword::TEMP,
254 Keyword::TEMPORARY,
255 Keyword::VOLATILE,
256 Keyword::TRANSIENT,
257 Keyword::ICEBERG,
258 ]) {
259 Some(Keyword::TEMP | Keyword::TEMPORARY) => temporary = true,
260 Some(Keyword::VOLATILE) => volatile = true,
261 Some(Keyword::TRANSIENT) => transient = true,
262 Some(Keyword::ICEBERG) => iceberg = true,
263 _ => {}
264 }
265
266 if parser.parse_keyword(Keyword::STAGE) {
267 return Some(parse_create_stage(or_replace, temporary, parser));
269 } else if parser.parse_keyword(Keyword::TABLE) {
270 return Some(parse_create_table(
271 or_replace, global, temporary, volatile, transient, iceberg, dynamic, parser,
272 ));
273 } else if parser.parse_keyword(Keyword::DATABASE) {
274 return Some(parse_create_database(or_replace, transient, parser));
275 } else {
276 let mut back = 1;
278 if or_replace {
279 back += 2
280 }
281 if temporary {
282 back += 1
283 }
284 for _i in 0..back {
285 parser.prev_token();
286 }
287 }
288 }
289 if parser.parse_keywords(&[Keyword::COPY, Keyword::INTO]) {
290 return Some(parse_copy_into(parser));
292 }
293
294 if let Some(kw) = parser.parse_one_of_keywords(&[
295 Keyword::LIST,
296 Keyword::LS,
297 Keyword::REMOVE,
298 Keyword::RM,
299 ]) {
300 return Some(parse_file_staging_command(kw, parser));
301 }
302
303 if parser.parse_keyword(Keyword::SHOW) {
304 let terse = parser.parse_keyword(Keyword::TERSE);
305 if parser.parse_keyword(Keyword::OBJECTS) {
306 return Some(parse_show_objects(terse, parser));
307 }
308 if terse {
310 parser.prev_token();
311 }
312 parser.prev_token();
314 }
315
316 None
317 }
318
319 fn parse_column_option(
320 &self,
321 parser: &mut Parser,
322 ) -> Result<Option<Result<Option<ColumnOption>, ParserError>>, ParserError> {
323 parser.maybe_parse(|parser| {
324 let with = parser.parse_keyword(Keyword::WITH);
325
326 if parser.parse_keyword(Keyword::IDENTITY) {
327 Ok(parse_identity_property(parser)
328 .map(|p| Some(ColumnOption::Identity(IdentityPropertyKind::Identity(p)))))
329 } else if parser.parse_keyword(Keyword::AUTOINCREMENT) {
330 Ok(parse_identity_property(parser).map(|p| {
331 Some(ColumnOption::Identity(IdentityPropertyKind::Autoincrement(
332 p,
333 )))
334 }))
335 } else if parser.parse_keywords(&[Keyword::MASKING, Keyword::POLICY]) {
336 Ok(parse_column_policy_property(parser, with)
337 .map(|p| Some(ColumnOption::Policy(ColumnPolicy::MaskingPolicy(p)))))
338 } else if parser.parse_keywords(&[Keyword::PROJECTION, Keyword::POLICY]) {
339 Ok(parse_column_policy_property(parser, with)
340 .map(|p| Some(ColumnOption::Policy(ColumnPolicy::ProjectionPolicy(p)))))
341 } else if parser.parse_keywords(&[Keyword::TAG]) {
342 Ok(parse_column_tags(parser, with).map(|p| Some(ColumnOption::Tags(p))))
343 } else {
344 Err(ParserError::ParserError("not found match".to_string()))
345 }
346 })
347 }
348
349 fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
350 let token = parser.peek_token();
351 match token.token {
353 Token::Colon => Some(Ok(self.prec_value(Precedence::DoubleColon))),
354 _ => None,
355 }
356 }
357
358 fn describe_requires_table_keyword(&self) -> bool {
359 true
360 }
361
362 fn allow_extract_custom(&self) -> bool {
363 true
364 }
365
366 fn allow_extract_single_quotes(&self) -> bool {
367 true
368 }
369
370 fn supports_show_like_before_in(&self) -> bool {
373 true
374 }
375
376 fn supports_left_associative_joins_without_parens(&self) -> bool {
377 false
378 }
379
380 fn is_reserved_for_identifier(&self, kw: Keyword) -> bool {
381 if matches!(kw, Keyword::INTERVAL) {
384 false
385 } else {
386 RESERVED_FOR_IDENTIFIER.contains(&kw)
387 }
388 }
389
390 fn supports_partiql(&self) -> bool {
391 true
392 }
393
394 fn is_column_alias(&self, kw: &Keyword, parser: &mut Parser) -> bool {
395 match kw {
396 Keyword::EXCEPT
400 | Keyword::RETURNING if !matches!(parser.peek_token_ref().token, Token::Comma | Token::EOF) =>
402 {
403 false
404 }
405
406 Keyword::LIMIT | Keyword::OFFSET if peek_for_limit_options(parser) => false,
409
410 Keyword::FETCH if parser.peek_one_of_keywords(&[Keyword::FIRST, Keyword::NEXT]).is_some()
415 || peek_for_limit_options(parser) =>
416 {
417 false
418 }
419
420 Keyword::FROM
424 | Keyword::GROUP
425 | Keyword::HAVING
426 | Keyword::INTERSECT
427 | Keyword::INTO
428 | Keyword::MINUS
429 | Keyword::ORDER
430 | Keyword::SELECT
431 | Keyword::UNION
432 | Keyword::WHERE
433 | Keyword::WITH => false,
434
435 _ => true,
437 }
438 }
439
440 fn is_table_alias(&self, kw: &Keyword, parser: &mut Parser) -> bool {
441 match kw {
442 Keyword::RETURNING
445 | Keyword::INNER
446 | Keyword::USING
447 | Keyword::PIVOT
448 | Keyword::UNPIVOT
449 | Keyword::EXCEPT
450 | Keyword::MATCH_RECOGNIZE
451 if !matches!(parser.peek_token_ref().token, Token::SemiColon | Token::EOF) =>
452 {
453 false
454 }
455
456 Keyword::LIMIT | Keyword::OFFSET if peek_for_limit_options(parser) => false,
460
461 Keyword::FETCH
466 if parser
467 .peek_one_of_keywords(&[Keyword::FIRST, Keyword::NEXT])
468 .is_some()
469 || peek_for_limit_options(parser) =>
470 {
471 false
472 }
473
474 Keyword::RIGHT | Keyword::LEFT | Keyword::SEMI | Keyword::ANTI
477 if parser
478 .peek_one_of_keywords(&[Keyword::JOIN, Keyword::OUTER])
479 .is_some() =>
480 {
481 false
482 }
483
484 Keyword::GLOBAL if parser.peek_keyword(Keyword::FULL) => false,
485
486 Keyword::WITH
490 | Keyword::ORDER
491 | Keyword::SELECT
492 | Keyword::WHERE
493 | Keyword::GROUP
494 | Keyword::HAVING
495 | Keyword::LATERAL
496 | Keyword::UNION
497 | Keyword::INTERSECT
498 | Keyword::MINUS
499 | Keyword::ON
500 | Keyword::JOIN
501 | Keyword::INNER
502 | Keyword::CROSS
503 | Keyword::FULL
504 | Keyword::LEFT
505 | Keyword::RIGHT
506 | Keyword::NATURAL
507 | Keyword::USING
508 | Keyword::ASOF
509 | Keyword::MATCH_CONDITION
510 | Keyword::SET
511 | Keyword::QUALIFY
512 | Keyword::FOR
513 | Keyword::START
514 | Keyword::CONNECT
515 | Keyword::SAMPLE
516 | Keyword::TABLESAMPLE
517 | Keyword::FROM => false,
518
519 _ => true,
521 }
522 }
523
524 fn is_table_factor(&self, kw: &Keyword, parser: &mut Parser) -> bool {
525 match kw {
526 Keyword::LIMIT if peek_for_limit_options(parser) => false,
527 Keyword::TABLE if matches!(parser.peek_token_ref().token, Token::LParen) => true,
529 _ => !RESERVED_KEYWORDS_FOR_TABLE_FACTOR.contains(kw),
530 }
531 }
532
533 fn supports_timestamp_versioning(&self) -> bool {
535 true
536 }
537
538 fn supports_group_by_expr(&self) -> bool {
540 true
541 }
542
543 fn get_reserved_keywords_for_select_item_operator(&self) -> &[Keyword] {
545 &RESERVED_KEYWORDS_FOR_SELECT_ITEM_OPERATOR
546 }
547
548 fn supports_space_separated_column_options(&self) -> bool {
549 true
550 }
551
552 fn supports_comma_separated_drop_column_list(&self) -> bool {
553 true
554 }
555
556 fn is_identifier_generating_function_name(
557 &self,
558 ident: &Ident,
559 name_parts: &[ObjectNamePart],
560 ) -> bool {
561 ident.quote_style.is_none()
562 && ident.value.to_lowercase() == "identifier"
563 && !name_parts
564 .iter()
565 .any(|p| matches!(p, ObjectNamePart::Function(_)))
566 }
567
568 fn supports_select_expr_star(&self) -> bool {
570 true
571 }
572
573 fn supports_select_wildcard_exclude(&self) -> bool {
574 true
575 }
576
577 fn supports_semantic_view_table_factor(&self) -> bool {
578 true
579 }
580}
581
582fn peek_for_limit_options(parser: &Parser) -> bool {
585 match &parser.peek_token_ref().token {
586 Token::Number(_, _) | Token::Placeholder(_) => true,
587 Token::SingleQuotedString(val) if val.is_empty() => true,
588 Token::DollarQuotedString(DollarQuotedString { value, .. }) if value.is_empty() => true,
589 Token::Word(w) if w.keyword == Keyword::NULL => true,
590 _ => false,
591 }
592}
593
594fn parse_file_staging_command(kw: Keyword, parser: &mut Parser) -> Result<Statement, ParserError> {
595 let stage = parse_snowflake_stage_name(parser)?;
596 let pattern = if parser.parse_keyword(Keyword::PATTERN) {
597 parser.expect_token(&Token::Eq)?;
598 Some(parser.parse_literal_string()?)
599 } else {
600 None
601 };
602
603 match kw {
604 Keyword::LIST | Keyword::LS => Ok(Statement::List(FileStagingCommand { stage, pattern })),
605 Keyword::REMOVE | Keyword::RM => {
606 Ok(Statement::Remove(FileStagingCommand { stage, pattern }))
607 }
608 _ => Err(ParserError::ParserError(
609 "unexpected stage command, expecting LIST, LS, REMOVE or RM".to_string(),
610 )),
611 }
612}
613
614fn parse_alter_dynamic_table(parser: &mut Parser) -> Result<Statement, ParserError> {
617 let table_name = parser.parse_object_name(true)?;
619
620 let operation = if parser.parse_keyword(Keyword::REFRESH) {
622 AlterTableOperation::Refresh
623 } else if parser.parse_keyword(Keyword::SUSPEND) {
624 AlterTableOperation::Suspend
625 } else if parser.parse_keyword(Keyword::RESUME) {
626 AlterTableOperation::Resume
627 } else {
628 return parser.expected(
629 "REFRESH, SUSPEND, or RESUME after ALTER DYNAMIC TABLE",
630 parser.peek_token(),
631 );
632 };
633
634 let end_token = if parser.peek_token_ref().token == Token::SemiColon {
635 parser.peek_token_ref().clone()
636 } else {
637 parser.get_current_token().clone()
638 };
639
640 Ok(Statement::AlterTable(AlterTable {
641 name: table_name,
642 if_exists: false,
643 only: false,
644 operations: vec![operation],
645 location: None,
646 on_cluster: None,
647 table_type: Some(AlterTableType::Dynamic),
648 end_token: AttachedToken(end_token),
649 }))
650}
651
652fn parse_alter_session(parser: &mut Parser, set: bool) -> Result<Statement, ParserError> {
655 let session_options = parse_session_options(parser, set)?;
656 Ok(Statement::AlterSession {
657 set,
658 session_params: KeyValueOptions {
659 options: session_options,
660 delimiter: KeyValueOptionsDelimiter::Space,
661 },
662 })
663}
664
665#[allow(clippy::too_many_arguments)]
669pub fn parse_create_table(
670 or_replace: bool,
671 global: Option<bool>,
672 temporary: bool,
673 volatile: bool,
674 transient: bool,
675 iceberg: bool,
676 dynamic: bool,
677 parser: &mut Parser,
678) -> Result<Statement, ParserError> {
679 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
680 let table_name = parser.parse_object_name(false)?;
681
682 let mut builder = CreateTableBuilder::new(table_name)
683 .or_replace(or_replace)
684 .if_not_exists(if_not_exists)
685 .temporary(temporary)
686 .transient(transient)
687 .volatile(volatile)
688 .iceberg(iceberg)
689 .global(global)
690 .dynamic(dynamic)
691 .hive_formats(None);
692
693 let mut plain_options = vec![];
700
701 loop {
702 let next_token = parser.next_token();
703 match &next_token.token {
704 Token::Word(word) => match word.keyword {
705 Keyword::COPY => {
706 parser.expect_keyword_is(Keyword::GRANTS)?;
707 builder = builder.copy_grants(true);
708 }
709 Keyword::COMMENT => {
710 parser.prev_token();
712 if let Some(comment_def) = parser.parse_optional_inline_comment()? {
713 plain_options.push(SqlOption::Comment(comment_def))
714 }
715 }
716 Keyword::AS => {
717 let query = parser.parse_query()?;
718 builder = builder.query(Some(query));
719 }
720 Keyword::CLONE => {
721 let clone = parser.parse_object_name(false).ok();
722 builder = builder.clone_clause(clone);
723 }
724 Keyword::LIKE => {
725 let name = parser.parse_object_name(false)?;
726 builder = builder.like(Some(CreateTableLikeKind::Plain(
727 crate::ast::CreateTableLike {
728 name,
729 defaults: None,
730 },
731 )));
732 }
733 Keyword::CLUSTER => {
734 parser.expect_keyword_is(Keyword::BY)?;
735 parser.expect_token(&Token::LParen)?;
736 let cluster_by = Some(WrappedCollection::Parentheses(
737 parser.parse_comma_separated(|p| p.parse_expr())?,
738 ));
739 parser.expect_token(&Token::RParen)?;
740
741 builder = builder.cluster_by(cluster_by)
742 }
743 Keyword::ENABLE_SCHEMA_EVOLUTION => {
744 parser.expect_token(&Token::Eq)?;
745 builder = builder.enable_schema_evolution(Some(parser.parse_boolean_string()?));
746 }
747 Keyword::CHANGE_TRACKING => {
748 parser.expect_token(&Token::Eq)?;
749 builder = builder.change_tracking(Some(parser.parse_boolean_string()?));
750 }
751 Keyword::DATA_RETENTION_TIME_IN_DAYS => {
752 parser.expect_token(&Token::Eq)?;
753 let data_retention_time_in_days = parser.parse_literal_uint()?;
754 builder =
755 builder.data_retention_time_in_days(Some(data_retention_time_in_days));
756 }
757 Keyword::MAX_DATA_EXTENSION_TIME_IN_DAYS => {
758 parser.expect_token(&Token::Eq)?;
759 let max_data_extension_time_in_days = parser.parse_literal_uint()?;
760 builder = builder
761 .max_data_extension_time_in_days(Some(max_data_extension_time_in_days));
762 }
763 Keyword::DEFAULT_DDL_COLLATION => {
764 parser.expect_token(&Token::Eq)?;
765 let default_ddl_collation = parser.parse_literal_string()?;
766 builder = builder.default_ddl_collation(Some(default_ddl_collation));
767 }
768 Keyword::WITH => {
771 parser.expect_one_of_keywords(&[
772 Keyword::AGGREGATION,
773 Keyword::TAG,
774 Keyword::ROW,
775 ])?;
776 parser.prev_token();
777 }
778 Keyword::AGGREGATION => {
779 parser.expect_keyword_is(Keyword::POLICY)?;
780 let aggregation_policy = parser.parse_object_name(false)?;
781 builder = builder.with_aggregation_policy(Some(aggregation_policy));
782 }
783 Keyword::ROW => {
784 parser.expect_keywords(&[Keyword::ACCESS, Keyword::POLICY])?;
785 let policy = parser.parse_object_name(false)?;
786 parser.expect_keyword_is(Keyword::ON)?;
787 parser.expect_token(&Token::LParen)?;
788 let columns = parser.parse_comma_separated(|p| p.parse_identifier())?;
789 parser.expect_token(&Token::RParen)?;
790
791 builder =
792 builder.with_row_access_policy(Some(RowAccessPolicy::new(policy, columns)))
793 }
794 Keyword::TAG => {
795 parser.expect_token(&Token::LParen)?;
796 let tags = parser.parse_comma_separated(Parser::parse_tag)?;
797 parser.expect_token(&Token::RParen)?;
798 builder = builder.with_tags(Some(tags));
799 }
800 Keyword::ON if parser.parse_keyword(Keyword::COMMIT) => {
801 let on_commit = Some(parser.parse_create_table_on_commit()?);
802 builder = builder.on_commit(on_commit);
803 }
804 Keyword::EXTERNAL_VOLUME => {
805 parser.expect_token(&Token::Eq)?;
806 builder.external_volume = Some(parser.parse_literal_string()?);
807 }
808 Keyword::CATALOG => {
809 parser.expect_token(&Token::Eq)?;
810 builder.catalog = Some(parser.parse_literal_string()?);
811 }
812 Keyword::BASE_LOCATION => {
813 parser.expect_token(&Token::Eq)?;
814 builder.base_location = Some(parser.parse_literal_string()?);
815 }
816 Keyword::CATALOG_SYNC => {
817 parser.expect_token(&Token::Eq)?;
818 builder.catalog_sync = Some(parser.parse_literal_string()?);
819 }
820 Keyword::STORAGE_SERIALIZATION_POLICY => {
821 parser.expect_token(&Token::Eq)?;
822
823 builder.storage_serialization_policy =
824 Some(parse_storage_serialization_policy(parser)?);
825 }
826 Keyword::IF if parser.parse_keywords(&[Keyword::NOT, Keyword::EXISTS]) => {
827 builder = builder.if_not_exists(true);
828 }
829 Keyword::TARGET_LAG => {
830 parser.expect_token(&Token::Eq)?;
831 let target_lag = parser.parse_literal_string()?;
832 builder = builder.target_lag(Some(target_lag));
833 }
834 Keyword::WAREHOUSE => {
835 parser.expect_token(&Token::Eq)?;
836 let warehouse = parser.parse_identifier()?;
837 builder = builder.warehouse(Some(warehouse));
838 }
839 Keyword::AT | Keyword::BEFORE => {
840 parser.prev_token();
841 let version = parser.maybe_parse_table_version()?;
842 builder = builder.version(version);
843 }
844 Keyword::REFRESH_MODE => {
845 parser.expect_token(&Token::Eq)?;
846 let refresh_mode = match parser.parse_one_of_keywords(&[
847 Keyword::AUTO,
848 Keyword::FULL,
849 Keyword::INCREMENTAL,
850 ]) {
851 Some(Keyword::AUTO) => Some(RefreshModeKind::Auto),
852 Some(Keyword::FULL) => Some(RefreshModeKind::Full),
853 Some(Keyword::INCREMENTAL) => Some(RefreshModeKind::Incremental),
854 _ => return parser.expected("AUTO, FULL or INCREMENTAL", next_token),
855 };
856 builder = builder.refresh_mode(refresh_mode);
857 }
858 Keyword::INITIALIZE => {
859 parser.expect_token(&Token::Eq)?;
860 let initialize = match parser
861 .parse_one_of_keywords(&[Keyword::ON_CREATE, Keyword::ON_SCHEDULE])
862 {
863 Some(Keyword::ON_CREATE) => Some(InitializeKind::OnCreate),
864 Some(Keyword::ON_SCHEDULE) => Some(InitializeKind::OnSchedule),
865 _ => return parser.expected("ON_CREATE or ON_SCHEDULE", next_token),
866 };
867 builder = builder.initialize(initialize);
868 }
869 Keyword::REQUIRE if parser.parse_keyword(Keyword::USER) => {
870 builder = builder.require_user(true);
871 }
872 _ => {
873 return parser.expected("end of statement", next_token);
874 }
875 },
876 Token::LParen => {
877 parser.prev_token();
878 let (columns, constraints) = parser.parse_columns()?;
879 builder = builder.columns(columns).constraints(constraints);
880 }
881 Token::EOF => {
882 break;
883 }
884 Token::SemiColon => {
885 parser.prev_token();
886 break;
887 }
888 _ => {
889 return parser.expected("end of statement", next_token);
890 }
891 }
892 }
893 let table_options = if !plain_options.is_empty() {
894 crate::ast::CreateTableOptions::Plain(plain_options)
895 } else {
896 crate::ast::CreateTableOptions::None
897 };
898
899 builder = builder.table_options(table_options);
900
901 if iceberg && builder.base_location.is_none() {
902 return Err(ParserError::ParserError(
903 "BASE_LOCATION is required for ICEBERG tables".to_string(),
904 ));
905 }
906
907 Ok(builder.build())
908}
909
910pub fn parse_create_database(
913 or_replace: bool,
914 transient: bool,
915 parser: &mut Parser,
916) -> Result<Statement, ParserError> {
917 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
918 let name = parser.parse_object_name(false)?;
919
920 let mut builder = CreateDatabaseBuilder::new(name)
921 .or_replace(or_replace)
922 .transient(transient)
923 .if_not_exists(if_not_exists);
924
925 loop {
926 let next_token = parser.next_token();
927 match &next_token.token {
928 Token::Word(word) => match word.keyword {
929 Keyword::CLONE => {
930 builder = builder.clone_clause(Some(parser.parse_object_name(false)?));
931 }
932 Keyword::DATA_RETENTION_TIME_IN_DAYS => {
933 parser.expect_token(&Token::Eq)?;
934 builder =
935 builder.data_retention_time_in_days(Some(parser.parse_literal_uint()?));
936 }
937 Keyword::MAX_DATA_EXTENSION_TIME_IN_DAYS => {
938 parser.expect_token(&Token::Eq)?;
939 builder =
940 builder.max_data_extension_time_in_days(Some(parser.parse_literal_uint()?));
941 }
942 Keyword::EXTERNAL_VOLUME => {
943 parser.expect_token(&Token::Eq)?;
944 builder = builder.external_volume(Some(parser.parse_literal_string()?));
945 }
946 Keyword::CATALOG => {
947 parser.expect_token(&Token::Eq)?;
948 builder = builder.catalog(Some(parser.parse_literal_string()?));
949 }
950 Keyword::REPLACE_INVALID_CHARACTERS => {
951 parser.expect_token(&Token::Eq)?;
952 builder =
953 builder.replace_invalid_characters(Some(parser.parse_boolean_string()?));
954 }
955 Keyword::DEFAULT_DDL_COLLATION => {
956 parser.expect_token(&Token::Eq)?;
957 builder = builder.default_ddl_collation(Some(parser.parse_literal_string()?));
958 }
959 Keyword::STORAGE_SERIALIZATION_POLICY => {
960 parser.expect_token(&Token::Eq)?;
961 let policy = parse_storage_serialization_policy(parser)?;
962 builder = builder.storage_serialization_policy(Some(policy));
963 }
964 Keyword::COMMENT => {
965 parser.expect_token(&Token::Eq)?;
966 builder = builder.comment(Some(parser.parse_literal_string()?));
967 }
968 Keyword::CATALOG_SYNC => {
969 parser.expect_token(&Token::Eq)?;
970 builder = builder.catalog_sync(Some(parser.parse_literal_string()?));
971 }
972 Keyword::CATALOG_SYNC_NAMESPACE_FLATTEN_DELIMITER => {
973 parser.expect_token(&Token::Eq)?;
974 builder = builder.catalog_sync_namespace_flatten_delimiter(Some(
975 parser.parse_literal_string()?,
976 ));
977 }
978 Keyword::CATALOG_SYNC_NAMESPACE_MODE => {
979 parser.expect_token(&Token::Eq)?;
980 let mode =
981 match parser.parse_one_of_keywords(&[Keyword::NEST, Keyword::FLATTEN]) {
982 Some(Keyword::NEST) => CatalogSyncNamespaceMode::Nest,
983 Some(Keyword::FLATTEN) => CatalogSyncNamespaceMode::Flatten,
984 _ => {
985 return parser.expected("NEST or FLATTEN", next_token);
986 }
987 };
988 builder = builder.catalog_sync_namespace_mode(Some(mode));
989 }
990 Keyword::WITH => {
991 if parser.parse_keyword(Keyword::TAG) {
992 parser.expect_token(&Token::LParen)?;
993 let tags = parser.parse_comma_separated(Parser::parse_tag)?;
994 parser.expect_token(&Token::RParen)?;
995 builder = builder.with_tags(Some(tags));
996 } else if parser.parse_keyword(Keyword::CONTACT) {
997 parser.expect_token(&Token::LParen)?;
998 let contacts = parser.parse_comma_separated(|p| {
999 let purpose = p.parse_identifier()?.value;
1000 p.expect_token(&Token::Eq)?;
1001 let contact = p.parse_identifier()?.value;
1002 Ok(ContactEntry { purpose, contact })
1003 })?;
1004 parser.expect_token(&Token::RParen)?;
1005 builder = builder.with_contacts(Some(contacts));
1006 } else {
1007 return parser.expected("TAG or CONTACT", next_token);
1008 }
1009 }
1010 _ => return parser.expected("end of statement", next_token),
1011 },
1012 Token::SemiColon | Token::EOF => break,
1013 _ => return parser.expected("end of statement", next_token),
1014 }
1015 }
1016 Ok(builder.build())
1017}
1018
1019pub fn parse_storage_serialization_policy(
1020 parser: &mut Parser,
1021) -> Result<StorageSerializationPolicy, ParserError> {
1022 let next_token = parser.next_token();
1023 match &next_token.token {
1024 Token::Word(w) => match w.keyword {
1025 Keyword::COMPATIBLE => Ok(StorageSerializationPolicy::Compatible),
1026 Keyword::OPTIMIZED => Ok(StorageSerializationPolicy::Optimized),
1027 _ => parser.expected("storage_serialization_policy", next_token),
1028 },
1029 _ => parser.expected("storage_serialization_policy", next_token),
1030 }
1031}
1032
1033pub fn parse_create_stage(
1034 or_replace: bool,
1035 temporary: bool,
1036 parser: &mut Parser,
1037) -> Result<Statement, ParserError> {
1038 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
1040 let name = parser.parse_object_name(false)?;
1041 let mut directory_table_params = Vec::new();
1042 let mut file_format = Vec::new();
1043 let mut copy_options = Vec::new();
1044 let mut comment = None;
1045
1046 let stage_params = parse_stage_params(parser)?;
1048
1049 if parser.parse_keyword(Keyword::DIRECTORY) {
1051 parser.expect_token(&Token::Eq)?;
1052 directory_table_params = parser.parse_key_value_options(true, &[])?.options;
1053 }
1054
1055 if parser.parse_keyword(Keyword::FILE_FORMAT) {
1057 parser.expect_token(&Token::Eq)?;
1058 file_format = parser.parse_key_value_options(true, &[])?.options;
1059 }
1060
1061 if parser.parse_keyword(Keyword::COPY_OPTIONS) {
1063 parser.expect_token(&Token::Eq)?;
1064 copy_options = parser.parse_key_value_options(true, &[])?.options;
1065 }
1066
1067 if parser.parse_keyword(Keyword::COMMENT) {
1069 parser.expect_token(&Token::Eq)?;
1070 comment = Some(parser.parse_comment_value()?);
1071 }
1072
1073 Ok(Statement::CreateStage {
1074 or_replace,
1075 temporary,
1076 if_not_exists,
1077 name,
1078 stage_params,
1079 directory_table_params: KeyValueOptions {
1080 options: directory_table_params,
1081 delimiter: KeyValueOptionsDelimiter::Space,
1082 },
1083 file_format: KeyValueOptions {
1084 options: file_format,
1085 delimiter: KeyValueOptionsDelimiter::Space,
1086 },
1087 copy_options: KeyValueOptions {
1088 options: copy_options,
1089 delimiter: KeyValueOptionsDelimiter::Space,
1090 },
1091 comment,
1092 })
1093}
1094
1095pub fn parse_stage_name_identifier(parser: &mut Parser) -> Result<Ident, ParserError> {
1096 let mut ident = String::new();
1097 while let Some(next_token) = parser.next_token_no_skip() {
1098 match &next_token.token {
1099 Token::Whitespace(_) | Token::SemiColon => break,
1100 Token::Period => {
1101 parser.prev_token();
1102 break;
1103 }
1104 Token::RParen => {
1105 parser.prev_token();
1106 break;
1107 }
1108 Token::AtSign => ident.push('@'),
1109 Token::Tilde => ident.push('~'),
1110 Token::Mod => ident.push('%'),
1111 Token::Div => ident.push('/'),
1112 Token::Plus => ident.push('+'),
1113 Token::Minus => ident.push('-'),
1114 Token::Number(n, _) => ident.push_str(n),
1115 Token::Word(w) => ident.push_str(&w.to_string()),
1116 _ => return parser.expected("stage name identifier", parser.peek_token()),
1117 }
1118 }
1119 Ok(Ident::new(ident))
1120}
1121
1122pub fn parse_snowflake_stage_name(parser: &mut Parser) -> Result<ObjectName, ParserError> {
1123 match parser.next_token().token {
1124 Token::AtSign => {
1125 parser.prev_token();
1126 let mut idents = vec![];
1127 loop {
1128 idents.push(parse_stage_name_identifier(parser)?);
1129 if !parser.consume_token(&Token::Period) {
1130 break;
1131 }
1132 }
1133 Ok(ObjectName::from(idents))
1134 }
1135 _ => {
1136 parser.prev_token();
1137 Ok(parser.parse_object_name(false)?)
1138 }
1139 }
1140}
1141
1142pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
1145 let kind = match parser.peek_token().token {
1146 Token::AtSign => CopyIntoSnowflakeKind::Location,
1148 Token::SingleQuotedString(s) if s.contains("://") => CopyIntoSnowflakeKind::Location,
1150 _ => CopyIntoSnowflakeKind::Table,
1151 };
1152
1153 let mut files: Vec<String> = vec![];
1154 let mut from_transformations: Option<Vec<StageLoadSelectItemKind>> = None;
1155 let mut from_stage_alias = None;
1156 let mut from_stage = None;
1157 let mut stage_params = StageParamsObject {
1158 url: None,
1159 encryption: KeyValueOptions {
1160 options: vec![],
1161 delimiter: KeyValueOptionsDelimiter::Space,
1162 },
1163 endpoint: None,
1164 storage_integration: None,
1165 credentials: KeyValueOptions {
1166 options: vec![],
1167 delimiter: KeyValueOptionsDelimiter::Space,
1168 },
1169 };
1170 let mut from_query = None;
1171 let mut partition = None;
1172 let mut file_format = Vec::new();
1173 let mut pattern = None;
1174 let mut validation_mode = None;
1175 let mut copy_options = Vec::new();
1176
1177 let into: ObjectName = parse_snowflake_stage_name(parser)?;
1178 if kind == CopyIntoSnowflakeKind::Location {
1179 stage_params = parse_stage_params(parser)?;
1180 }
1181
1182 let into_columns = match &parser.peek_token().token {
1183 Token::LParen => Some(parser.parse_parenthesized_column_list(IsOptional::Optional, true)?),
1184 _ => None,
1185 };
1186
1187 parser.expect_keyword_is(Keyword::FROM)?;
1188 match parser.next_token().token {
1189 Token::LParen if kind == CopyIntoSnowflakeKind::Table => {
1190 parser.expect_keyword_is(Keyword::SELECT)?;
1192 from_transformations = parse_select_items_for_data_load(parser)?;
1193
1194 parser.expect_keyword_is(Keyword::FROM)?;
1195 from_stage = Some(parse_snowflake_stage_name(parser)?);
1196 stage_params = parse_stage_params(parser)?;
1197
1198 from_stage_alias = parser
1200 .maybe_parse_table_alias()?
1201 .map(|table_alias| table_alias.name);
1202 parser.expect_token(&Token::RParen)?;
1203 }
1204 Token::LParen if kind == CopyIntoSnowflakeKind::Location => {
1205 from_query = Some(parser.parse_query()?);
1207 parser.expect_token(&Token::RParen)?;
1208 }
1209 _ => {
1210 parser.prev_token();
1211 from_stage = Some(parse_snowflake_stage_name(parser)?);
1212 stage_params = parse_stage_params(parser)?;
1213
1214 from_stage_alias = if parser.parse_keyword(Keyword::AS) {
1216 Some(match parser.next_token().token {
1217 Token::Word(w) => Ok(Ident::new(w.value)),
1218 _ => parser.expected("stage alias", parser.peek_token()),
1219 }?)
1220 } else {
1221 None
1222 };
1223 }
1224 }
1225
1226 loop {
1227 if parser.parse_keyword(Keyword::FILE_FORMAT) {
1229 parser.expect_token(&Token::Eq)?;
1230 file_format = parser.parse_key_value_options(true, &[])?.options;
1231 } else if parser.parse_keywords(&[Keyword::PARTITION, Keyword::BY]) {
1233 partition = Some(Box::new(parser.parse_expr()?))
1234 } else if parser.parse_keyword(Keyword::FILES) {
1236 parser.expect_token(&Token::Eq)?;
1237 parser.expect_token(&Token::LParen)?;
1238 let mut continue_loop = true;
1239 while continue_loop {
1240 continue_loop = false;
1241 let next_token = parser.next_token();
1242 match next_token.token {
1243 Token::SingleQuotedString(s) => files.push(s),
1244 _ => parser.expected("file token", next_token)?,
1245 };
1246 if parser.next_token().token.eq(&Token::Comma) {
1247 continue_loop = true;
1248 } else {
1249 parser.prev_token(); }
1251 }
1252 parser.expect_token(&Token::RParen)?;
1253 } else if parser.parse_keyword(Keyword::PATTERN) {
1255 parser.expect_token(&Token::Eq)?;
1256 let next_token = parser.next_token();
1257 pattern = Some(match next_token.token {
1258 Token::SingleQuotedString(s) => s,
1259 _ => parser.expected("pattern", next_token)?,
1260 });
1261 } else if parser.parse_keyword(Keyword::VALIDATION_MODE) {
1263 parser.expect_token(&Token::Eq)?;
1264 validation_mode = Some(parser.next_token().token.to_string());
1265 } else if parser.parse_keyword(Keyword::COPY_OPTIONS) {
1267 parser.expect_token(&Token::Eq)?;
1268 copy_options = parser.parse_key_value_options(true, &[])?.options;
1269 } else {
1270 match parser.next_token().token {
1271 Token::SemiColon | Token::EOF => break,
1272 Token::Comma => continue,
1273 Token::Word(key) => copy_options.push(parser.parse_key_value_option(&key)?),
1276 _ => return parser.expected("another copy option, ; or EOF'", parser.peek_token()),
1277 }
1278 }
1279 }
1280
1281 Ok(Statement::CopyIntoSnowflake {
1282 kind,
1283 into,
1284 into_columns,
1285 from_obj: from_stage,
1286 from_obj_alias: from_stage_alias,
1287 stage_params,
1288 from_transformations,
1289 from_query,
1290 files: if files.is_empty() { None } else { Some(files) },
1291 pattern,
1292 file_format: KeyValueOptions {
1293 options: file_format,
1294 delimiter: KeyValueOptionsDelimiter::Space,
1295 },
1296 copy_options: KeyValueOptions {
1297 options: copy_options,
1298 delimiter: KeyValueOptionsDelimiter::Space,
1299 },
1300 validation_mode,
1301 partition,
1302 })
1303}
1304
1305fn parse_select_items_for_data_load(
1306 parser: &mut Parser,
1307) -> Result<Option<Vec<StageLoadSelectItemKind>>, ParserError> {
1308 let mut select_items: Vec<StageLoadSelectItemKind> = vec![];
1309 loop {
1310 match parser.maybe_parse(parse_select_item_for_data_load)? {
1311 Some(item) => select_items.push(StageLoadSelectItemKind::StageLoadSelectItem(item)),
1313 None => select_items.push(StageLoadSelectItemKind::SelectItem(
1315 parser.parse_select_item()?,
1316 )),
1317 }
1318 if matches!(parser.peek_token_ref().token, Token::Comma) {
1319 parser.advance_token();
1320 } else {
1321 break;
1322 }
1323 }
1324 Ok(Some(select_items))
1325}
1326
1327fn parse_select_item_for_data_load(
1328 parser: &mut Parser,
1329) -> Result<StageLoadSelectItem, ParserError> {
1330 let mut alias: Option<Ident> = None;
1331 let mut file_col_num: i32 = 0;
1332 let mut element: Option<Ident> = None;
1333 let mut item_as: Option<Ident> = None;
1334
1335 let next_token = parser.next_token();
1336 match next_token.token {
1337 Token::Placeholder(w) => {
1338 file_col_num = w.to_string().split_off(1).parse::<i32>().map_err(|e| {
1339 ParserError::ParserError(format!("Could not parse '{w}' as i32: {e}"))
1340 })?;
1341 Ok(())
1342 }
1343 Token::Word(w) => {
1344 alias = Some(Ident::new(w.value));
1345 Ok(())
1346 }
1347 _ => parser.expected("alias or file_col_num", next_token),
1348 }?;
1349
1350 if alias.is_some() {
1351 parser.expect_token(&Token::Period)?;
1352 let col_num_token = parser.next_token();
1354 match col_num_token.token {
1355 Token::Placeholder(w) => {
1356 file_col_num = w.to_string().split_off(1).parse::<i32>().map_err(|e| {
1357 ParserError::ParserError(format!("Could not parse '{w}' as i32: {e}"))
1358 })?;
1359 Ok(())
1360 }
1361 _ => parser.expected("file_col_num", col_num_token),
1362 }?;
1363 }
1364
1365 match parser.next_token().token {
1367 Token::Colon => {
1368 element = Some(Ident::new(match parser.next_token().token {
1370 Token::Word(w) => Ok(w.value),
1371 _ => parser.expected("file_col_num", parser.peek_token()),
1372 }?));
1373 }
1374 _ => {
1375 parser.prev_token();
1377 }
1378 }
1379
1380 if parser.parse_keyword(Keyword::AS) {
1382 item_as = Some(match parser.next_token().token {
1383 Token::Word(w) => Ok(Ident::new(w.value)),
1384 _ => parser.expected("column item alias", parser.peek_token()),
1385 }?);
1386 }
1387
1388 Ok(StageLoadSelectItem {
1389 alias,
1390 file_col_num,
1391 element,
1392 item_as,
1393 })
1394}
1395
1396fn parse_stage_params(parser: &mut Parser) -> Result<StageParamsObject, ParserError> {
1397 let (mut url, mut storage_integration, mut endpoint) = (None, None, None);
1398 let mut encryption: KeyValueOptions = KeyValueOptions {
1399 options: vec![],
1400 delimiter: KeyValueOptionsDelimiter::Space,
1401 };
1402 let mut credentials: KeyValueOptions = KeyValueOptions {
1403 options: vec![],
1404 delimiter: KeyValueOptionsDelimiter::Space,
1405 };
1406
1407 if parser.parse_keyword(Keyword::URL) {
1409 parser.expect_token(&Token::Eq)?;
1410 url = Some(match parser.next_token().token {
1411 Token::SingleQuotedString(word) => Ok(word),
1412 _ => parser.expected("a URL statement", parser.peek_token()),
1413 }?)
1414 }
1415
1416 if parser.parse_keyword(Keyword::STORAGE_INTEGRATION) {
1418 parser.expect_token(&Token::Eq)?;
1419 storage_integration = Some(parser.next_token().token.to_string());
1420 }
1421
1422 if parser.parse_keyword(Keyword::ENDPOINT) {
1424 parser.expect_token(&Token::Eq)?;
1425 endpoint = Some(match parser.next_token().token {
1426 Token::SingleQuotedString(word) => Ok(word),
1427 _ => parser.expected("an endpoint statement", parser.peek_token()),
1428 }?)
1429 }
1430
1431 if parser.parse_keyword(Keyword::CREDENTIALS) {
1433 parser.expect_token(&Token::Eq)?;
1434 credentials = KeyValueOptions {
1435 options: parser.parse_key_value_options(true, &[])?.options,
1436 delimiter: KeyValueOptionsDelimiter::Space,
1437 };
1438 }
1439
1440 if parser.parse_keyword(Keyword::ENCRYPTION) {
1442 parser.expect_token(&Token::Eq)?;
1443 encryption = KeyValueOptions {
1444 options: parser.parse_key_value_options(true, &[])?.options,
1445 delimiter: KeyValueOptionsDelimiter::Space,
1446 };
1447 }
1448
1449 Ok(StageParamsObject {
1450 url,
1451 encryption,
1452 endpoint,
1453 storage_integration,
1454 credentials,
1455 })
1456}
1457
1458fn parse_session_options(
1463 parser: &mut Parser,
1464 set: bool,
1465) -> Result<Vec<KeyValueOption>, ParserError> {
1466 let mut options: Vec<KeyValueOption> = Vec::new();
1467 let empty = String::new;
1468 loop {
1469 let next_token = parser.peek_token();
1470 match next_token.token {
1471 Token::SemiColon | Token::EOF => break,
1472 Token::Comma => {
1473 parser.advance_token();
1474 continue;
1475 }
1476 Token::Word(key) => {
1477 parser.advance_token();
1478 if set {
1479 let option = parser.parse_key_value_option(&key)?;
1480 options.push(option);
1481 } else {
1482 options.push(KeyValueOption {
1483 option_name: key.value,
1484 option_value: KeyValueOptionKind::Single(Value::Placeholder(empty())),
1485 });
1486 }
1487 }
1488 _ => {
1489 return parser.expected("another option or end of statement", next_token);
1490 }
1491 }
1492 }
1493 if options.is_empty() {
1494 Err(ParserError::ParserError(
1495 "expected at least one option".to_string(),
1496 ))
1497 } else {
1498 Ok(options)
1499 }
1500}
1501
1502fn parse_identity_property(parser: &mut Parser) -> Result<IdentityProperty, ParserError> {
1509 let parameters = if parser.consume_token(&Token::LParen) {
1510 let seed = parser.parse_number()?;
1511 parser.expect_token(&Token::Comma)?;
1512 let increment = parser.parse_number()?;
1513 parser.expect_token(&Token::RParen)?;
1514
1515 Some(IdentityPropertyFormatKind::FunctionCall(
1516 IdentityParameters { seed, increment },
1517 ))
1518 } else if parser.parse_keyword(Keyword::START) {
1519 let seed = parser.parse_number()?;
1520 parser.expect_keyword_is(Keyword::INCREMENT)?;
1521 let increment = parser.parse_number()?;
1522
1523 Some(IdentityPropertyFormatKind::StartAndIncrement(
1524 IdentityParameters { seed, increment },
1525 ))
1526 } else {
1527 None
1528 };
1529 let order = match parser.parse_one_of_keywords(&[Keyword::ORDER, Keyword::NOORDER]) {
1530 Some(Keyword::ORDER) => Some(IdentityPropertyOrder::Order),
1531 Some(Keyword::NOORDER) => Some(IdentityPropertyOrder::NoOrder),
1532 _ => None,
1533 };
1534 Ok(IdentityProperty { parameters, order })
1535}
1536
1537fn parse_column_policy_property(
1544 parser: &mut Parser,
1545 with: bool,
1546) -> Result<ColumnPolicyProperty, ParserError> {
1547 let policy_name = parser.parse_object_name(false)?;
1548 let using_columns = if parser.parse_keyword(Keyword::USING) {
1549 parser.expect_token(&Token::LParen)?;
1550 let columns = parser.parse_comma_separated(|p| p.parse_identifier())?;
1551 parser.expect_token(&Token::RParen)?;
1552 Some(columns)
1553 } else {
1554 None
1555 };
1556
1557 Ok(ColumnPolicyProperty {
1558 with,
1559 policy_name,
1560 using_columns,
1561 })
1562}
1563
1564fn parse_column_tags(parser: &mut Parser, with: bool) -> Result<TagsColumnOption, ParserError> {
1571 parser.expect_token(&Token::LParen)?;
1572 let tags = parser.parse_comma_separated(Parser::parse_tag)?;
1573 parser.expect_token(&Token::RParen)?;
1574
1575 Ok(TagsColumnOption { with, tags })
1576}
1577
1578fn parse_show_objects(terse: bool, parser: &mut Parser) -> Result<Statement, ParserError> {
1581 let show_options = parser.parse_show_stmt_options()?;
1582 Ok(Statement::ShowObjects(ShowObjects {
1583 terse,
1584 show_options,
1585 }))
1586}