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 if parser.parse_keywords(&[Keyword::FILE, Keyword::FORMAT]) {
330 return Some(parse_create_file_format(
331 or_replace, temporary, volatile, parser,
332 ));
333 } else {
334 let mut back = 1;
336 if or_replace {
337 back += 2
338 }
339 if temporary {
340 back += 1
341 }
342 for _i in 0..back {
343 parser.prev_token();
344 }
345 }
346 }
347 if parser.parse_keywords(&[Keyword::COPY, Keyword::INTO]) {
348 return Some(parse_copy_into(parser));
350 }
351
352 if let Some(kw) = parser.parse_one_of_keywords(&[
353 Keyword::LIST,
354 Keyword::LS,
355 Keyword::REMOVE,
356 Keyword::RM,
357 ]) {
358 return Some(parse_file_staging_command(kw, parser));
359 }
360
361 if parser.parse_keyword(Keyword::PUT) {
362 return Some(parse_put(parser));
363 }
364
365 if parser.parse_keyword(Keyword::SHOW) {
366 let terse = parser.parse_keyword(Keyword::TERSE);
367 if parser.parse_keyword(Keyword::OBJECTS) {
368 return Some(parse_show_objects(terse, parser));
369 }
370 if terse {
372 parser.prev_token();
373 }
374 parser.prev_token();
376 }
377
378 if parser.parse_keyword(Keyword::INSERT) {
381 let insert_token = parser.get_current_token().clone();
382 let overwrite = parser.parse_keyword(Keyword::OVERWRITE);
383
384 if let Some(kw) = parser.parse_one_of_keywords(&[Keyword::ALL, Keyword::FIRST]) {
386 let multi_table_insert_type = match kw {
387 Keyword::FIRST => MultiTableInsertType::First,
388 _ => MultiTableInsertType::All,
389 };
390 return Some(parse_multi_table_insert(
391 parser,
392 insert_token,
393 overwrite,
394 multi_table_insert_type,
395 ));
396 }
397
398 if overwrite {
400 parser.prev_token(); }
402 parser.prev_token(); }
404
405 None
406 }
407
408 fn parse_column_option(
409 &self,
410 parser: &mut Parser,
411 ) -> Result<Option<Result<Option<ColumnOption>, ParserError>>, ParserError> {
412 parser.maybe_parse(|parser| {
413 let with = parser.parse_keyword(Keyword::WITH);
414
415 if parser.parse_keyword(Keyword::IDENTITY) {
416 Ok(parse_identity_property(parser)
417 .map(|p| Some(ColumnOption::Identity(IdentityPropertyKind::Identity(p)))))
418 } else if parser.parse_keyword(Keyword::AUTOINCREMENT) {
419 Ok(parse_identity_property(parser).map(|p| {
420 Some(ColumnOption::Identity(IdentityPropertyKind::Autoincrement(
421 p,
422 )))
423 }))
424 } else if parser.parse_keywords(&[Keyword::MASKING, Keyword::POLICY]) {
425 Ok(parse_column_policy_property(parser, with)
426 .map(|p| Some(ColumnOption::Policy(ColumnPolicy::MaskingPolicy(p)))))
427 } else if parser.parse_keywords(&[Keyword::PROJECTION, Keyword::POLICY]) {
428 Ok(parse_column_policy_property(parser, with)
429 .map(|p| Some(ColumnOption::Policy(ColumnPolicy::ProjectionPolicy(p)))))
430 } else if parser.parse_keywords(&[Keyword::TAG]) {
431 Ok(parse_column_tags(parser, with).map(|p| Some(ColumnOption::Tags(p))))
432 } else {
433 Err(ParserError::ParserError("not found match".to_string()))
434 }
435 })
436 }
437
438 fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
439 let token = parser.peek_token_ref();
440 match &token.token {
442 Token::Colon => Some(Ok(self.prec_value(Precedence::DoubleColon))),
443 _ => None,
444 }
445 }
446
447 fn describe_requires_table_keyword(&self) -> bool {
448 true
449 }
450
451 fn allow_extract_custom(&self) -> bool {
452 true
453 }
454
455 fn allow_extract_single_quotes(&self) -> bool {
456 true
457 }
458
459 fn supports_show_like_before_in(&self) -> bool {
462 true
463 }
464
465 fn supports_left_associative_joins_without_parens(&self) -> bool {
466 false
467 }
468
469 fn is_reserved_for_identifier(&self, kw: Keyword) -> bool {
470 if matches!(kw, Keyword::INTERVAL) {
473 false
474 } else {
475 RESERVED_FOR_IDENTIFIER.contains(&kw)
476 }
477 }
478
479 fn supports_partiql(&self) -> bool {
480 true
481 }
482
483 fn is_column_alias(&self, kw: &Keyword, parser: &mut Parser) -> bool {
484 match kw {
485 Keyword::EXCEPT
489 | Keyword::RETURNING if !matches!(parser.peek_token_ref().token, Token::Comma | Token::EOF) =>
491 {
492 false
493 }
494
495 Keyword::LIMIT | Keyword::OFFSET if peek_for_limit_options(parser) => false,
498
499 Keyword::FETCH if parser.peek_one_of_keywords(&[Keyword::FIRST, Keyword::NEXT]).is_some()
504 || peek_for_limit_options(parser) =>
505 {
506 false
507 }
508
509 Keyword::FROM
513 | Keyword::GROUP
514 | Keyword::HAVING
515 | Keyword::INTERSECT
516 | Keyword::INTO
517 | Keyword::MINUS
518 | Keyword::ORDER
519 | Keyword::SELECT
520 | Keyword::UNION
521 | Keyword::WHERE
522 | Keyword::WITH => false,
523
524 _ => true,
526 }
527 }
528
529 fn is_table_alias(&self, kw: &Keyword, parser: &mut Parser) -> bool {
530 match kw {
531 Keyword::RETURNING
534 | Keyword::INNER
535 | Keyword::USING
536 | Keyword::PIVOT
537 | Keyword::UNPIVOT
538 | Keyword::EXCEPT
539 | Keyword::MATCH_RECOGNIZE
540 if !matches!(parser.peek_token_ref().token, Token::SemiColon | Token::EOF) =>
541 {
542 false
543 }
544
545 Keyword::LIMIT | Keyword::OFFSET if peek_for_limit_options(parser) => false,
549
550 Keyword::FETCH
555 if parser
556 .peek_one_of_keywords(&[Keyword::FIRST, Keyword::NEXT])
557 .is_some()
558 || peek_for_limit_options(parser) =>
559 {
560 false
561 }
562
563 Keyword::RIGHT | Keyword::LEFT | Keyword::SEMI | Keyword::ANTI
566 if parser
567 .peek_one_of_keywords(&[Keyword::JOIN, Keyword::OUTER])
568 .is_some() =>
569 {
570 false
571 }
572
573 Keyword::GLOBAL if parser.peek_keyword(Keyword::FULL) => false,
574
575 Keyword::WITH
579 | Keyword::ORDER
580 | Keyword::SELECT
581 | Keyword::WHERE
582 | Keyword::GROUP
583 | Keyword::HAVING
584 | Keyword::LATERAL
585 | Keyword::UNION
586 | Keyword::INTERSECT
587 | Keyword::MINUS
588 | Keyword::ON
589 | Keyword::JOIN
590 | Keyword::INNER
591 | Keyword::CROSS
592 | Keyword::FULL
593 | Keyword::LEFT
594 | Keyword::RIGHT
595 | Keyword::NATURAL
596 | Keyword::USING
597 | Keyword::ASOF
598 | Keyword::MATCH_CONDITION
599 | Keyword::SET
600 | Keyword::QUALIFY
601 | Keyword::FOR
602 | Keyword::START
603 | Keyword::CONNECT
604 | Keyword::SAMPLE
605 | Keyword::TABLESAMPLE
606 | Keyword::FROM => false,
607
608 _ => true,
610 }
611 }
612
613 fn is_table_factor(&self, kw: &Keyword, parser: &mut Parser) -> bool {
614 match kw {
615 Keyword::LIMIT if peek_for_limit_options(parser) => false,
616 Keyword::TABLE if matches!(parser.peek_token_ref().token, Token::LParen) => true,
618 _ => !RESERVED_KEYWORDS_FOR_TABLE_FACTOR.contains(kw),
619 }
620 }
621
622 fn supports_table_versioning(&self) -> bool {
624 true
625 }
626
627 fn supports_group_by_expr(&self) -> bool {
629 true
630 }
631
632 fn get_reserved_keywords_for_select_item_operator(&self) -> &[Keyword] {
634 &RESERVED_KEYWORDS_FOR_SELECT_ITEM_OPERATOR
635 }
636
637 fn supports_space_separated_column_options(&self) -> bool {
638 true
639 }
640
641 fn supports_comma_separated_drop_column_list(&self) -> bool {
642 true
643 }
644
645 fn is_identifier_generating_function_name(
646 &self,
647 ident: &Ident,
648 name_parts: &[ObjectNamePart],
649 ) -> bool {
650 ident.quote_style.is_none()
651 && ident.value.to_lowercase() == "identifier"
652 && !name_parts
653 .iter()
654 .any(|p| matches!(p, ObjectNamePart::Function(_)))
655 }
656
657 fn supports_select_expr_star(&self) -> bool {
659 true
660 }
661
662 fn supports_select_wildcard_exclude(&self) -> bool {
663 true
664 }
665
666 fn supports_semantic_view_table_factor(&self) -> bool {
667 true
668 }
669
670 fn supports_select_wildcard_replace(&self) -> bool {
672 true
673 }
674
675 fn supports_select_wildcard_ilike(&self) -> bool {
677 true
678 }
679
680 fn supports_select_wildcard_rename(&self) -> bool {
682 true
683 }
684
685 fn supports_lambda_functions(&self) -> bool {
687 true
688 }
689
690 fn supports_comma_separated_trim(&self) -> bool {
691 true
692 }
693}
694
695fn peek_for_limit_options(parser: &Parser) -> bool {
698 match &parser.peek_token_ref().token {
699 Token::Number(_, _) | Token::Placeholder(_) => true,
700 Token::SingleQuotedString(val) if val.is_empty() => true,
701 Token::DollarQuotedString(DollarQuotedString { value, .. }) if value.is_empty() => true,
702 Token::Word(w) if w.keyword == Keyword::NULL => true,
703 _ => false,
704 }
705}
706
707fn parse_put(parser: &mut Parser) -> Result<Statement, ParserError> {
712 let source = parser.parse_literal_string()?;
713 let stage = parse_snowflake_stage_name(parser)?;
714 let options = parser.parse_key_value_options(false, &[])?;
715 Ok(Statement::Put {
716 source,
717 stage,
718 options,
719 })
720}
721
722fn parse_file_staging_command(kw: Keyword, parser: &mut Parser) -> Result<Statement, ParserError> {
723 let stage = parse_snowflake_stage_name(parser)?;
724 let pattern = if parser.parse_keyword(Keyword::PATTERN) {
725 parser.expect_token(&Token::Eq)?;
726 Some(parser.parse_literal_string()?)
727 } else {
728 None
729 };
730
731 match kw {
732 Keyword::LIST | Keyword::LS => Ok(Statement::List(FileStagingCommand { stage, pattern })),
733 Keyword::REMOVE | Keyword::RM => {
734 Ok(Statement::Remove(FileStagingCommand { stage, pattern }))
735 }
736 _ => Err(ParserError::ParserError(
737 "unexpected stage command, expecting LIST, LS, REMOVE or RM".to_string(),
738 )),
739 }
740}
741
742fn parse_alter_dynamic_table(parser: &mut Parser) -> Result<Statement, ParserError> {
745 let table_name = parser.parse_object_name(true)?;
747
748 let operation = if parser.parse_keyword(Keyword::REFRESH) {
750 AlterTableOperation::Refresh { subpath: None }
751 } else if parser.parse_keyword(Keyword::SUSPEND) {
752 AlterTableOperation::Suspend
753 } else if parser.parse_keyword(Keyword::RESUME) {
754 AlterTableOperation::Resume
755 } else {
756 return parser.expected_ref(
757 "REFRESH, SUSPEND, or RESUME after ALTER DYNAMIC TABLE",
758 parser.peek_token_ref(),
759 );
760 };
761
762 let end_token = if parser.peek_token_ref().token == Token::SemiColon {
763 parser.peek_token_ref().clone()
764 } else {
765 parser.get_current_token().clone()
766 };
767
768 Ok(Statement::AlterTable(AlterTable {
769 name: table_name,
770 if_exists: false,
771 only: false,
772 operations: vec![operation],
773 location: None,
774 on_cluster: None,
775 table_type: Some(AlterTableType::Dynamic),
776 end_token: AttachedToken(end_token),
777 }))
778}
779
780fn parse_alter_external_table(parser: &mut Parser) -> Result<Statement, ParserError> {
783 let if_exists = parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
784 let table_name = parser.parse_object_name(true)?;
785
786 let operation = if parser.parse_keyword(Keyword::REFRESH) {
788 let subpath = match parser.peek_token().token {
790 Token::SingleQuotedString(s) => {
791 parser.next_token();
792 Some(s)
793 }
794 _ => None,
795 };
796 AlterTableOperation::Refresh { subpath }
797 } else {
798 return parser.expected_ref(
799 "REFRESH after ALTER EXTERNAL TABLE",
800 parser.peek_token_ref(),
801 );
802 };
803
804 let end_token = if parser.peek_token_ref().token == Token::SemiColon {
805 parser.peek_token_ref().clone()
806 } else {
807 parser.get_current_token().clone()
808 };
809
810 Ok(Statement::AlterTable(AlterTable {
811 name: table_name,
812 if_exists,
813 only: false,
814 operations: vec![operation],
815 location: None,
816 on_cluster: None,
817 table_type: Some(AlterTableType::External),
818 end_token: AttachedToken(end_token),
819 }))
820}
821
822fn parse_alter_session(parser: &mut Parser, set: bool) -> Result<Statement, ParserError> {
825 let session_options = parse_session_options(parser, set)?;
826 Ok(Statement::AlterSession {
827 set,
828 session_params: KeyValueOptions {
829 options: session_options,
830 delimiter: KeyValueOptionsDelimiter::Space,
831 },
832 })
833}
834
835#[allow(clippy::too_many_arguments)]
839pub fn parse_create_table(
840 or_replace: bool,
841 global: Option<bool>,
842 temporary: bool,
843 volatile: bool,
844 transient: bool,
845 iceberg: bool,
846 dynamic: bool,
847 parser: &mut Parser,
848) -> Result<CreateTable, ParserError> {
849 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
850 let table_name = parser.parse_object_name(false)?;
851
852 let mut builder = CreateTableBuilder::new(table_name)
853 .or_replace(or_replace)
854 .if_not_exists(if_not_exists)
855 .temporary(temporary)
856 .transient(transient)
857 .volatile(volatile)
858 .iceberg(iceberg)
859 .global(global)
860 .dynamic(dynamic)
861 .hive_formats(None);
862
863 let mut plain_options = vec![];
870
871 loop {
872 let next_token = parser.next_token();
873 match &next_token.token {
874 Token::Word(word) => match word.keyword {
875 Keyword::COPY => {
876 parser.expect_keyword_is(Keyword::GRANTS)?;
877 builder = builder.copy_grants(true);
878 }
879 Keyword::COMMENT => {
880 parser.prev_token();
882 if let Some(comment_def) = parser.parse_optional_inline_comment()? {
883 plain_options.push(SqlOption::Comment(comment_def))
884 }
885 }
886 Keyword::AS => {
887 let query = parser.parse_query()?;
888 builder = builder.query(Some(query));
889 }
890 Keyword::CLONE => {
891 let clone = parser.parse_object_name(false).ok();
892 builder = builder.clone_clause(clone);
893 }
894 Keyword::LIKE => {
895 let name = parser.parse_object_name(false)?;
896 builder = builder.like(Some(CreateTableLikeKind::Plain(
897 crate::ast::CreateTableLike {
898 name,
899 defaults: None,
900 },
901 )));
902 }
903 Keyword::CLUSTER => {
904 parser.expect_keyword_is(Keyword::BY)?;
905 parser.expect_token(&Token::LParen)?;
906 let cluster_by = Some(WrappedCollection::Parentheses(
907 parser.parse_comma_separated(|p| p.parse_expr())?,
908 ));
909 parser.expect_token(&Token::RParen)?;
910
911 builder = builder.cluster_by(cluster_by)
912 }
913 Keyword::ENABLE_SCHEMA_EVOLUTION => {
914 parser.expect_token(&Token::Eq)?;
915 builder = builder.enable_schema_evolution(Some(parser.parse_boolean_string()?));
916 }
917 Keyword::CHANGE_TRACKING => {
918 parser.expect_token(&Token::Eq)?;
919 builder = builder.change_tracking(Some(parser.parse_boolean_string()?));
920 }
921 Keyword::DATA_RETENTION_TIME_IN_DAYS => {
922 parser.expect_token(&Token::Eq)?;
923 let data_retention_time_in_days = parser.parse_literal_uint()?;
924 builder =
925 builder.data_retention_time_in_days(Some(data_retention_time_in_days));
926 }
927 Keyword::MAX_DATA_EXTENSION_TIME_IN_DAYS => {
928 parser.expect_token(&Token::Eq)?;
929 let max_data_extension_time_in_days = parser.parse_literal_uint()?;
930 builder = builder
931 .max_data_extension_time_in_days(Some(max_data_extension_time_in_days));
932 }
933 Keyword::DEFAULT_DDL_COLLATION => {
934 parser.expect_token(&Token::Eq)?;
935 let default_ddl_collation = parser.parse_literal_string()?;
936 builder = builder.default_ddl_collation(Some(default_ddl_collation));
937 }
938 Keyword::WITH => {
941 parser.expect_one_of_keywords(&[
942 Keyword::AGGREGATION,
943 Keyword::STORAGE,
944 Keyword::TAG,
945 Keyword::ROW,
946 ])?;
947 parser.prev_token();
948 }
949 Keyword::AGGREGATION => {
950 parser.expect_keyword_is(Keyword::POLICY)?;
951 let aggregation_policy = parser.parse_object_name(false)?;
952 builder = builder.with_aggregation_policy(Some(aggregation_policy));
953 }
954 Keyword::ROW => {
955 parser.expect_keywords(&[Keyword::ACCESS, Keyword::POLICY])?;
956 let policy = parser.parse_object_name(false)?;
957 parser.expect_keyword_is(Keyword::ON)?;
958 parser.expect_token(&Token::LParen)?;
959 let columns = parser.parse_comma_separated(|p| p.parse_identifier())?;
960 parser.expect_token(&Token::RParen)?;
961
962 builder =
963 builder.with_row_access_policy(Some(RowAccessPolicy::new(policy, columns)))
964 }
965 Keyword::STORAGE => {
966 parser.expect_keywords(&[Keyword::LIFECYCLE, Keyword::POLICY])?;
967 let policy = parser.parse_object_name(false)?;
968 parser.expect_keyword_is(Keyword::ON)?;
969 parser.expect_token(&Token::LParen)?;
970 let columns = parser.parse_comma_separated(|p| p.parse_identifier())?;
971 parser.expect_token(&Token::RParen)?;
972
973 builder = builder.with_storage_lifecycle_policy(Some(StorageLifecyclePolicy {
974 policy,
975 on: columns,
976 }))
977 }
978 Keyword::TAG => {
979 parser.expect_token(&Token::LParen)?;
980 let tags = parser.parse_comma_separated(Parser::parse_tag)?;
981 parser.expect_token(&Token::RParen)?;
982 builder = builder.with_tags(Some(tags));
983 }
984 Keyword::ON if parser.parse_keyword(Keyword::COMMIT) => {
985 let on_commit = Some(parser.parse_create_table_on_commit()?);
986 builder = builder.on_commit(on_commit);
987 }
988 Keyword::EXTERNAL_VOLUME => {
989 parser.expect_token(&Token::Eq)?;
990 builder.external_volume = Some(parser.parse_literal_string()?);
991 }
992 Keyword::CATALOG => {
993 parser.expect_token(&Token::Eq)?;
994 builder.catalog = Some(parser.parse_literal_string()?);
995 }
996 Keyword::BASE_LOCATION => {
997 parser.expect_token(&Token::Eq)?;
998 builder.base_location = Some(parser.parse_literal_string()?);
999 }
1000 Keyword::CATALOG_SYNC => {
1001 parser.expect_token(&Token::Eq)?;
1002 builder.catalog_sync = Some(parser.parse_literal_string()?);
1003 }
1004 Keyword::STORAGE_SERIALIZATION_POLICY => {
1005 parser.expect_token(&Token::Eq)?;
1006
1007 builder.storage_serialization_policy =
1008 Some(parse_storage_serialization_policy(parser)?);
1009 }
1010 Keyword::IF if parser.parse_keywords(&[Keyword::NOT, Keyword::EXISTS]) => {
1011 builder = builder.if_not_exists(true);
1012 }
1013 Keyword::TARGET_LAG => {
1014 parser.expect_token(&Token::Eq)?;
1015 let target_lag = parser.parse_literal_string()?;
1016 builder = builder.target_lag(Some(target_lag));
1017 }
1018 Keyword::WAREHOUSE => {
1019 parser.expect_token(&Token::Eq)?;
1020 let warehouse = parser.parse_identifier()?;
1021 builder = builder.warehouse(Some(warehouse));
1022 }
1023 Keyword::AT | Keyword::BEFORE => {
1024 parser.prev_token();
1025 let version = parser.maybe_parse_table_version()?;
1026 builder = builder.version(version);
1027 }
1028 Keyword::REFRESH_MODE => {
1029 parser.expect_token(&Token::Eq)?;
1030 let refresh_mode = match parser.parse_one_of_keywords(&[
1031 Keyword::AUTO,
1032 Keyword::FULL,
1033 Keyword::INCREMENTAL,
1034 ]) {
1035 Some(Keyword::AUTO) => Some(RefreshModeKind::Auto),
1036 Some(Keyword::FULL) => Some(RefreshModeKind::Full),
1037 Some(Keyword::INCREMENTAL) => Some(RefreshModeKind::Incremental),
1038 _ => return parser.expected("AUTO, FULL or INCREMENTAL", next_token),
1039 };
1040 builder = builder.refresh_mode(refresh_mode);
1041 }
1042 Keyword::INITIALIZE => {
1043 parser.expect_token(&Token::Eq)?;
1044 let initialize = match parser
1045 .parse_one_of_keywords(&[Keyword::ON_CREATE, Keyword::ON_SCHEDULE])
1046 {
1047 Some(Keyword::ON_CREATE) => Some(InitializeKind::OnCreate),
1048 Some(Keyword::ON_SCHEDULE) => Some(InitializeKind::OnSchedule),
1049 _ => return parser.expected("ON_CREATE or ON_SCHEDULE", next_token),
1050 };
1051 builder = builder.initialize(initialize);
1052 }
1053 Keyword::REQUIRE if parser.parse_keyword(Keyword::USER) => {
1054 builder = builder.require_user(true);
1055 }
1056 _ => {
1057 return parser.expected("end of statement", next_token);
1058 }
1059 },
1060 Token::LParen => {
1061 parser.prev_token();
1062 let (columns, constraints) = parser.parse_columns()?;
1063 builder = builder.columns(columns).constraints(constraints);
1064 }
1065 Token::EOF => {
1066 break;
1067 }
1068 Token::SemiColon => {
1069 parser.prev_token();
1070 break;
1071 }
1072 _ => {
1073 return parser.expected("end of statement", next_token);
1074 }
1075 }
1076 }
1077 let table_options = if !plain_options.is_empty() {
1078 crate::ast::CreateTableOptions::Plain(plain_options)
1079 } else {
1080 crate::ast::CreateTableOptions::None
1081 };
1082
1083 builder = builder.table_options(table_options);
1084
1085 if iceberg && builder.base_location.is_none() {
1086 return Err(ParserError::ParserError(
1087 "BASE_LOCATION is required for ICEBERG tables".to_string(),
1088 ));
1089 }
1090
1091 Ok(builder.build())
1092}
1093
1094pub fn parse_create_database(
1097 or_replace: bool,
1098 transient: bool,
1099 parser: &mut Parser,
1100) -> Result<Statement, ParserError> {
1101 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
1102 let name = parser.parse_object_name(false)?;
1103
1104 let mut builder = CreateDatabaseBuilder::new(name)
1105 .or_replace(or_replace)
1106 .transient(transient)
1107 .if_not_exists(if_not_exists);
1108
1109 loop {
1110 let next_token = parser.next_token();
1111 match &next_token.token {
1112 Token::Word(word) => match word.keyword {
1113 Keyword::CLONE => {
1114 builder = builder.clone_clause(Some(parser.parse_object_name(false)?));
1115 }
1116 Keyword::DATA_RETENTION_TIME_IN_DAYS => {
1117 parser.expect_token(&Token::Eq)?;
1118 builder =
1119 builder.data_retention_time_in_days(Some(parser.parse_literal_uint()?));
1120 }
1121 Keyword::MAX_DATA_EXTENSION_TIME_IN_DAYS => {
1122 parser.expect_token(&Token::Eq)?;
1123 builder =
1124 builder.max_data_extension_time_in_days(Some(parser.parse_literal_uint()?));
1125 }
1126 Keyword::EXTERNAL_VOLUME => {
1127 parser.expect_token(&Token::Eq)?;
1128 builder = builder.external_volume(Some(parser.parse_literal_string()?));
1129 }
1130 Keyword::CATALOG => {
1131 parser.expect_token(&Token::Eq)?;
1132 builder = builder.catalog(Some(parser.parse_literal_string()?));
1133 }
1134 Keyword::REPLACE_INVALID_CHARACTERS => {
1135 parser.expect_token(&Token::Eq)?;
1136 builder =
1137 builder.replace_invalid_characters(Some(parser.parse_boolean_string()?));
1138 }
1139 Keyword::DEFAULT_DDL_COLLATION => {
1140 parser.expect_token(&Token::Eq)?;
1141 builder = builder.default_ddl_collation(Some(parser.parse_literal_string()?));
1142 }
1143 Keyword::STORAGE_SERIALIZATION_POLICY => {
1144 parser.expect_token(&Token::Eq)?;
1145 let policy = parse_storage_serialization_policy(parser)?;
1146 builder = builder.storage_serialization_policy(Some(policy));
1147 }
1148 Keyword::COMMENT => {
1149 parser.expect_token(&Token::Eq)?;
1150 builder = builder.comment(Some(parser.parse_literal_string()?));
1151 }
1152 Keyword::CATALOG_SYNC => {
1153 parser.expect_token(&Token::Eq)?;
1154 builder = builder.catalog_sync(Some(parser.parse_literal_string()?));
1155 }
1156 Keyword::CATALOG_SYNC_NAMESPACE_FLATTEN_DELIMITER => {
1157 parser.expect_token(&Token::Eq)?;
1158 builder = builder.catalog_sync_namespace_flatten_delimiter(Some(
1159 parser.parse_literal_string()?,
1160 ));
1161 }
1162 Keyword::CATALOG_SYNC_NAMESPACE_MODE => {
1163 parser.expect_token(&Token::Eq)?;
1164 let mode =
1165 match parser.parse_one_of_keywords(&[Keyword::NEST, Keyword::FLATTEN]) {
1166 Some(Keyword::NEST) => CatalogSyncNamespaceMode::Nest,
1167 Some(Keyword::FLATTEN) => CatalogSyncNamespaceMode::Flatten,
1168 _ => {
1169 return parser.expected("NEST or FLATTEN", next_token);
1170 }
1171 };
1172 builder = builder.catalog_sync_namespace_mode(Some(mode));
1173 }
1174 Keyword::WITH => {
1175 if parser.parse_keyword(Keyword::TAG) {
1176 parser.expect_token(&Token::LParen)?;
1177 let tags = parser.parse_comma_separated(Parser::parse_tag)?;
1178 parser.expect_token(&Token::RParen)?;
1179 builder = builder.with_tags(Some(tags));
1180 } else if parser.parse_keyword(Keyword::CONTACT) {
1181 parser.expect_token(&Token::LParen)?;
1182 let contacts = parser.parse_comma_separated(|p| {
1183 let purpose = p.parse_identifier()?.value;
1184 p.expect_token(&Token::Eq)?;
1185 let contact = p.parse_identifier()?.value;
1186 Ok(ContactEntry { purpose, contact })
1187 })?;
1188 parser.expect_token(&Token::RParen)?;
1189 builder = builder.with_contacts(Some(contacts));
1190 } else {
1191 return parser.expected("TAG or CONTACT", next_token);
1192 }
1193 }
1194 _ => return parser.expected("end of statement", next_token),
1195 },
1196 Token::SemiColon | Token::EOF => break,
1197 _ => return parser.expected("end of statement", next_token),
1198 }
1199 }
1200 Ok(builder.build())
1201}
1202
1203pub fn parse_storage_serialization_policy(
1204 parser: &mut Parser,
1205) -> Result<StorageSerializationPolicy, ParserError> {
1206 let next_token = parser.next_token();
1207 match &next_token.token {
1208 Token::Word(w) => match w.keyword {
1209 Keyword::COMPATIBLE => Ok(StorageSerializationPolicy::Compatible),
1210 Keyword::OPTIMIZED => Ok(StorageSerializationPolicy::Optimized),
1211 _ => parser.expected("storage_serialization_policy", next_token),
1212 },
1213 _ => parser.expected("storage_serialization_policy", next_token),
1214 }
1215}
1216
1217pub fn parse_create_stage(
1218 or_replace: bool,
1219 temporary: bool,
1220 parser: &mut Parser,
1221) -> Result<Statement, ParserError> {
1222 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
1224 let name = parser.parse_object_name(false)?;
1225 let mut directory_table_params = Vec::new();
1226 let mut file_format = Vec::new();
1227 let mut copy_options = Vec::new();
1228 let mut comment = None;
1229
1230 let stage_params = parse_stage_params(parser)?;
1232
1233 if parser.parse_keyword(Keyword::DIRECTORY) {
1235 parser.expect_token(&Token::Eq)?;
1236 directory_table_params = parser.parse_key_value_options(true, &[])?.options;
1237 }
1238
1239 if parser.parse_keyword(Keyword::FILE_FORMAT) {
1241 parser.expect_token(&Token::Eq)?;
1242 file_format = parser.parse_key_value_options(true, &[])?.options;
1243 }
1244
1245 if parser.parse_keyword(Keyword::COPY_OPTIONS) {
1247 parser.expect_token(&Token::Eq)?;
1248 copy_options = parser.parse_key_value_options(true, &[])?.options;
1249 }
1250
1251 if parser.parse_keyword(Keyword::COMMENT) {
1253 parser.expect_token(&Token::Eq)?;
1254 comment = Some(parser.parse_comment_value()?);
1255 }
1256
1257 Ok(Statement::CreateStage {
1258 or_replace,
1259 temporary,
1260 if_not_exists,
1261 name,
1262 stage_params,
1263 directory_table_params: KeyValueOptions {
1264 options: directory_table_params,
1265 delimiter: KeyValueOptionsDelimiter::Space,
1266 },
1267 file_format: KeyValueOptions {
1268 options: file_format,
1269 delimiter: KeyValueOptionsDelimiter::Space,
1270 },
1271 copy_options: KeyValueOptions {
1272 options: copy_options,
1273 delimiter: KeyValueOptionsDelimiter::Space,
1274 },
1275 comment,
1276 })
1277}
1278
1279pub fn parse_create_file_format(
1282 or_replace: bool,
1283 temporary: bool,
1284 volatile: bool,
1285 parser: &mut Parser,
1286) -> Result<Statement, ParserError> {
1287 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
1288 let name = parser.parse_object_name(true)?;
1289 let options = parser.parse_key_value_options(false, &[Keyword::COMMENT])?;
1290 let comment = if parser.parse_keyword(Keyword::COMMENT) {
1291 parser.expect_token(&Token::Eq)?;
1292 Some(parser.parse_comment_value()?)
1293 } else {
1294 None
1295 };
1296
1297 Ok(Statement::CreateFileFormat {
1298 or_replace,
1299 temporary,
1300 volatile,
1301 if_not_exists,
1302 name,
1303 options,
1304 comment,
1305 })
1306}
1307
1308pub fn parse_stage_name_identifier(parser: &mut Parser) -> Result<Ident, ParserError> {
1309 let mut ident = String::new();
1310 while let Some(next_token) = parser.next_token_no_skip() {
1311 match &next_token.token {
1312 Token::Whitespace(_) | Token::SemiColon => break,
1313 Token::Period => {
1314 parser.prev_token();
1315 break;
1316 }
1317 Token::LParen | Token::RParen => {
1318 parser.prev_token();
1319 break;
1320 }
1321 Token::AtSign => ident.push('@'),
1322 Token::Tilde => ident.push('~'),
1323 Token::Mod => ident.push('%'),
1324 Token::Div => ident.push('/'),
1325 Token::Plus => ident.push('+'),
1326 Token::Minus => ident.push('-'),
1327 Token::Eq => ident.push('='),
1328 Token::Colon => ident.push(':'),
1329 Token::Number(n, _) => ident.push_str(n),
1330 Token::Word(w) => ident.push_str(&w.to_string()),
1331 _ => return parser.expected_ref("stage name identifier", parser.peek_token_ref()),
1332 }
1333 }
1334 Ok(Ident::new(ident))
1335}
1336
1337pub fn parse_snowflake_stage_name(parser: &mut Parser) -> Result<ObjectName, ParserError> {
1340 match parser.next_token().token {
1341 Token::AtSign => {
1342 parser.prev_token();
1343 let mut idents = vec![];
1344 loop {
1345 idents.push(parse_stage_name_identifier(parser)?);
1346 if !parser.consume_token(&Token::Period) {
1347 break;
1348 }
1349 }
1350 Ok(ObjectName::from(idents))
1351 }
1352 _ => {
1353 parser.prev_token();
1354 Ok(parser.parse_object_name(false)?)
1355 }
1356 }
1357}
1358
1359pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
1362 let kind = match &parser.peek_token_ref().token {
1363 Token::AtSign => CopyIntoSnowflakeKind::Location,
1365 Token::SingleQuotedString(s) if s.contains("://") => CopyIntoSnowflakeKind::Location,
1367 _ => CopyIntoSnowflakeKind::Table,
1368 };
1369
1370 let mut files: Vec<String> = vec![];
1371 let mut from_transformations: Option<Vec<StageLoadSelectItemKind>> = None;
1372 let mut from_stage_alias = None;
1373 let mut from_stage = None;
1374 let mut stage_params = StageParamsObject {
1375 url: None,
1376 encryption: KeyValueOptions {
1377 options: vec![],
1378 delimiter: KeyValueOptionsDelimiter::Space,
1379 },
1380 endpoint: None,
1381 storage_integration: None,
1382 credentials: KeyValueOptions {
1383 options: vec![],
1384 delimiter: KeyValueOptionsDelimiter::Space,
1385 },
1386 };
1387 let mut from_query = None;
1388 let mut partition = None;
1389 let mut file_format = Vec::new();
1390 let mut pattern = None;
1391 let mut validation_mode = None;
1392 let mut copy_options = Vec::new();
1393
1394 let into: ObjectName = parse_snowflake_stage_name(parser)?;
1395 if kind == CopyIntoSnowflakeKind::Location {
1396 stage_params = parse_stage_params(parser)?;
1397 }
1398
1399 let into_columns = match &parser.peek_token().token {
1400 Token::LParen => Some(parser.parse_parenthesized_column_list(IsOptional::Optional, true)?),
1401 _ => None,
1402 };
1403
1404 parser.expect_keyword_is(Keyword::FROM)?;
1405 match parser.next_token().token {
1406 Token::LParen if kind == CopyIntoSnowflakeKind::Table => {
1407 parser.expect_keyword_is(Keyword::SELECT)?;
1409 from_transformations = parse_select_items_for_data_load(parser)?;
1410
1411 parser.expect_keyword_is(Keyword::FROM)?;
1412 from_stage = Some(parse_snowflake_stage_name(parser)?);
1413 stage_params = parse_stage_params(parser)?;
1414
1415 from_stage_alias = parser
1417 .maybe_parse_table_alias()?
1418 .map(|table_alias| table_alias.name);
1419 parser.expect_token(&Token::RParen)?;
1420 }
1421 Token::LParen if kind == CopyIntoSnowflakeKind::Location => {
1422 from_query = Some(parser.parse_query()?);
1424 parser.expect_token(&Token::RParen)?;
1425 }
1426 _ => {
1427 parser.prev_token();
1428 from_stage = Some(parse_snowflake_stage_name(parser)?);
1429 stage_params = parse_stage_params(parser)?;
1430
1431 from_stage_alias = if parser.parse_keyword(Keyword::AS) {
1433 Some(match parser.next_token().token {
1434 Token::Word(w) => Ok(Ident::new(w.value)),
1435 _ => parser.expected_ref("stage alias", parser.peek_token_ref()),
1436 }?)
1437 } else {
1438 None
1439 };
1440 }
1441 }
1442
1443 loop {
1444 if parser.parse_keyword(Keyword::FILE_FORMAT) {
1446 parser.expect_token(&Token::Eq)?;
1447 file_format = parser.parse_key_value_options(true, &[])?.options;
1448 } else if parser.parse_keywords(&[Keyword::PARTITION, Keyword::BY]) {
1450 partition = Some(Box::new(parser.parse_expr()?))
1451 } else if parser.parse_keyword(Keyword::FILES) {
1453 parser.expect_token(&Token::Eq)?;
1454 parser.expect_token(&Token::LParen)?;
1455 let mut continue_loop = true;
1456 while continue_loop {
1457 continue_loop = false;
1458 let next_token = parser.next_token();
1459 match next_token.token {
1460 Token::SingleQuotedString(s) => files.push(s),
1461 _ => parser.expected("file token", next_token)?,
1462 };
1463 if parser.next_token().token.eq(&Token::Comma) {
1464 continue_loop = true;
1465 } else {
1466 parser.prev_token(); }
1468 }
1469 parser.expect_token(&Token::RParen)?;
1470 } else if parser.parse_keyword(Keyword::PATTERN) {
1472 parser.expect_token(&Token::Eq)?;
1473 let next_token = parser.next_token();
1474 pattern = Some(match next_token.token {
1475 Token::SingleQuotedString(s) => s,
1476 _ => parser.expected("pattern", next_token)?,
1477 });
1478 } else if parser.parse_keyword(Keyword::VALIDATION_MODE) {
1480 parser.expect_token(&Token::Eq)?;
1481 validation_mode = Some(parser.next_token().token.to_string());
1482 } else if parser.parse_keyword(Keyword::COPY_OPTIONS) {
1484 parser.expect_token(&Token::Eq)?;
1485 copy_options = parser.parse_key_value_options(true, &[])?.options;
1486 } else {
1487 match parser.next_token().token {
1488 Token::SemiColon | Token::EOF => break,
1489 Token::Comma => continue,
1490 Token::Word(key) => copy_options.push(parser.parse_key_value_option(&key)?),
1493 _ => {
1494 return parser
1495 .expected_ref("another copy option, ; or EOF'", parser.peek_token_ref())
1496 }
1497 }
1498 }
1499 }
1500
1501 Ok(Statement::CopyIntoSnowflake {
1502 kind,
1503 into,
1504 into_columns,
1505 from_obj: from_stage,
1506 from_obj_alias: from_stage_alias,
1507 stage_params,
1508 from_transformations,
1509 from_query,
1510 files: if files.is_empty() { None } else { Some(files) },
1511 pattern,
1512 file_format: KeyValueOptions {
1513 options: file_format,
1514 delimiter: KeyValueOptionsDelimiter::Space,
1515 },
1516 copy_options: KeyValueOptions {
1517 options: copy_options,
1518 delimiter: KeyValueOptionsDelimiter::Space,
1519 },
1520 validation_mode,
1521 partition,
1522 })
1523}
1524
1525fn parse_select_items_for_data_load(
1526 parser: &mut Parser,
1527) -> Result<Option<Vec<StageLoadSelectItemKind>>, ParserError> {
1528 let mut select_items: Vec<StageLoadSelectItemKind> = vec![];
1529 loop {
1530 match parser.maybe_parse(parse_select_item_for_data_load)? {
1531 Some(item) => select_items.push(StageLoadSelectItemKind::StageLoadSelectItem(item)),
1533 None => select_items.push(StageLoadSelectItemKind::SelectItem(
1535 parser.parse_select_item()?,
1536 )),
1537 }
1538 if matches!(parser.peek_token_ref().token, Token::Comma) {
1539 parser.advance_token();
1540 } else {
1541 break;
1542 }
1543 }
1544 Ok(Some(select_items))
1545}
1546
1547fn parse_select_item_for_data_load(
1548 parser: &mut Parser,
1549) -> Result<StageLoadSelectItem, ParserError> {
1550 let mut alias: Option<Ident> = None;
1551 let mut file_col_num: i32 = 0;
1552 let mut element: Option<Ident> = None;
1553 let mut item_as: Option<Ident> = None;
1554
1555 let next_token = parser.next_token();
1556 match next_token.token {
1557 Token::Placeholder(w) => {
1558 file_col_num = w.to_string().split_off(1).parse::<i32>().map_err(|e| {
1559 ParserError::ParserError(format!("Could not parse '{w}' as i32: {e}"))
1560 })?;
1561 Ok(())
1562 }
1563 Token::Word(w) => {
1564 alias = Some(Ident::new(w.value));
1565 Ok(())
1566 }
1567 _ => parser.expected("alias or file_col_num", next_token),
1568 }?;
1569
1570 if alias.is_some() {
1571 parser.expect_token(&Token::Period)?;
1572 let col_num_token = parser.next_token();
1574 match col_num_token.token {
1575 Token::Placeholder(w) => {
1576 file_col_num = w.to_string().split_off(1).parse::<i32>().map_err(|e| {
1577 ParserError::ParserError(format!("Could not parse '{w}' as i32: {e}"))
1578 })?;
1579 Ok(())
1580 }
1581 _ => parser.expected("file_col_num", col_num_token),
1582 }?;
1583 }
1584
1585 match parser.next_token().token {
1587 Token::Colon => {
1588 element = Some(Ident::new(match parser.next_token().token {
1590 Token::Word(w) => Ok(w.value),
1591 _ => parser.expected_ref("file_col_num", parser.peek_token_ref()),
1592 }?));
1593 }
1594 _ => {
1595 parser.prev_token();
1597 }
1598 }
1599
1600 if matches!(parser.peek_token_ref().token, Token::DoubleColon) {
1603 return parser.expected("stage load select item", parser.peek_token());
1604 }
1605
1606 if parser.parse_keyword(Keyword::AS) {
1608 item_as = Some(match parser.next_token().token {
1609 Token::Word(w) => Ok(Ident::new(w.value)),
1610 _ => parser.expected_ref("column item alias", parser.peek_token_ref()),
1611 }?);
1612 }
1613
1614 Ok(StageLoadSelectItem {
1615 alias,
1616 file_col_num,
1617 element,
1618 item_as,
1619 })
1620}
1621
1622fn parse_stage_params(parser: &mut Parser) -> Result<StageParamsObject, ParserError> {
1623 let (mut url, mut storage_integration, mut endpoint) = (None, None, None);
1624 let mut encryption: KeyValueOptions = KeyValueOptions {
1625 options: vec![],
1626 delimiter: KeyValueOptionsDelimiter::Space,
1627 };
1628 let mut credentials: KeyValueOptions = KeyValueOptions {
1629 options: vec![],
1630 delimiter: KeyValueOptionsDelimiter::Space,
1631 };
1632
1633 if parser.parse_keyword(Keyword::URL) {
1635 parser.expect_token(&Token::Eq)?;
1636 url = Some(match parser.next_token().token {
1637 Token::SingleQuotedString(word) => Ok(word),
1638 _ => parser.expected_ref("a URL statement", parser.peek_token_ref()),
1639 }?)
1640 }
1641
1642 if parser.parse_keyword(Keyword::STORAGE_INTEGRATION) {
1644 parser.expect_token(&Token::Eq)?;
1645 storage_integration = Some(parser.next_token().token.to_string());
1646 }
1647
1648 if parser.parse_keyword(Keyword::ENDPOINT) {
1650 parser.expect_token(&Token::Eq)?;
1651 endpoint = Some(match parser.next_token().token {
1652 Token::SingleQuotedString(word) => Ok(word),
1653 _ => parser.expected_ref("an endpoint statement", parser.peek_token_ref()),
1654 }?)
1655 }
1656
1657 if parser.parse_keyword(Keyword::CREDENTIALS) {
1659 parser.expect_token(&Token::Eq)?;
1660 credentials = KeyValueOptions {
1661 options: parser.parse_key_value_options(true, &[])?.options,
1662 delimiter: KeyValueOptionsDelimiter::Space,
1663 };
1664 }
1665
1666 if parser.parse_keyword(Keyword::ENCRYPTION) {
1668 parser.expect_token(&Token::Eq)?;
1669 encryption = KeyValueOptions {
1670 options: parser.parse_key_value_options(true, &[])?.options,
1671 delimiter: KeyValueOptionsDelimiter::Space,
1672 };
1673 }
1674
1675 Ok(StageParamsObject {
1676 url,
1677 encryption,
1678 endpoint,
1679 storage_integration,
1680 credentials,
1681 })
1682}
1683
1684fn parse_session_options(
1689 parser: &mut Parser,
1690 set: bool,
1691) -> Result<Vec<KeyValueOption>, ParserError> {
1692 let mut options: Vec<KeyValueOption> = Vec::new();
1693 let empty = String::new;
1694 loop {
1695 let peeked_token = parser.peek_token();
1696 match peeked_token.token {
1697 Token::SemiColon | Token::EOF => break,
1698 Token::Comma => {
1699 parser.advance_token();
1700 continue;
1701 }
1702 Token::Word(key) => {
1703 parser.advance_token();
1704 if set {
1705 let option = parser.parse_key_value_option(&key)?;
1706 options.push(option);
1707 } else {
1708 options.push(KeyValueOption {
1709 option_name: key.value,
1710 option_value: KeyValueOptionKind::Single(
1711 Value::Placeholder(empty()).with_span(Span {
1712 start: peeked_token.span.end,
1713 end: peeked_token.span.end,
1714 }),
1715 ),
1716 });
1717 }
1718 }
1719 _ => {
1720 return parser.expected("another option or end of statement", peeked_token);
1721 }
1722 }
1723 }
1724 if options.is_empty() {
1725 Err(ParserError::ParserError(
1726 "expected at least one option".to_string(),
1727 ))
1728 } else {
1729 Ok(options)
1730 }
1731}
1732
1733fn parse_identity_property(parser: &mut Parser) -> Result<IdentityProperty, ParserError> {
1740 let parameters = if parser.consume_token(&Token::LParen) {
1741 let seed = parser.parse_number()?;
1742 parser.expect_token(&Token::Comma)?;
1743 let increment = parser.parse_number()?;
1744 parser.expect_token(&Token::RParen)?;
1745
1746 Some(IdentityPropertyFormatKind::FunctionCall(
1747 IdentityParameters { seed, increment },
1748 ))
1749 } else if parser.parse_keyword(Keyword::START) {
1750 let seed = parser.parse_number()?;
1751 parser.expect_keyword_is(Keyword::INCREMENT)?;
1752 let increment = parser.parse_number()?;
1753
1754 Some(IdentityPropertyFormatKind::StartAndIncrement(
1755 IdentityParameters { seed, increment },
1756 ))
1757 } else {
1758 None
1759 };
1760 let order = match parser.parse_one_of_keywords(&[Keyword::ORDER, Keyword::NOORDER]) {
1761 Some(Keyword::ORDER) => Some(IdentityPropertyOrder::Order),
1762 Some(Keyword::NOORDER) => Some(IdentityPropertyOrder::NoOrder),
1763 _ => None,
1764 };
1765 Ok(IdentityProperty { parameters, order })
1766}
1767
1768fn parse_column_policy_property(
1775 parser: &mut Parser,
1776 with: bool,
1777) -> Result<ColumnPolicyProperty, ParserError> {
1778 let policy_name = parser.parse_object_name(false)?;
1779 let using_columns = if parser.parse_keyword(Keyword::USING) {
1780 parser.expect_token(&Token::LParen)?;
1781 let columns = parser.parse_comma_separated(|p| p.parse_identifier())?;
1782 parser.expect_token(&Token::RParen)?;
1783 Some(columns)
1784 } else {
1785 None
1786 };
1787
1788 Ok(ColumnPolicyProperty {
1789 with,
1790 policy_name,
1791 using_columns,
1792 })
1793}
1794
1795fn parse_column_tags(parser: &mut Parser, with: bool) -> Result<TagsColumnOption, ParserError> {
1802 parser.expect_token(&Token::LParen)?;
1803 let tags = parser.parse_comma_separated(Parser::parse_tag)?;
1804 parser.expect_token(&Token::RParen)?;
1805
1806 Ok(TagsColumnOption { with, tags })
1807}
1808
1809fn parse_show_objects(terse: bool, parser: &mut Parser) -> Result<Statement, ParserError> {
1812 let show_options = parser.parse_show_stmt_options()?;
1813 Ok(Statement::ShowObjects(ShowObjects {
1814 terse,
1815 show_options,
1816 }))
1817}
1818
1819fn parse_multi_table_insert(
1838 parser: &mut Parser,
1839 insert_token: TokenWithSpan,
1840 overwrite: bool,
1841 multi_table_insert_type: MultiTableInsertType,
1842) -> Result<Statement, ParserError> {
1843 let is_conditional = parser.peek_keyword(Keyword::WHEN);
1845
1846 let (multi_table_into_clauses, multi_table_when_clauses, multi_table_else_clause) =
1847 if is_conditional {
1848 let (when_clauses, else_clause) = parse_multi_table_insert_when_clauses(parser)?;
1850 (vec![], when_clauses, else_clause)
1851 } else {
1852 let into_clauses = parse_multi_table_insert_into_clauses(parser)?;
1854 (into_clauses, vec![], None)
1855 };
1856
1857 let source = parser.parse_query()?;
1859
1860 Ok(Statement::Insert(Insert {
1861 insert_token: insert_token.into(),
1862 optimizer_hints: vec![],
1863 or: None,
1864 ignore: false,
1865 into: false,
1866 table: TableObject::TableName(ObjectName(vec![])), table_alias: None,
1868 columns: vec![],
1869 overwrite,
1870 source: Some(source),
1871 assignments: vec![],
1872 partitioned: None,
1873 after_columns: vec![],
1874 has_table_keyword: false,
1875 on: None,
1876 returning: None,
1877 output: None,
1878 replace_into: false,
1879 priority: None,
1880 insert_alias: None,
1881 settings: None,
1882 format_clause: None,
1883 multi_table_insert_type: Some(multi_table_insert_type),
1884 multi_table_into_clauses,
1885 multi_table_when_clauses,
1886 multi_table_else_clause,
1887 }))
1888}
1889
1890fn parse_multi_table_insert_into_clauses(
1892 parser: &mut Parser,
1893) -> Result<Vec<MultiTableInsertIntoClause>, ParserError> {
1894 let mut into_clauses = vec![];
1895 while parser.parse_keyword(Keyword::INTO) {
1896 into_clauses.push(parse_multi_table_insert_into_clause(parser)?);
1897 }
1898 if into_clauses.is_empty() {
1899 return parser.expected_ref("INTO clause in multi-table INSERT", parser.peek_token_ref());
1900 }
1901 Ok(into_clauses)
1902}
1903
1904fn parse_multi_table_insert_into_clause(
1908 parser: &mut Parser,
1909) -> Result<MultiTableInsertIntoClause, ParserError> {
1910 let table_name = parser.parse_object_name(false)?;
1911
1912 let columns = parser
1914 .maybe_parse(|p| p.parse_parenthesized_column_list(IsOptional::Mandatory, false))?
1915 .unwrap_or_default();
1916
1917 let values = if parser.parse_keyword(Keyword::VALUES) {
1919 parser.expect_token(&Token::LParen)?;
1920 let values = parser.parse_comma_separated(parse_multi_table_insert_value)?;
1921 parser.expect_token(&Token::RParen)?;
1922 Some(MultiTableInsertValues { values })
1923 } else {
1924 None
1925 };
1926
1927 Ok(MultiTableInsertIntoClause {
1928 table_name,
1929 columns,
1930 values,
1931 })
1932}
1933
1934fn parse_multi_table_insert_value(
1936 parser: &mut Parser,
1937) -> Result<MultiTableInsertValue, ParserError> {
1938 if parser.parse_keyword(Keyword::DEFAULT) {
1939 Ok(MultiTableInsertValue::Default)
1940 } else {
1941 Ok(MultiTableInsertValue::Expr(parser.parse_expr()?))
1942 }
1943}
1944
1945fn parse_multi_table_insert_when_clauses(
1947 parser: &mut Parser,
1948) -> Result<
1949 (
1950 Vec<MultiTableInsertWhenClause>,
1951 Option<Vec<MultiTableInsertIntoClause>>,
1952 ),
1953 ParserError,
1954> {
1955 let mut when_clauses = vec![];
1956 let mut else_clause = None;
1957
1958 while parser.parse_keyword(Keyword::WHEN) {
1960 let condition = parser.parse_expr()?;
1961 parser.expect_keyword(Keyword::THEN)?;
1962
1963 let into_clauses = parse_multi_table_insert_into_clauses(parser)?;
1965
1966 when_clauses.push(MultiTableInsertWhenClause {
1967 condition,
1968 into_clauses,
1969 });
1970 }
1971
1972 if parser.parse_keyword(Keyword::ELSE) {
1974 else_clause = Some(parse_multi_table_insert_into_clauses(parser)?);
1975 }
1976
1977 if when_clauses.is_empty() {
1978 return parser.expected_ref(
1979 "at least one WHEN clause in conditional multi-table INSERT",
1980 parser.peek_token_ref(),
1981 );
1982 }
1983
1984 Ok((when_clauses, else_clause))
1985}