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, CreateTable,
32 CreateTableLikeKind, DollarQuotedString, Ident, IdentityParameters, IdentityProperty,
33 IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, InitializeKind,
34 Insert, MultiTableInsertIntoClause, MultiTableInsertType, MultiTableInsertValue,
35 MultiTableInsertValues, MultiTableInsertWhenClause, ObjectName, ObjectNamePart,
36 RefreshModeKind, RowAccessPolicy, ShowObjects, SqlOption, Statement, StorageLifecyclePolicy,
37 StorageSerializationPolicy, TableObject, TagsColumnOption, Value, WrappedCollection,
38};
39use crate::dialect::{Dialect, Precedence};
40use crate::keywords::Keyword;
41use crate::parser::{IsOptional, Parser, ParserError};
42use crate::tokenizer::TokenWithSpan;
43use crate::tokenizer::{Span, Token};
44#[cfg(not(feature = "std"))]
45use alloc::boxed::Box;
46#[cfg(not(feature = "std"))]
47use alloc::string::String;
48#[cfg(not(feature = "std"))]
49use alloc::vec::Vec;
50#[cfg(not(feature = "std"))]
51use alloc::{format, vec};
52
53use super::keywords::RESERVED_FOR_IDENTIFIER;
54
55const RESERVED_KEYWORDS_FOR_SELECT_ITEM_OPERATOR: [Keyword; 1] = [Keyword::CONNECT_BY_ROOT];
56
57const RESERVED_KEYWORDS_FOR_TABLE_FACTOR: &[Keyword] = &[
59 Keyword::ALL,
60 Keyword::ALTER,
61 Keyword::AND,
62 Keyword::ANY,
63 Keyword::AS,
64 Keyword::BETWEEN,
65 Keyword::BY,
66 Keyword::CHECK,
67 Keyword::COLUMN,
68 Keyword::CONNECT,
69 Keyword::CREATE,
70 Keyword::CROSS,
71 Keyword::CURRENT,
72 Keyword::DELETE,
73 Keyword::DISTINCT,
74 Keyword::DROP,
75 Keyword::ELSE,
76 Keyword::EXISTS,
77 Keyword::FOLLOWING,
78 Keyword::FOR,
79 Keyword::FROM,
80 Keyword::FULL,
81 Keyword::GRANT,
82 Keyword::GROUP,
83 Keyword::HAVING,
84 Keyword::ILIKE,
85 Keyword::IN,
86 Keyword::INCREMENT,
87 Keyword::INNER,
88 Keyword::INSERT,
89 Keyword::INTERSECT,
90 Keyword::INTO,
91 Keyword::IS,
92 Keyword::JOIN,
93 Keyword::LEFT,
94 Keyword::LIKE,
95 Keyword::MINUS,
96 Keyword::NATURAL,
97 Keyword::NOT,
98 Keyword::NULL,
99 Keyword::OF,
100 Keyword::ON,
101 Keyword::OR,
102 Keyword::ORDER,
103 Keyword::QUALIFY,
104 Keyword::REGEXP,
105 Keyword::REVOKE,
106 Keyword::RIGHT,
107 Keyword::RLIKE,
108 Keyword::ROW,
109 Keyword::ROWS,
110 Keyword::SAMPLE,
111 Keyword::SELECT,
112 Keyword::SET,
113 Keyword::SOME,
114 Keyword::START,
115 Keyword::TABLE,
116 Keyword::TABLESAMPLE,
117 Keyword::THEN,
118 Keyword::TO,
119 Keyword::TRIGGER,
120 Keyword::UNION,
121 Keyword::UNIQUE,
122 Keyword::UPDATE,
123 Keyword::USING,
124 Keyword::VALUES,
125 Keyword::WHEN,
126 Keyword::WHENEVER,
127 Keyword::WHERE,
128 Keyword::WINDOW,
129 Keyword::WITH,
130];
131
132#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
134#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
135pub struct SnowflakeDialect;
136
137impl Dialect for SnowflakeDialect {
138 fn is_identifier_start(&self, ch: char) -> bool {
140 ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch == '_'
141 }
142
143 fn supports_projection_trailing_commas(&self) -> bool {
144 true
145 }
146
147 fn supports_from_trailing_commas(&self) -> bool {
148 true
149 }
150
151 fn supports_object_name_double_dot_notation(&self) -> bool {
156 true
157 }
158
159 fn is_identifier_part(&self, ch: char) -> bool {
160 ch.is_ascii_lowercase()
161 || ch.is_ascii_uppercase()
162 || ch.is_ascii_digit()
163 || ch == '$'
164 || ch == '_'
165 }
166
167 fn supports_string_literal_backslash_escape(&self) -> bool {
169 true
170 }
171
172 fn supports_within_after_array_aggregation(&self) -> bool {
173 true
174 }
175
176 fn supports_outer_join_operator(&self) -> bool {
178 true
179 }
180
181 fn supports_connect_by(&self) -> bool {
182 true
183 }
184
185 fn supports_execute_immediate(&self) -> bool {
187 true
188 }
189
190 fn supports_match_recognize(&self) -> bool {
191 true
192 }
193
194 fn supports_dictionary_syntax(&self) -> bool {
199 true
200 }
201
202 fn supports_window_function_null_treatment_arg(&self) -> bool {
205 true
206 }
207
208 fn supports_parenthesized_set_variables(&self) -> bool {
210 true
211 }
212
213 fn supports_comment_on(&self) -> bool {
215 true
216 }
217
218 fn supports_extract_comma_syntax(&self) -> bool {
220 true
221 }
222
223 fn supports_subquery_as_function_arg(&self) -> bool {
225 true
226 }
227
228 fn supports_create_view_comment_syntax(&self) -> bool {
230 true
231 }
232
233 fn supports_array_typedef_without_element_type(&self) -> bool {
235 true
236 }
237
238 fn supports_parens_around_table_factor(&self) -> bool {
240 true
241 }
242
243 fn supports_values_as_table_factor(&self) -> bool {
245 true
246 }
247
248 fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
249 if parser.parse_keyword(Keyword::BEGIN) {
250 if parser
254 .peek_one_of_keywords(&[Keyword::TRANSACTION, Keyword::WORK, Keyword::NAME])
255 .is_some()
256 || matches!(parser.peek_token_ref().token, Token::SemiColon | Token::EOF)
257 {
258 parser.prev_token();
259 return None;
260 }
261 return Some(parser.parse_begin_exception_end());
262 }
263
264 if parser.parse_keywords(&[Keyword::ALTER, Keyword::DYNAMIC, Keyword::TABLE]) {
265 return Some(parse_alter_dynamic_table(parser));
267 }
268
269 if parser.parse_keywords(&[Keyword::ALTER, Keyword::EXTERNAL, Keyword::TABLE]) {
270 return Some(parse_alter_external_table(parser));
272 }
273
274 if parser.parse_keywords(&[Keyword::ALTER, Keyword::SESSION]) {
275 let set = match parser.parse_one_of_keywords(&[Keyword::SET, Keyword::UNSET]) {
277 Some(Keyword::SET) => true,
278 Some(Keyword::UNSET) => false,
279 _ => return Some(parser.expected_ref("SET or UNSET", parser.peek_token_ref())),
280 };
281 return Some(parse_alter_session(parser, set));
282 }
283
284 if parser.parse_keyword(Keyword::CREATE) {
285 let or_replace = parser.parse_keywords(&[Keyword::OR, Keyword::REPLACE]);
288 let global = match parser.parse_one_of_keywords(&[Keyword::LOCAL, Keyword::GLOBAL]) {
290 Some(Keyword::LOCAL) => Some(false),
291 Some(Keyword::GLOBAL) => Some(true),
292 _ => None,
293 };
294
295 let dynamic = parser.parse_keyword(Keyword::DYNAMIC);
296
297 let mut temporary = false;
298 let mut volatile = false;
299 let mut transient = false;
300 let mut iceberg = false;
301
302 match parser.parse_one_of_keywords(&[
303 Keyword::TEMP,
304 Keyword::TEMPORARY,
305 Keyword::VOLATILE,
306 Keyword::TRANSIENT,
307 Keyword::ICEBERG,
308 ]) {
309 Some(Keyword::TEMP | Keyword::TEMPORARY) => temporary = true,
310 Some(Keyword::VOLATILE) => volatile = true,
311 Some(Keyword::TRANSIENT) => transient = true,
312 Some(Keyword::ICEBERG) => iceberg = true,
313 _ => {}
314 }
315
316 if parser.parse_keyword(Keyword::STAGE) {
317 return Some(parse_create_stage(or_replace, temporary, parser));
319 } else if parser.parse_keyword(Keyword::TABLE) {
320 return Some(
321 parse_create_table(
322 or_replace, global, temporary, volatile, transient, iceberg, dynamic,
323 parser,
324 )
325 .map(Into::into),
326 );
327 } else if parser.parse_keyword(Keyword::DATABASE) {
328 return Some(parse_create_database(or_replace, transient, parser));
329 } else {
330 let mut back = 1;
332 if or_replace {
333 back += 2
334 }
335 if temporary {
336 back += 1
337 }
338 for _i in 0..back {
339 parser.prev_token();
340 }
341 }
342 }
343 if parser.parse_keywords(&[Keyword::COPY, Keyword::INTO]) {
344 return Some(parse_copy_into(parser));
346 }
347
348 if let Some(kw) = parser.parse_one_of_keywords(&[
349 Keyword::LIST,
350 Keyword::LS,
351 Keyword::REMOVE,
352 Keyword::RM,
353 ]) {
354 return Some(parse_file_staging_command(kw, parser));
355 }
356
357 if parser.parse_keyword(Keyword::SHOW) {
358 let terse = parser.parse_keyword(Keyword::TERSE);
359 if parser.parse_keyword(Keyword::OBJECTS) {
360 return Some(parse_show_objects(terse, parser));
361 }
362 if terse {
364 parser.prev_token();
365 }
366 parser.prev_token();
368 }
369
370 if parser.parse_keyword(Keyword::INSERT) {
373 let insert_token = parser.get_current_token().clone();
374 let overwrite = parser.parse_keyword(Keyword::OVERWRITE);
375
376 if let Some(kw) = parser.parse_one_of_keywords(&[Keyword::ALL, Keyword::FIRST]) {
378 let multi_table_insert_type = match kw {
379 Keyword::FIRST => MultiTableInsertType::First,
380 _ => MultiTableInsertType::All,
381 };
382 return Some(parse_multi_table_insert(
383 parser,
384 insert_token,
385 overwrite,
386 multi_table_insert_type,
387 ));
388 }
389
390 if overwrite {
392 parser.prev_token(); }
394 parser.prev_token(); }
396
397 None
398 }
399
400 fn parse_column_option(
401 &self,
402 parser: &mut Parser,
403 ) -> Result<Option<Result<Option<ColumnOption>, ParserError>>, ParserError> {
404 parser.maybe_parse(|parser| {
405 let with = parser.parse_keyword(Keyword::WITH);
406
407 if parser.parse_keyword(Keyword::IDENTITY) {
408 Ok(parse_identity_property(parser)
409 .map(|p| Some(ColumnOption::Identity(IdentityPropertyKind::Identity(p)))))
410 } else if parser.parse_keyword(Keyword::AUTOINCREMENT) {
411 Ok(parse_identity_property(parser).map(|p| {
412 Some(ColumnOption::Identity(IdentityPropertyKind::Autoincrement(
413 p,
414 )))
415 }))
416 } else if parser.parse_keywords(&[Keyword::MASKING, Keyword::POLICY]) {
417 Ok(parse_column_policy_property(parser, with)
418 .map(|p| Some(ColumnOption::Policy(ColumnPolicy::MaskingPolicy(p)))))
419 } else if parser.parse_keywords(&[Keyword::PROJECTION, Keyword::POLICY]) {
420 Ok(parse_column_policy_property(parser, with)
421 .map(|p| Some(ColumnOption::Policy(ColumnPolicy::ProjectionPolicy(p)))))
422 } else if parser.parse_keywords(&[Keyword::TAG]) {
423 Ok(parse_column_tags(parser, with).map(|p| Some(ColumnOption::Tags(p))))
424 } else {
425 Err(ParserError::ParserError("not found match".to_string()))
426 }
427 })
428 }
429
430 fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
431 let token = parser.peek_token_ref();
432 match &token.token {
434 Token::Colon => Some(Ok(self.prec_value(Precedence::DoubleColon))),
435 _ => None,
436 }
437 }
438
439 fn describe_requires_table_keyword(&self) -> bool {
440 true
441 }
442
443 fn allow_extract_custom(&self) -> bool {
444 true
445 }
446
447 fn allow_extract_single_quotes(&self) -> bool {
448 true
449 }
450
451 fn supports_show_like_before_in(&self) -> bool {
454 true
455 }
456
457 fn supports_left_associative_joins_without_parens(&self) -> bool {
458 false
459 }
460
461 fn is_reserved_for_identifier(&self, kw: Keyword) -> bool {
462 if matches!(kw, Keyword::INTERVAL) {
465 false
466 } else {
467 RESERVED_FOR_IDENTIFIER.contains(&kw)
468 }
469 }
470
471 fn supports_partiql(&self) -> bool {
472 true
473 }
474
475 fn is_column_alias(&self, kw: &Keyword, parser: &mut Parser) -> bool {
476 match kw {
477 Keyword::EXCEPT
481 | Keyword::RETURNING if !matches!(parser.peek_token_ref().token, Token::Comma | Token::EOF) =>
483 {
484 false
485 }
486
487 Keyword::LIMIT | Keyword::OFFSET if peek_for_limit_options(parser) => false,
490
491 Keyword::FETCH if parser.peek_one_of_keywords(&[Keyword::FIRST, Keyword::NEXT]).is_some()
496 || peek_for_limit_options(parser) =>
497 {
498 false
499 }
500
501 Keyword::FROM
505 | Keyword::GROUP
506 | Keyword::HAVING
507 | Keyword::INTERSECT
508 | Keyword::INTO
509 | Keyword::MINUS
510 | Keyword::ORDER
511 | Keyword::SELECT
512 | Keyword::UNION
513 | Keyword::WHERE
514 | Keyword::WITH => false,
515
516 _ => true,
518 }
519 }
520
521 fn is_table_alias(&self, kw: &Keyword, parser: &mut Parser) -> bool {
522 match kw {
523 Keyword::RETURNING
526 | Keyword::INNER
527 | Keyword::USING
528 | Keyword::PIVOT
529 | Keyword::UNPIVOT
530 | Keyword::EXCEPT
531 | Keyword::MATCH_RECOGNIZE
532 if !matches!(parser.peek_token_ref().token, Token::SemiColon | Token::EOF) =>
533 {
534 false
535 }
536
537 Keyword::LIMIT | Keyword::OFFSET if peek_for_limit_options(parser) => false,
541
542 Keyword::FETCH
547 if parser
548 .peek_one_of_keywords(&[Keyword::FIRST, Keyword::NEXT])
549 .is_some()
550 || peek_for_limit_options(parser) =>
551 {
552 false
553 }
554
555 Keyword::RIGHT | Keyword::LEFT | Keyword::SEMI | Keyword::ANTI
558 if parser
559 .peek_one_of_keywords(&[Keyword::JOIN, Keyword::OUTER])
560 .is_some() =>
561 {
562 false
563 }
564
565 Keyword::GLOBAL if parser.peek_keyword(Keyword::FULL) => false,
566
567 Keyword::WITH
571 | Keyword::ORDER
572 | Keyword::SELECT
573 | Keyword::WHERE
574 | Keyword::GROUP
575 | Keyword::HAVING
576 | Keyword::LATERAL
577 | Keyword::UNION
578 | Keyword::INTERSECT
579 | Keyword::MINUS
580 | Keyword::ON
581 | Keyword::JOIN
582 | Keyword::INNER
583 | Keyword::CROSS
584 | Keyword::FULL
585 | Keyword::LEFT
586 | Keyword::RIGHT
587 | Keyword::NATURAL
588 | Keyword::USING
589 | Keyword::ASOF
590 | Keyword::MATCH_CONDITION
591 | Keyword::SET
592 | Keyword::QUALIFY
593 | Keyword::FOR
594 | Keyword::START
595 | Keyword::CONNECT
596 | Keyword::SAMPLE
597 | Keyword::TABLESAMPLE
598 | Keyword::FROM => false,
599
600 _ => true,
602 }
603 }
604
605 fn is_table_factor(&self, kw: &Keyword, parser: &mut Parser) -> bool {
606 match kw {
607 Keyword::LIMIT if peek_for_limit_options(parser) => false,
608 Keyword::TABLE if matches!(parser.peek_token_ref().token, Token::LParen) => true,
610 _ => !RESERVED_KEYWORDS_FOR_TABLE_FACTOR.contains(kw),
611 }
612 }
613
614 fn supports_table_versioning(&self) -> bool {
616 true
617 }
618
619 fn supports_group_by_expr(&self) -> bool {
621 true
622 }
623
624 fn get_reserved_keywords_for_select_item_operator(&self) -> &[Keyword] {
626 &RESERVED_KEYWORDS_FOR_SELECT_ITEM_OPERATOR
627 }
628
629 fn supports_space_separated_column_options(&self) -> bool {
630 true
631 }
632
633 fn supports_comma_separated_drop_column_list(&self) -> bool {
634 true
635 }
636
637 fn is_identifier_generating_function_name(
638 &self,
639 ident: &Ident,
640 name_parts: &[ObjectNamePart],
641 ) -> bool {
642 ident.quote_style.is_none()
643 && ident.value.to_lowercase() == "identifier"
644 && !name_parts
645 .iter()
646 .any(|p| matches!(p, ObjectNamePart::Function(_)))
647 }
648
649 fn supports_select_expr_star(&self) -> bool {
651 true
652 }
653
654 fn supports_select_wildcard_exclude(&self) -> bool {
655 true
656 }
657
658 fn supports_semantic_view_table_factor(&self) -> bool {
659 true
660 }
661
662 fn supports_select_wildcard_replace(&self) -> bool {
664 true
665 }
666
667 fn supports_select_wildcard_ilike(&self) -> bool {
669 true
670 }
671
672 fn supports_select_wildcard_rename(&self) -> bool {
674 true
675 }
676
677 fn supports_lambda_functions(&self) -> bool {
679 true
680 }
681
682 fn supports_comma_separated_trim(&self) -> bool {
683 true
684 }
685}
686
687fn peek_for_limit_options(parser: &Parser) -> bool {
690 match &parser.peek_token_ref().token {
691 Token::Number(_, _) | Token::Placeholder(_) => true,
692 Token::SingleQuotedString(val) if val.is_empty() => true,
693 Token::DollarQuotedString(DollarQuotedString { value, .. }) if value.is_empty() => true,
694 Token::Word(w) if w.keyword == Keyword::NULL => true,
695 _ => false,
696 }
697}
698
699fn parse_file_staging_command(kw: Keyword, parser: &mut Parser) -> Result<Statement, ParserError> {
700 let stage = parse_snowflake_stage_name(parser)?;
701 let pattern = if parser.parse_keyword(Keyword::PATTERN) {
702 parser.expect_token(&Token::Eq)?;
703 Some(parser.parse_literal_string()?)
704 } else {
705 None
706 };
707
708 match kw {
709 Keyword::LIST | Keyword::LS => Ok(Statement::List(FileStagingCommand { stage, pattern })),
710 Keyword::REMOVE | Keyword::RM => {
711 Ok(Statement::Remove(FileStagingCommand { stage, pattern }))
712 }
713 _ => Err(ParserError::ParserError(
714 "unexpected stage command, expecting LIST, LS, REMOVE or RM".to_string(),
715 )),
716 }
717}
718
719fn parse_alter_dynamic_table(parser: &mut Parser) -> Result<Statement, ParserError> {
722 let table_name = parser.parse_object_name(true)?;
724
725 let operation = if parser.parse_keyword(Keyword::REFRESH) {
727 AlterTableOperation::Refresh { subpath: None }
728 } else if parser.parse_keyword(Keyword::SUSPEND) {
729 AlterTableOperation::Suspend
730 } else if parser.parse_keyword(Keyword::RESUME) {
731 AlterTableOperation::Resume
732 } else {
733 return parser.expected_ref(
734 "REFRESH, SUSPEND, or RESUME after ALTER DYNAMIC TABLE",
735 parser.peek_token_ref(),
736 );
737 };
738
739 let end_token = if parser.peek_token_ref().token == Token::SemiColon {
740 parser.peek_token_ref().clone()
741 } else {
742 parser.get_current_token().clone()
743 };
744
745 Ok(Statement::AlterTable(AlterTable {
746 name: table_name,
747 r#async: false,
748 if_exists: false,
749 only: false,
750 operations: vec![operation],
751 location: None,
752 on_cluster: None,
753 table_type: Some(AlterTableType::Dynamic),
754 end_token: AttachedToken(end_token),
755 }))
756}
757
758fn parse_alter_external_table(parser: &mut Parser) -> Result<Statement, ParserError> {
761 let if_exists = parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
762 let table_name = parser.parse_object_name(true)?;
763
764 let operation = if parser.parse_keyword(Keyword::REFRESH) {
766 let subpath = match parser.peek_token().token {
768 Token::SingleQuotedString(s) => {
769 parser.next_token();
770 Some(s)
771 }
772 _ => None,
773 };
774 AlterTableOperation::Refresh { subpath }
775 } else {
776 return parser.expected_ref(
777 "REFRESH after ALTER EXTERNAL TABLE",
778 parser.peek_token_ref(),
779 );
780 };
781
782 let end_token = if parser.peek_token_ref().token == Token::SemiColon {
783 parser.peek_token_ref().clone()
784 } else {
785 parser.get_current_token().clone()
786 };
787
788 Ok(Statement::AlterTable(AlterTable {
789 name: table_name,
790 r#async: false,
791 if_exists,
792 only: false,
793 operations: vec![operation],
794 location: None,
795 on_cluster: None,
796 table_type: Some(AlterTableType::External),
797 end_token: AttachedToken(end_token),
798 }))
799}
800
801fn parse_alter_session(parser: &mut Parser, set: bool) -> Result<Statement, ParserError> {
804 let session_options = parse_session_options(parser, set)?;
805 Ok(Statement::AlterSession {
806 set,
807 session_params: KeyValueOptions {
808 options: session_options,
809 delimiter: KeyValueOptionsDelimiter::Space,
810 },
811 })
812}
813
814#[allow(clippy::too_many_arguments)]
818pub fn parse_create_table(
819 or_replace: bool,
820 global: Option<bool>,
821 temporary: bool,
822 volatile: bool,
823 transient: bool,
824 iceberg: bool,
825 dynamic: bool,
826 parser: &mut Parser,
827) -> Result<CreateTable, ParserError> {
828 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
829 let table_name = parser.parse_object_name(false)?;
830
831 let mut builder = CreateTableBuilder::new(table_name)
832 .or_replace(or_replace)
833 .if_not_exists(if_not_exists)
834 .temporary(temporary)
835 .transient(transient)
836 .volatile(volatile)
837 .iceberg(iceberg)
838 .global(global)
839 .dynamic(dynamic)
840 .hive_formats(None);
841
842 let mut plain_options = vec![];
849
850 loop {
851 let next_token = parser.next_token();
852 match &next_token.token {
853 Token::Word(word) => match word.keyword {
854 Keyword::COPY => {
855 parser.expect_keyword_is(Keyword::GRANTS)?;
856 builder = builder.copy_grants(true);
857 }
858 Keyword::COMMENT => {
859 parser.prev_token();
861 if let Some(comment_def) = parser.parse_optional_inline_comment()? {
862 plain_options.push(SqlOption::Comment(comment_def))
863 }
864 }
865 Keyword::AS => {
866 let query = parser.parse_query()?;
867 builder = builder.query(Some(query));
868 }
869 Keyword::CLONE => {
870 let clone = parser.parse_object_name(false).ok();
871 builder = builder.clone_clause(clone);
872 }
873 Keyword::LIKE => {
874 let name = parser.parse_object_name(false)?;
875 builder = builder.like(Some(CreateTableLikeKind::Plain(
876 crate::ast::CreateTableLike {
877 name,
878 defaults: None,
879 },
880 )));
881 }
882 Keyword::CLUSTER => {
883 parser.expect_keyword_is(Keyword::BY)?;
884 parser.expect_token(&Token::LParen)?;
885 let cluster_by = Some(WrappedCollection::Parentheses(
886 parser.parse_comma_separated(|p| p.parse_expr())?,
887 ));
888 parser.expect_token(&Token::RParen)?;
889
890 builder = builder.cluster_by(cluster_by)
891 }
892 Keyword::ENABLE_SCHEMA_EVOLUTION => {
893 parser.expect_token(&Token::Eq)?;
894 builder = builder.enable_schema_evolution(Some(parser.parse_boolean_string()?));
895 }
896 Keyword::CHANGE_TRACKING => {
897 parser.expect_token(&Token::Eq)?;
898 builder = builder.change_tracking(Some(parser.parse_boolean_string()?));
899 }
900 Keyword::DATA_RETENTION_TIME_IN_DAYS => {
901 parser.expect_token(&Token::Eq)?;
902 let data_retention_time_in_days = parser.parse_literal_uint()?;
903 builder =
904 builder.data_retention_time_in_days(Some(data_retention_time_in_days));
905 }
906 Keyword::MAX_DATA_EXTENSION_TIME_IN_DAYS => {
907 parser.expect_token(&Token::Eq)?;
908 let max_data_extension_time_in_days = parser.parse_literal_uint()?;
909 builder = builder
910 .max_data_extension_time_in_days(Some(max_data_extension_time_in_days));
911 }
912 Keyword::DEFAULT_DDL_COLLATION => {
913 parser.expect_token(&Token::Eq)?;
914 let default_ddl_collation = parser.parse_literal_string()?;
915 builder = builder.default_ddl_collation(Some(default_ddl_collation));
916 }
917 Keyword::WITH => {
920 parser.expect_one_of_keywords(&[
921 Keyword::AGGREGATION,
922 Keyword::STORAGE,
923 Keyword::TAG,
924 Keyword::ROW,
925 ])?;
926 parser.prev_token();
927 }
928 Keyword::AGGREGATION => {
929 parser.expect_keyword_is(Keyword::POLICY)?;
930 let aggregation_policy = parser.parse_object_name(false)?;
931 builder = builder.with_aggregation_policy(Some(aggregation_policy));
932 }
933 Keyword::ROW => {
934 parser.expect_keywords(&[Keyword::ACCESS, Keyword::POLICY])?;
935 let policy = parser.parse_object_name(false)?;
936 parser.expect_keyword_is(Keyword::ON)?;
937 parser.expect_token(&Token::LParen)?;
938 let columns = parser.parse_comma_separated(|p| p.parse_identifier())?;
939 parser.expect_token(&Token::RParen)?;
940
941 builder =
942 builder.with_row_access_policy(Some(RowAccessPolicy::new(policy, columns)))
943 }
944 Keyword::STORAGE => {
945 parser.expect_keywords(&[Keyword::LIFECYCLE, Keyword::POLICY])?;
946 let policy = parser.parse_object_name(false)?;
947 parser.expect_keyword_is(Keyword::ON)?;
948 parser.expect_token(&Token::LParen)?;
949 let columns = parser.parse_comma_separated(|p| p.parse_identifier())?;
950 parser.expect_token(&Token::RParen)?;
951
952 builder = builder.with_storage_lifecycle_policy(Some(StorageLifecyclePolicy {
953 policy,
954 on: columns,
955 }))
956 }
957 Keyword::TAG => {
958 parser.expect_token(&Token::LParen)?;
959 let tags = parser.parse_comma_separated(Parser::parse_tag)?;
960 parser.expect_token(&Token::RParen)?;
961 builder = builder.with_tags(Some(tags));
962 }
963 Keyword::ON if parser.parse_keyword(Keyword::COMMIT) => {
964 let on_commit = Some(parser.parse_create_table_on_commit()?);
965 builder = builder.on_commit(on_commit);
966 }
967 Keyword::EXTERNAL_VOLUME => {
968 parser.expect_token(&Token::Eq)?;
969 builder.external_volume = Some(parser.parse_literal_string()?);
970 }
971 Keyword::CATALOG => {
972 parser.expect_token(&Token::Eq)?;
973 builder.catalog = Some(parser.parse_literal_string()?);
974 }
975 Keyword::BASE_LOCATION => {
976 parser.expect_token(&Token::Eq)?;
977 builder.base_location = Some(parser.parse_literal_string()?);
978 }
979 Keyword::CATALOG_SYNC => {
980 parser.expect_token(&Token::Eq)?;
981 builder.catalog_sync = Some(parser.parse_literal_string()?);
982 }
983 Keyword::STORAGE_SERIALIZATION_POLICY => {
984 parser.expect_token(&Token::Eq)?;
985
986 builder.storage_serialization_policy =
987 Some(parse_storage_serialization_policy(parser)?);
988 }
989 Keyword::IF if parser.parse_keywords(&[Keyword::NOT, Keyword::EXISTS]) => {
990 builder = builder.if_not_exists(true);
991 }
992 Keyword::TARGET_LAG => {
993 parser.expect_token(&Token::Eq)?;
994 let target_lag = parser.parse_literal_string()?;
995 builder = builder.target_lag(Some(target_lag));
996 }
997 Keyword::WAREHOUSE => {
998 parser.expect_token(&Token::Eq)?;
999 let warehouse = parser.parse_identifier()?;
1000 builder = builder.warehouse(Some(warehouse));
1001 }
1002 Keyword::AT | Keyword::BEFORE => {
1003 parser.prev_token();
1004 let version = parser.maybe_parse_table_version()?;
1005 builder = builder.version(version);
1006 }
1007 Keyword::REFRESH_MODE => {
1008 parser.expect_token(&Token::Eq)?;
1009 let refresh_mode = match parser.parse_one_of_keywords(&[
1010 Keyword::AUTO,
1011 Keyword::FULL,
1012 Keyword::INCREMENTAL,
1013 ]) {
1014 Some(Keyword::AUTO) => Some(RefreshModeKind::Auto),
1015 Some(Keyword::FULL) => Some(RefreshModeKind::Full),
1016 Some(Keyword::INCREMENTAL) => Some(RefreshModeKind::Incremental),
1017 _ => return parser.expected("AUTO, FULL or INCREMENTAL", next_token),
1018 };
1019 builder = builder.refresh_mode(refresh_mode);
1020 }
1021 Keyword::INITIALIZE => {
1022 parser.expect_token(&Token::Eq)?;
1023 let initialize = match parser
1024 .parse_one_of_keywords(&[Keyword::ON_CREATE, Keyword::ON_SCHEDULE])
1025 {
1026 Some(Keyword::ON_CREATE) => Some(InitializeKind::OnCreate),
1027 Some(Keyword::ON_SCHEDULE) => Some(InitializeKind::OnSchedule),
1028 _ => return parser.expected("ON_CREATE or ON_SCHEDULE", next_token),
1029 };
1030 builder = builder.initialize(initialize);
1031 }
1032 Keyword::REQUIRE if parser.parse_keyword(Keyword::USER) => {
1033 builder = builder.require_user(true);
1034 }
1035 _ => {
1036 return parser.expected("end of statement", next_token);
1037 }
1038 },
1039 Token::LParen => {
1040 parser.prev_token();
1041 let (columns, constraints) = parser.parse_columns()?;
1042 builder = builder.columns(columns).constraints(constraints);
1043 }
1044 Token::EOF => {
1045 break;
1046 }
1047 Token::SemiColon => {
1048 parser.prev_token();
1049 break;
1050 }
1051 _ => {
1052 return parser.expected("end of statement", next_token);
1053 }
1054 }
1055 }
1056 let table_options = if !plain_options.is_empty() {
1057 crate::ast::CreateTableOptions::Plain(plain_options)
1058 } else {
1059 crate::ast::CreateTableOptions::None
1060 };
1061
1062 builder = builder.table_options(table_options);
1063
1064 if iceberg && builder.base_location.is_none() {
1065 return Err(ParserError::ParserError(
1066 "BASE_LOCATION is required for ICEBERG tables".to_string(),
1067 ));
1068 }
1069
1070 Ok(builder.build())
1071}
1072
1073pub fn parse_create_database(
1076 or_replace: bool,
1077 transient: bool,
1078 parser: &mut Parser,
1079) -> Result<Statement, ParserError> {
1080 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
1081 let name = parser.parse_object_name(false)?;
1082
1083 let mut builder = CreateDatabaseBuilder::new(name)
1084 .or_replace(or_replace)
1085 .transient(transient)
1086 .if_not_exists(if_not_exists);
1087
1088 loop {
1089 let next_token = parser.next_token();
1090 match &next_token.token {
1091 Token::Word(word) => match word.keyword {
1092 Keyword::CLONE => {
1093 builder = builder.clone_clause(Some(parser.parse_object_name(false)?));
1094 }
1095 Keyword::DATA_RETENTION_TIME_IN_DAYS => {
1096 parser.expect_token(&Token::Eq)?;
1097 builder =
1098 builder.data_retention_time_in_days(Some(parser.parse_literal_uint()?));
1099 }
1100 Keyword::MAX_DATA_EXTENSION_TIME_IN_DAYS => {
1101 parser.expect_token(&Token::Eq)?;
1102 builder =
1103 builder.max_data_extension_time_in_days(Some(parser.parse_literal_uint()?));
1104 }
1105 Keyword::EXTERNAL_VOLUME => {
1106 parser.expect_token(&Token::Eq)?;
1107 builder = builder.external_volume(Some(parser.parse_literal_string()?));
1108 }
1109 Keyword::CATALOG => {
1110 parser.expect_token(&Token::Eq)?;
1111 builder = builder.catalog(Some(parser.parse_literal_string()?));
1112 }
1113 Keyword::REPLACE_INVALID_CHARACTERS => {
1114 parser.expect_token(&Token::Eq)?;
1115 builder =
1116 builder.replace_invalid_characters(Some(parser.parse_boolean_string()?));
1117 }
1118 Keyword::DEFAULT_DDL_COLLATION => {
1119 parser.expect_token(&Token::Eq)?;
1120 builder = builder.default_ddl_collation(Some(parser.parse_literal_string()?));
1121 }
1122 Keyword::STORAGE_SERIALIZATION_POLICY => {
1123 parser.expect_token(&Token::Eq)?;
1124 let policy = parse_storage_serialization_policy(parser)?;
1125 builder = builder.storage_serialization_policy(Some(policy));
1126 }
1127 Keyword::COMMENT => {
1128 parser.expect_token(&Token::Eq)?;
1129 builder = builder.comment(Some(parser.parse_literal_string()?));
1130 }
1131 Keyword::CATALOG_SYNC => {
1132 parser.expect_token(&Token::Eq)?;
1133 builder = builder.catalog_sync(Some(parser.parse_literal_string()?));
1134 }
1135 Keyword::CATALOG_SYNC_NAMESPACE_FLATTEN_DELIMITER => {
1136 parser.expect_token(&Token::Eq)?;
1137 builder = builder.catalog_sync_namespace_flatten_delimiter(Some(
1138 parser.parse_literal_string()?,
1139 ));
1140 }
1141 Keyword::CATALOG_SYNC_NAMESPACE_MODE => {
1142 parser.expect_token(&Token::Eq)?;
1143 let mode =
1144 match parser.parse_one_of_keywords(&[Keyword::NEST, Keyword::FLATTEN]) {
1145 Some(Keyword::NEST) => CatalogSyncNamespaceMode::Nest,
1146 Some(Keyword::FLATTEN) => CatalogSyncNamespaceMode::Flatten,
1147 _ => {
1148 return parser.expected("NEST or FLATTEN", next_token);
1149 }
1150 };
1151 builder = builder.catalog_sync_namespace_mode(Some(mode));
1152 }
1153 Keyword::WITH => {
1154 if parser.parse_keyword(Keyword::TAG) {
1155 parser.expect_token(&Token::LParen)?;
1156 let tags = parser.parse_comma_separated(Parser::parse_tag)?;
1157 parser.expect_token(&Token::RParen)?;
1158 builder = builder.with_tags(Some(tags));
1159 } else if parser.parse_keyword(Keyword::CONTACT) {
1160 parser.expect_token(&Token::LParen)?;
1161 let contacts = parser.parse_comma_separated(|p| {
1162 let purpose = p.parse_identifier()?.value;
1163 p.expect_token(&Token::Eq)?;
1164 let contact = p.parse_identifier()?.value;
1165 Ok(ContactEntry { purpose, contact })
1166 })?;
1167 parser.expect_token(&Token::RParen)?;
1168 builder = builder.with_contacts(Some(contacts));
1169 } else {
1170 return parser.expected("TAG or CONTACT", next_token);
1171 }
1172 }
1173 _ => return parser.expected("end of statement", next_token),
1174 },
1175 Token::SemiColon | Token::EOF => break,
1176 _ => return parser.expected("end of statement", next_token),
1177 }
1178 }
1179 Ok(builder.build())
1180}
1181
1182pub fn parse_storage_serialization_policy(
1183 parser: &mut Parser,
1184) -> Result<StorageSerializationPolicy, ParserError> {
1185 let next_token = parser.next_token();
1186 match &next_token.token {
1187 Token::Word(w) => match w.keyword {
1188 Keyword::COMPATIBLE => Ok(StorageSerializationPolicy::Compatible),
1189 Keyword::OPTIMIZED => Ok(StorageSerializationPolicy::Optimized),
1190 _ => parser.expected("storage_serialization_policy", next_token),
1191 },
1192 _ => parser.expected("storage_serialization_policy", next_token),
1193 }
1194}
1195
1196pub fn parse_create_stage(
1197 or_replace: bool,
1198 temporary: bool,
1199 parser: &mut Parser,
1200) -> Result<Statement, ParserError> {
1201 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
1203 let name = parser.parse_object_name(false)?;
1204 let mut directory_table_params = Vec::new();
1205 let mut file_format = Vec::new();
1206 let mut copy_options = Vec::new();
1207 let mut comment = None;
1208
1209 let stage_params = parse_stage_params(parser)?;
1211
1212 if parser.parse_keyword(Keyword::DIRECTORY) {
1214 parser.expect_token(&Token::Eq)?;
1215 directory_table_params = parser.parse_key_value_options(true, &[])?.options;
1216 }
1217
1218 if parser.parse_keyword(Keyword::FILE_FORMAT) {
1220 parser.expect_token(&Token::Eq)?;
1221 file_format = parser.parse_key_value_options(true, &[])?.options;
1222 }
1223
1224 if parser.parse_keyword(Keyword::COPY_OPTIONS) {
1226 parser.expect_token(&Token::Eq)?;
1227 copy_options = parser.parse_key_value_options(true, &[])?.options;
1228 }
1229
1230 if parser.parse_keyword(Keyword::COMMENT) {
1232 parser.expect_token(&Token::Eq)?;
1233 comment = Some(parser.parse_comment_value()?);
1234 }
1235
1236 Ok(Statement::CreateStage {
1237 or_replace,
1238 temporary,
1239 if_not_exists,
1240 name,
1241 stage_params,
1242 directory_table_params: KeyValueOptions {
1243 options: directory_table_params,
1244 delimiter: KeyValueOptionsDelimiter::Space,
1245 },
1246 file_format: KeyValueOptions {
1247 options: file_format,
1248 delimiter: KeyValueOptionsDelimiter::Space,
1249 },
1250 copy_options: KeyValueOptions {
1251 options: copy_options,
1252 delimiter: KeyValueOptionsDelimiter::Space,
1253 },
1254 comment,
1255 })
1256}
1257
1258pub fn parse_stage_name_identifier(parser: &mut Parser) -> Result<Ident, ParserError> {
1259 let mut ident = String::new();
1260 while let Some(next_token) = parser.next_token_no_skip() {
1261 match &next_token.token {
1262 Token::Whitespace(_) | Token::SemiColon => break,
1263 Token::Period => {
1264 parser.prev_token();
1265 break;
1266 }
1267 Token::LParen | Token::RParen => {
1268 parser.prev_token();
1269 break;
1270 }
1271 Token::AtSign => ident.push('@'),
1272 Token::Tilde => ident.push('~'),
1273 Token::Mod => ident.push('%'),
1274 Token::Div => ident.push('/'),
1275 Token::Plus => ident.push('+'),
1276 Token::Minus => ident.push('-'),
1277 Token::Eq => ident.push('='),
1278 Token::Colon => ident.push(':'),
1279 Token::Number(n, _) => ident.push_str(n),
1280 Token::Word(w) => ident.push_str(&w.to_string()),
1281 _ => return parser.expected_ref("stage name identifier", parser.peek_token_ref()),
1282 }
1283 }
1284 Ok(Ident::new(ident))
1285}
1286
1287pub fn parse_snowflake_stage_name(parser: &mut Parser) -> Result<ObjectName, ParserError> {
1290 match parser.next_token().token {
1291 Token::AtSign => {
1292 parser.prev_token();
1293 let mut idents = vec![];
1294 loop {
1295 idents.push(parse_stage_name_identifier(parser)?);
1296 if !parser.consume_token(&Token::Period) {
1297 break;
1298 }
1299 }
1300 Ok(ObjectName::from(idents))
1301 }
1302 _ => {
1303 parser.prev_token();
1304 Ok(parser.parse_object_name(false)?)
1305 }
1306 }
1307}
1308
1309pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
1312 let kind = match &parser.peek_token_ref().token {
1313 Token::AtSign => CopyIntoSnowflakeKind::Location,
1315 Token::SingleQuotedString(s) if s.contains("://") => CopyIntoSnowflakeKind::Location,
1317 _ => CopyIntoSnowflakeKind::Table,
1318 };
1319
1320 let mut files: Vec<String> = vec![];
1321 let mut from_transformations: Option<Vec<StageLoadSelectItemKind>> = None;
1322 let mut from_stage_alias = None;
1323 let mut from_stage = None;
1324 let mut stage_params = StageParamsObject {
1325 url: None,
1326 encryption: KeyValueOptions {
1327 options: vec![],
1328 delimiter: KeyValueOptionsDelimiter::Space,
1329 },
1330 endpoint: None,
1331 storage_integration: None,
1332 credentials: KeyValueOptions {
1333 options: vec![],
1334 delimiter: KeyValueOptionsDelimiter::Space,
1335 },
1336 };
1337 let mut from_query = None;
1338 let mut partition = None;
1339 let mut file_format = Vec::new();
1340 let mut pattern = None;
1341 let mut validation_mode = None;
1342 let mut copy_options = Vec::new();
1343
1344 let into: ObjectName = parse_snowflake_stage_name(parser)?;
1345 if kind == CopyIntoSnowflakeKind::Location {
1346 stage_params = parse_stage_params(parser)?;
1347 }
1348
1349 let into_columns = match &parser.peek_token().token {
1350 Token::LParen => Some(parser.parse_parenthesized_column_list(IsOptional::Optional, true)?),
1351 _ => None,
1352 };
1353
1354 parser.expect_keyword_is(Keyword::FROM)?;
1355 match parser.next_token().token {
1356 Token::LParen if kind == CopyIntoSnowflakeKind::Table => {
1357 parser.expect_keyword_is(Keyword::SELECT)?;
1359 from_transformations = parse_select_items_for_data_load(parser)?;
1360
1361 parser.expect_keyword_is(Keyword::FROM)?;
1362 from_stage = Some(parse_snowflake_stage_name(parser)?);
1363 stage_params = parse_stage_params(parser)?;
1364
1365 from_stage_alias = parser
1367 .maybe_parse_table_alias()?
1368 .map(|table_alias| table_alias.name);
1369 parser.expect_token(&Token::RParen)?;
1370 }
1371 Token::LParen if kind == CopyIntoSnowflakeKind::Location => {
1372 from_query = Some(parser.parse_query()?);
1374 parser.expect_token(&Token::RParen)?;
1375 }
1376 _ => {
1377 parser.prev_token();
1378 from_stage = Some(parse_snowflake_stage_name(parser)?);
1379 stage_params = parse_stage_params(parser)?;
1380
1381 from_stage_alias = if parser.parse_keyword(Keyword::AS) {
1383 Some(match parser.next_token().token {
1384 Token::Word(w) => Ok(Ident::new(w.value)),
1385 _ => parser.expected_ref("stage alias", parser.peek_token_ref()),
1386 }?)
1387 } else {
1388 None
1389 };
1390 }
1391 }
1392
1393 loop {
1394 if parser.parse_keyword(Keyword::FILE_FORMAT) {
1396 parser.expect_token(&Token::Eq)?;
1397 file_format = parser.parse_key_value_options(true, &[])?.options;
1398 } else if parser.parse_keywords(&[Keyword::PARTITION, Keyword::BY]) {
1400 partition = Some(Box::new(parser.parse_expr()?))
1401 } else if parser.parse_keyword(Keyword::FILES) {
1403 parser.expect_token(&Token::Eq)?;
1404 parser.expect_token(&Token::LParen)?;
1405 let mut continue_loop = true;
1406 while continue_loop {
1407 continue_loop = false;
1408 let next_token = parser.next_token();
1409 match next_token.token {
1410 Token::SingleQuotedString(s) => files.push(s),
1411 _ => parser.expected("file token", next_token)?,
1412 };
1413 if parser.next_token().token.eq(&Token::Comma) {
1414 continue_loop = true;
1415 } else {
1416 parser.prev_token(); }
1418 }
1419 parser.expect_token(&Token::RParen)?;
1420 } else if parser.parse_keyword(Keyword::PATTERN) {
1422 parser.expect_token(&Token::Eq)?;
1423 let next_token = parser.next_token();
1424 pattern = Some(match next_token.token {
1425 Token::SingleQuotedString(s) => s,
1426 _ => parser.expected("pattern", next_token)?,
1427 });
1428 } else if parser.parse_keyword(Keyword::VALIDATION_MODE) {
1430 parser.expect_token(&Token::Eq)?;
1431 validation_mode = Some(parser.next_token().token.to_string());
1432 } else if parser.parse_keyword(Keyword::COPY_OPTIONS) {
1434 parser.expect_token(&Token::Eq)?;
1435 copy_options = parser.parse_key_value_options(true, &[])?.options;
1436 } else {
1437 match parser.next_token().token {
1438 Token::SemiColon | Token::EOF => break,
1439 Token::Comma => continue,
1440 Token::Word(key) => copy_options.push(parser.parse_key_value_option(&key)?),
1443 _ => {
1444 return parser
1445 .expected_ref("another copy option, ; or EOF'", parser.peek_token_ref())
1446 }
1447 }
1448 }
1449 }
1450
1451 Ok(Statement::CopyIntoSnowflake {
1452 kind,
1453 into,
1454 into_columns,
1455 from_obj: from_stage,
1456 from_obj_alias: from_stage_alias,
1457 stage_params,
1458 from_transformations,
1459 from_query,
1460 files: if files.is_empty() { None } else { Some(files) },
1461 pattern,
1462 file_format: KeyValueOptions {
1463 options: file_format,
1464 delimiter: KeyValueOptionsDelimiter::Space,
1465 },
1466 copy_options: KeyValueOptions {
1467 options: copy_options,
1468 delimiter: KeyValueOptionsDelimiter::Space,
1469 },
1470 validation_mode,
1471 partition,
1472 })
1473}
1474
1475fn parse_select_items_for_data_load(
1476 parser: &mut Parser,
1477) -> Result<Option<Vec<StageLoadSelectItemKind>>, ParserError> {
1478 let mut select_items: Vec<StageLoadSelectItemKind> = vec![];
1479 loop {
1480 match parser.maybe_parse(parse_select_item_for_data_load)? {
1481 Some(item) => select_items.push(StageLoadSelectItemKind::StageLoadSelectItem(item)),
1483 None => select_items.push(StageLoadSelectItemKind::SelectItem(
1485 parser.parse_select_item()?,
1486 )),
1487 }
1488 if matches!(parser.peek_token_ref().token, Token::Comma) {
1489 parser.advance_token();
1490 } else {
1491 break;
1492 }
1493 }
1494 Ok(Some(select_items))
1495}
1496
1497fn parse_select_item_for_data_load(
1498 parser: &mut Parser,
1499) -> Result<StageLoadSelectItem, ParserError> {
1500 let mut alias: Option<Ident> = None;
1501 let mut file_col_num: i32 = 0;
1502 let mut element: Option<Ident> = None;
1503 let mut item_as: Option<Ident> = None;
1504
1505 let next_token = parser.next_token();
1506 match next_token.token {
1507 Token::Placeholder(w) => {
1508 file_col_num = w.to_string().split_off(1).parse::<i32>().map_err(|e| {
1509 ParserError::ParserError(format!("Could not parse '{w}' as i32: {e}"))
1510 })?;
1511 Ok(())
1512 }
1513 Token::Word(w) => {
1514 alias = Some(Ident::new(w.value));
1515 Ok(())
1516 }
1517 _ => parser.expected("alias or file_col_num", next_token),
1518 }?;
1519
1520 if alias.is_some() {
1521 parser.expect_token(&Token::Period)?;
1522 let col_num_token = parser.next_token();
1524 match col_num_token.token {
1525 Token::Placeholder(w) => {
1526 file_col_num = w.to_string().split_off(1).parse::<i32>().map_err(|e| {
1527 ParserError::ParserError(format!("Could not parse '{w}' as i32: {e}"))
1528 })?;
1529 Ok(())
1530 }
1531 _ => parser.expected("file_col_num", col_num_token),
1532 }?;
1533 }
1534
1535 match parser.next_token().token {
1537 Token::Colon => {
1538 element = Some(Ident::new(match parser.next_token().token {
1540 Token::Word(w) => Ok(w.value),
1541 _ => parser.expected_ref("file_col_num", parser.peek_token_ref()),
1542 }?));
1543 }
1544 _ => {
1545 parser.prev_token();
1547 }
1548 }
1549
1550 if matches!(parser.peek_token_ref().token, Token::DoubleColon) {
1553 return parser.expected("stage load select item", parser.peek_token());
1554 }
1555
1556 if parser.parse_keyword(Keyword::AS) {
1558 item_as = Some(match parser.next_token().token {
1559 Token::Word(w) => Ok(Ident::new(w.value)),
1560 _ => parser.expected_ref("column item alias", parser.peek_token_ref()),
1561 }?);
1562 }
1563
1564 Ok(StageLoadSelectItem {
1565 alias,
1566 file_col_num,
1567 element,
1568 item_as,
1569 })
1570}
1571
1572fn parse_stage_params(parser: &mut Parser) -> Result<StageParamsObject, ParserError> {
1573 let (mut url, mut storage_integration, mut endpoint) = (None, None, None);
1574 let mut encryption: KeyValueOptions = KeyValueOptions {
1575 options: vec![],
1576 delimiter: KeyValueOptionsDelimiter::Space,
1577 };
1578 let mut credentials: KeyValueOptions = KeyValueOptions {
1579 options: vec![],
1580 delimiter: KeyValueOptionsDelimiter::Space,
1581 };
1582
1583 if parser.parse_keyword(Keyword::URL) {
1585 parser.expect_token(&Token::Eq)?;
1586 url = Some(match parser.next_token().token {
1587 Token::SingleQuotedString(word) => Ok(word),
1588 _ => parser.expected_ref("a URL statement", parser.peek_token_ref()),
1589 }?)
1590 }
1591
1592 if parser.parse_keyword(Keyword::STORAGE_INTEGRATION) {
1594 parser.expect_token(&Token::Eq)?;
1595 storage_integration = Some(parser.next_token().token.to_string());
1596 }
1597
1598 if parser.parse_keyword(Keyword::ENDPOINT) {
1600 parser.expect_token(&Token::Eq)?;
1601 endpoint = Some(match parser.next_token().token {
1602 Token::SingleQuotedString(word) => Ok(word),
1603 _ => parser.expected_ref("an endpoint statement", parser.peek_token_ref()),
1604 }?)
1605 }
1606
1607 if parser.parse_keyword(Keyword::CREDENTIALS) {
1609 parser.expect_token(&Token::Eq)?;
1610 credentials = KeyValueOptions {
1611 options: parser.parse_key_value_options(true, &[])?.options,
1612 delimiter: KeyValueOptionsDelimiter::Space,
1613 };
1614 }
1615
1616 if parser.parse_keyword(Keyword::ENCRYPTION) {
1618 parser.expect_token(&Token::Eq)?;
1619 encryption = KeyValueOptions {
1620 options: parser.parse_key_value_options(true, &[])?.options,
1621 delimiter: KeyValueOptionsDelimiter::Space,
1622 };
1623 }
1624
1625 Ok(StageParamsObject {
1626 url,
1627 encryption,
1628 endpoint,
1629 storage_integration,
1630 credentials,
1631 })
1632}
1633
1634fn parse_session_options(
1639 parser: &mut Parser,
1640 set: bool,
1641) -> Result<Vec<KeyValueOption>, ParserError> {
1642 let mut options: Vec<KeyValueOption> = Vec::new();
1643 let empty = String::new;
1644 loop {
1645 let peeked_token = parser.peek_token();
1646 match peeked_token.token {
1647 Token::SemiColon | Token::EOF => break,
1648 Token::Comma => {
1649 parser.advance_token();
1650 continue;
1651 }
1652 Token::Word(key) => {
1653 parser.advance_token();
1654 if set {
1655 let option = parser.parse_key_value_option(&key)?;
1656 options.push(option);
1657 } else {
1658 options.push(KeyValueOption {
1659 option_name: key.value,
1660 option_value: KeyValueOptionKind::Single(
1661 Value::Placeholder(empty()).with_span(Span {
1662 start: peeked_token.span.end,
1663 end: peeked_token.span.end,
1664 }),
1665 ),
1666 });
1667 }
1668 }
1669 _ => {
1670 return parser.expected("another option or end of statement", peeked_token);
1671 }
1672 }
1673 }
1674 if options.is_empty() {
1675 Err(ParserError::ParserError(
1676 "expected at least one option".to_string(),
1677 ))
1678 } else {
1679 Ok(options)
1680 }
1681}
1682
1683fn parse_identity_property(parser: &mut Parser) -> Result<IdentityProperty, ParserError> {
1690 let parameters = if parser.consume_token(&Token::LParen) {
1691 let seed = parser.parse_number()?;
1692 parser.expect_token(&Token::Comma)?;
1693 let increment = parser.parse_number()?;
1694 parser.expect_token(&Token::RParen)?;
1695
1696 Some(IdentityPropertyFormatKind::FunctionCall(
1697 IdentityParameters { seed, increment },
1698 ))
1699 } else if parser.parse_keyword(Keyword::START) {
1700 let seed = parser.parse_number()?;
1701 parser.expect_keyword_is(Keyword::INCREMENT)?;
1702 let increment = parser.parse_number()?;
1703
1704 Some(IdentityPropertyFormatKind::StartAndIncrement(
1705 IdentityParameters { seed, increment },
1706 ))
1707 } else {
1708 None
1709 };
1710 let order = match parser.parse_one_of_keywords(&[Keyword::ORDER, Keyword::NOORDER]) {
1711 Some(Keyword::ORDER) => Some(IdentityPropertyOrder::Order),
1712 Some(Keyword::NOORDER) => Some(IdentityPropertyOrder::NoOrder),
1713 _ => None,
1714 };
1715 Ok(IdentityProperty { parameters, order })
1716}
1717
1718fn parse_column_policy_property(
1725 parser: &mut Parser,
1726 with: bool,
1727) -> Result<ColumnPolicyProperty, ParserError> {
1728 let policy_name = parser.parse_object_name(false)?;
1729 let using_columns = if parser.parse_keyword(Keyword::USING) {
1730 parser.expect_token(&Token::LParen)?;
1731 let columns = parser.parse_comma_separated(|p| p.parse_identifier())?;
1732 parser.expect_token(&Token::RParen)?;
1733 Some(columns)
1734 } else {
1735 None
1736 };
1737
1738 Ok(ColumnPolicyProperty {
1739 with,
1740 policy_name,
1741 using_columns,
1742 })
1743}
1744
1745fn parse_column_tags(parser: &mut Parser, with: bool) -> Result<TagsColumnOption, ParserError> {
1752 parser.expect_token(&Token::LParen)?;
1753 let tags = parser.parse_comma_separated(Parser::parse_tag)?;
1754 parser.expect_token(&Token::RParen)?;
1755
1756 Ok(TagsColumnOption { with, tags })
1757}
1758
1759fn parse_show_objects(terse: bool, parser: &mut Parser) -> Result<Statement, ParserError> {
1762 let show_options = parser.parse_show_stmt_options()?;
1763 Ok(Statement::ShowObjects(ShowObjects {
1764 terse,
1765 show_options,
1766 }))
1767}
1768
1769fn parse_multi_table_insert(
1788 parser: &mut Parser,
1789 insert_token: TokenWithSpan,
1790 overwrite: bool,
1791 multi_table_insert_type: MultiTableInsertType,
1792) -> Result<Statement, ParserError> {
1793 let is_conditional = parser.peek_keyword(Keyword::WHEN);
1795
1796 let (multi_table_into_clauses, multi_table_when_clauses, multi_table_else_clause) =
1797 if is_conditional {
1798 let (when_clauses, else_clause) = parse_multi_table_insert_when_clauses(parser)?;
1800 (vec![], when_clauses, else_clause)
1801 } else {
1802 let into_clauses = parse_multi_table_insert_into_clauses(parser)?;
1804 (into_clauses, vec![], None)
1805 };
1806
1807 let source = parser.parse_query()?;
1809
1810 Ok(Statement::Insert(Insert {
1811 insert_token: insert_token.into(),
1812 optimizer_hints: vec![],
1813 or: None,
1814 ignore: false,
1815 into: false,
1816 table: TableObject::TableName(ObjectName(vec![])), table_alias: None,
1818 columns: vec![],
1819 overwrite,
1820 source: Some(source),
1821 assignments: vec![],
1822 partitioned: None,
1823 after_columns: vec![],
1824 has_table_keyword: false,
1825 on: None,
1826 returning: None,
1827 output: None,
1828 replace_into: false,
1829 priority: None,
1830 insert_alias: None,
1831 settings: None,
1832 format_clause: None,
1833 multi_table_insert_type: Some(multi_table_insert_type),
1834 multi_table_into_clauses,
1835 multi_table_when_clauses,
1836 multi_table_else_clause,
1837 }))
1838}
1839
1840fn parse_multi_table_insert_into_clauses(
1842 parser: &mut Parser,
1843) -> Result<Vec<MultiTableInsertIntoClause>, ParserError> {
1844 let mut into_clauses = vec![];
1845 while parser.parse_keyword(Keyword::INTO) {
1846 into_clauses.push(parse_multi_table_insert_into_clause(parser)?);
1847 }
1848 if into_clauses.is_empty() {
1849 return parser.expected_ref("INTO clause in multi-table INSERT", parser.peek_token_ref());
1850 }
1851 Ok(into_clauses)
1852}
1853
1854fn parse_multi_table_insert_into_clause(
1858 parser: &mut Parser,
1859) -> Result<MultiTableInsertIntoClause, ParserError> {
1860 let table_name = parser.parse_object_name(false)?;
1861
1862 let columns = parser
1864 .maybe_parse(|p| p.parse_parenthesized_column_list(IsOptional::Mandatory, false))?
1865 .unwrap_or_default();
1866
1867 let values = if parser.parse_keyword(Keyword::VALUES) {
1869 parser.expect_token(&Token::LParen)?;
1870 let values = parser.parse_comma_separated(parse_multi_table_insert_value)?;
1871 parser.expect_token(&Token::RParen)?;
1872 Some(MultiTableInsertValues { values })
1873 } else {
1874 None
1875 };
1876
1877 Ok(MultiTableInsertIntoClause {
1878 table_name,
1879 columns,
1880 values,
1881 })
1882}
1883
1884fn parse_multi_table_insert_value(
1886 parser: &mut Parser,
1887) -> Result<MultiTableInsertValue, ParserError> {
1888 if parser.parse_keyword(Keyword::DEFAULT) {
1889 Ok(MultiTableInsertValue::Default)
1890 } else {
1891 Ok(MultiTableInsertValue::Expr(parser.parse_expr()?))
1892 }
1893}
1894
1895fn parse_multi_table_insert_when_clauses(
1897 parser: &mut Parser,
1898) -> Result<
1899 (
1900 Vec<MultiTableInsertWhenClause>,
1901 Option<Vec<MultiTableInsertIntoClause>>,
1902 ),
1903 ParserError,
1904> {
1905 let mut when_clauses = vec![];
1906 let mut else_clause = None;
1907
1908 while parser.parse_keyword(Keyword::WHEN) {
1910 let condition = parser.parse_expr()?;
1911 parser.expect_keyword(Keyword::THEN)?;
1912
1913 let into_clauses = parse_multi_table_insert_into_clauses(parser)?;
1915
1916 when_clauses.push(MultiTableInsertWhenClause {
1917 condition,
1918 into_clauses,
1919 });
1920 }
1921
1922 if parser.parse_keyword(Keyword::ELSE) {
1924 else_clause = Some(parse_multi_table_insert_into_clauses(parser)?);
1925 }
1926
1927 if when_clauses.is_empty() {
1928 return parser.expected_ref(
1929 "at least one WHEN clause in conditional multi-table INSERT",
1930 parser.peek_token_ref(),
1931 );
1932 }
1933
1934 Ok((when_clauses, else_clause))
1935}