1#[cfg(not(feature = "std"))]
19use crate::alloc::string::ToString;
20use crate::ast::helpers::key_value_options::{KeyValueOption, KeyValueOptionType, KeyValueOptions};
21use crate::ast::helpers::stmt_create_table::CreateTableBuilder;
22use crate::ast::helpers::stmt_data_loading::{
23 FileStagingCommand, StageLoadSelectItem, StageLoadSelectItemKind, StageParamsObject,
24};
25use crate::ast::{
26 ColumnOption, ColumnPolicy, ColumnPolicyProperty, CopyIntoSnowflakeKind, DollarQuotedString,
27 Ident, IdentityParameters, IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind,
28 IdentityPropertyOrder, ObjectName, ObjectNamePart, RowAccessPolicy, ShowObjects, SqlOption,
29 Statement, TagsColumnOption, WrappedCollection,
30};
31use crate::dialect::{Dialect, Precedence};
32use crate::keywords::Keyword;
33use crate::parser::{IsOptional, Parser, ParserError};
34use crate::tokenizer::{Token, Word};
35#[cfg(not(feature = "std"))]
36use alloc::boxed::Box;
37#[cfg(not(feature = "std"))]
38use alloc::string::String;
39#[cfg(not(feature = "std"))]
40use alloc::vec::Vec;
41#[cfg(not(feature = "std"))]
42use alloc::{format, vec};
43
44use super::keywords::RESERVED_FOR_IDENTIFIER;
45use sqlparser::ast::StorageSerializationPolicy;
46
47const RESERVED_KEYWORDS_FOR_SELECT_ITEM_OPERATOR: [Keyword; 1] = [Keyword::CONNECT_BY_ROOT];
48#[derive(Debug, Default)]
50pub struct SnowflakeDialect;
51
52impl Dialect for SnowflakeDialect {
53 fn is_identifier_start(&self, ch: char) -> bool {
55 ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch == '_'
56 }
57
58 fn supports_projection_trailing_commas(&self) -> bool {
59 true
60 }
61
62 fn supports_from_trailing_commas(&self) -> bool {
63 true
64 }
65
66 fn supports_object_name_double_dot_notation(&self) -> bool {
71 true
72 }
73
74 fn is_identifier_part(&self, ch: char) -> bool {
75 ch.is_ascii_lowercase()
76 || ch.is_ascii_uppercase()
77 || ch.is_ascii_digit()
78 || ch == '$'
79 || ch == '_'
80 }
81
82 fn supports_string_literal_backslash_escape(&self) -> bool {
84 true
85 }
86
87 fn supports_within_after_array_aggregation(&self) -> bool {
88 true
89 }
90
91 fn supports_outer_join_operator(&self) -> bool {
93 true
94 }
95
96 fn supports_connect_by(&self) -> bool {
97 true
98 }
99
100 fn supports_execute_immediate(&self) -> bool {
102 true
103 }
104
105 fn supports_match_recognize(&self) -> bool {
106 true
107 }
108
109 fn supports_dictionary_syntax(&self) -> bool {
114 true
115 }
116
117 fn supports_window_function_null_treatment_arg(&self) -> bool {
120 true
121 }
122
123 fn supports_parenthesized_set_variables(&self) -> bool {
125 true
126 }
127
128 fn supports_comment_on(&self) -> bool {
130 true
131 }
132
133 fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
134 if parser.parse_keyword(Keyword::BEGIN) {
135 return Some(parser.parse_begin_exception_end());
136 }
137
138 if parser.parse_keywords(&[Keyword::ALTER, Keyword::SESSION]) {
139 let set = match parser.parse_one_of_keywords(&[Keyword::SET, Keyword::UNSET]) {
141 Some(Keyword::SET) => true,
142 Some(Keyword::UNSET) => false,
143 _ => return Some(parser.expected("SET or UNSET", parser.peek_token())),
144 };
145 return Some(parse_alter_session(parser, set));
146 }
147
148 if parser.parse_keyword(Keyword::CREATE) {
149 let or_replace = parser.parse_keywords(&[Keyword::OR, Keyword::REPLACE]);
152 let global = match parser.parse_one_of_keywords(&[Keyword::LOCAL, Keyword::GLOBAL]) {
154 Some(Keyword::LOCAL) => Some(false),
155 Some(Keyword::GLOBAL) => Some(true),
156 _ => None,
157 };
158
159 let mut temporary = false;
160 let mut volatile = false;
161 let mut transient = false;
162 let mut iceberg = false;
163
164 match parser.parse_one_of_keywords(&[
165 Keyword::TEMP,
166 Keyword::TEMPORARY,
167 Keyword::VOLATILE,
168 Keyword::TRANSIENT,
169 Keyword::ICEBERG,
170 ]) {
171 Some(Keyword::TEMP | Keyword::TEMPORARY) => temporary = true,
172 Some(Keyword::VOLATILE) => volatile = true,
173 Some(Keyword::TRANSIENT) => transient = true,
174 Some(Keyword::ICEBERG) => iceberg = true,
175 _ => {}
176 }
177
178 if parser.parse_keyword(Keyword::STAGE) {
179 return Some(parse_create_stage(or_replace, temporary, parser));
181 } else if parser.parse_keyword(Keyword::TABLE) {
182 return Some(parse_create_table(
183 or_replace, global, temporary, volatile, transient, iceberg, parser,
184 ));
185 } else {
186 let mut back = 1;
188 if or_replace {
189 back += 2
190 }
191 if temporary {
192 back += 1
193 }
194 for _i in 0..back {
195 parser.prev_token();
196 }
197 }
198 }
199 if parser.parse_keywords(&[Keyword::COPY, Keyword::INTO]) {
200 return Some(parse_copy_into(parser));
202 }
203
204 if let Some(kw) = parser.parse_one_of_keywords(&[
205 Keyword::LIST,
206 Keyword::LS,
207 Keyword::REMOVE,
208 Keyword::RM,
209 ]) {
210 return Some(parse_file_staging_command(kw, parser));
211 }
212
213 if parser.parse_keyword(Keyword::SHOW) {
214 let terse = parser.parse_keyword(Keyword::TERSE);
215 if parser.parse_keyword(Keyword::OBJECTS) {
216 return Some(parse_show_objects(terse, parser));
217 }
218 if terse {
220 parser.prev_token();
221 }
222 parser.prev_token();
224 }
225
226 None
227 }
228
229 fn parse_column_option(
230 &self,
231 parser: &mut Parser,
232 ) -> Result<Option<Result<Option<ColumnOption>, ParserError>>, ParserError> {
233 parser.maybe_parse(|parser| {
234 let with = parser.parse_keyword(Keyword::WITH);
235
236 if parser.parse_keyword(Keyword::IDENTITY) {
237 Ok(parse_identity_property(parser)
238 .map(|p| Some(ColumnOption::Identity(IdentityPropertyKind::Identity(p)))))
239 } else if parser.parse_keyword(Keyword::AUTOINCREMENT) {
240 Ok(parse_identity_property(parser).map(|p| {
241 Some(ColumnOption::Identity(IdentityPropertyKind::Autoincrement(
242 p,
243 )))
244 }))
245 } else if parser.parse_keywords(&[Keyword::MASKING, Keyword::POLICY]) {
246 Ok(parse_column_policy_property(parser, with)
247 .map(|p| Some(ColumnOption::Policy(ColumnPolicy::MaskingPolicy(p)))))
248 } else if parser.parse_keywords(&[Keyword::PROJECTION, Keyword::POLICY]) {
249 Ok(parse_column_policy_property(parser, with)
250 .map(|p| Some(ColumnOption::Policy(ColumnPolicy::ProjectionPolicy(p)))))
251 } else if parser.parse_keywords(&[Keyword::TAG]) {
252 Ok(parse_column_tags(parser, with).map(|p| Some(ColumnOption::Tags(p))))
253 } else {
254 Err(ParserError::ParserError("not found match".to_string()))
255 }
256 })
257 }
258
259 fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
260 let token = parser.peek_token();
261 match token.token {
263 Token::Colon => Some(Ok(self.prec_value(Precedence::DoubleColon))),
264 _ => None,
265 }
266 }
267
268 fn describe_requires_table_keyword(&self) -> bool {
269 true
270 }
271
272 fn allow_extract_custom(&self) -> bool {
273 true
274 }
275
276 fn allow_extract_single_quotes(&self) -> bool {
277 true
278 }
279
280 fn supports_show_like_before_in(&self) -> bool {
283 true
284 }
285
286 fn supports_left_associative_joins_without_parens(&self) -> bool {
287 false
288 }
289
290 fn is_reserved_for_identifier(&self, kw: Keyword) -> bool {
291 if matches!(kw, Keyword::INTERVAL) {
294 false
295 } else {
296 RESERVED_FOR_IDENTIFIER.contains(&kw)
297 }
298 }
299
300 fn supports_partiql(&self) -> bool {
301 true
302 }
303
304 fn is_column_alias(&self, kw: &Keyword, parser: &mut Parser) -> bool {
305 match kw {
306 Keyword::EXCEPT
310 | Keyword::RETURNING if !matches!(parser.peek_token_ref().token, Token::Comma | Token::EOF) =>
312 {
313 false
314 }
315
316 Keyword::LIMIT | Keyword::OFFSET if peek_for_limit_options(parser) => false,
319
320 Keyword::FETCH if parser.peek_one_of_keywords(&[Keyword::FIRST, Keyword::NEXT]).is_some()
325 || peek_for_limit_options(parser) =>
326 {
327 false
328 }
329
330 Keyword::FROM
334 | Keyword::GROUP
335 | Keyword::HAVING
336 | Keyword::INTERSECT
337 | Keyword::INTO
338 | Keyword::MINUS
339 | Keyword::ORDER
340 | Keyword::SELECT
341 | Keyword::UNION
342 | Keyword::WHERE
343 | Keyword::WITH => false,
344
345 _ => true,
347 }
348 }
349
350 fn is_table_alias(&self, kw: &Keyword, parser: &mut Parser) -> bool {
351 match kw {
352 Keyword::RETURNING
355 | Keyword::INNER
356 | Keyword::USING
357 | Keyword::PIVOT
358 | Keyword::UNPIVOT
359 | Keyword::EXCEPT
360 | Keyword::MATCH_RECOGNIZE
361 if !matches!(parser.peek_token_ref().token, Token::SemiColon | Token::EOF) =>
362 {
363 false
364 }
365
366 Keyword::LIMIT | Keyword::OFFSET if peek_for_limit_options(parser) => false,
370
371 Keyword::FETCH
376 if parser
377 .peek_one_of_keywords(&[Keyword::FIRST, Keyword::NEXT])
378 .is_some()
379 || peek_for_limit_options(parser) =>
380 {
381 false
382 }
383
384 Keyword::RIGHT | Keyword::LEFT | Keyword::SEMI | Keyword::ANTI
387 if parser
388 .peek_one_of_keywords(&[Keyword::JOIN, Keyword::OUTER])
389 .is_some() =>
390 {
391 false
392 }
393
394 Keyword::GLOBAL if parser.peek_keyword(Keyword::FULL) => false,
395
396 Keyword::WITH
400 | Keyword::ORDER
401 | Keyword::SELECT
402 | Keyword::WHERE
403 | Keyword::GROUP
404 | Keyword::HAVING
405 | Keyword::LATERAL
406 | Keyword::UNION
407 | Keyword::INTERSECT
408 | Keyword::MINUS
409 | Keyword::ON
410 | Keyword::JOIN
411 | Keyword::INNER
412 | Keyword::CROSS
413 | Keyword::FULL
414 | Keyword::LEFT
415 | Keyword::RIGHT
416 | Keyword::NATURAL
417 | Keyword::USING
418 | Keyword::ASOF
419 | Keyword::MATCH_CONDITION
420 | Keyword::SET
421 | Keyword::QUALIFY
422 | Keyword::FOR
423 | Keyword::START
424 | Keyword::CONNECT
425 | Keyword::SAMPLE
426 | Keyword::TABLESAMPLE
427 | Keyword::FROM => false,
428
429 _ => true,
431 }
432 }
433
434 fn supports_timestamp_versioning(&self) -> bool {
436 true
437 }
438
439 fn supports_group_by_expr(&self) -> bool {
441 true
442 }
443
444 fn get_reserved_keywords_for_select_item_operator(&self) -> &[Keyword] {
446 &RESERVED_KEYWORDS_FOR_SELECT_ITEM_OPERATOR
447 }
448
449 fn supports_space_separated_column_options(&self) -> bool {
450 true
451 }
452
453 fn supports_comma_separated_drop_column_list(&self) -> bool {
454 true
455 }
456
457 fn is_identifier_generating_function_name(
458 &self,
459 ident: &Ident,
460 name_parts: &[ObjectNamePart],
461 ) -> bool {
462 ident.quote_style.is_none()
463 && ident.value.to_lowercase() == "identifier"
464 && !name_parts
465 .iter()
466 .any(|p| matches!(p, ObjectNamePart::Function(_)))
467 }
468
469 fn supports_select_expr_star(&self) -> bool {
471 true
472 }
473
474 fn supports_select_wildcard_exclude(&self) -> bool {
475 true
476 }
477}
478
479fn peek_for_limit_options(parser: &Parser) -> bool {
482 match &parser.peek_token_ref().token {
483 Token::Number(_, _) | Token::Placeholder(_) => true,
484 Token::SingleQuotedString(val) if val.is_empty() => true,
485 Token::DollarQuotedString(DollarQuotedString { value, .. }) if value.is_empty() => true,
486 Token::Word(w) if w.keyword == Keyword::NULL => true,
487 _ => false,
488 }
489}
490
491fn parse_file_staging_command(kw: Keyword, parser: &mut Parser) -> Result<Statement, ParserError> {
492 let stage = parse_snowflake_stage_name(parser)?;
493 let pattern = if parser.parse_keyword(Keyword::PATTERN) {
494 parser.expect_token(&Token::Eq)?;
495 Some(parser.parse_literal_string()?)
496 } else {
497 None
498 };
499
500 match kw {
501 Keyword::LIST | Keyword::LS => Ok(Statement::List(FileStagingCommand { stage, pattern })),
502 Keyword::REMOVE | Keyword::RM => {
503 Ok(Statement::Remove(FileStagingCommand { stage, pattern }))
504 }
505 _ => Err(ParserError::ParserError(
506 "unexpected stage command, expecting LIST, LS, REMOVE or RM".to_string(),
507 )),
508 }
509}
510
511fn parse_alter_session(parser: &mut Parser, set: bool) -> Result<Statement, ParserError> {
514 let session_options = parse_session_options(parser, set)?;
515 Ok(Statement::AlterSession {
516 set,
517 session_params: KeyValueOptions {
518 options: session_options,
519 },
520 })
521}
522
523pub fn parse_create_table(
527 or_replace: bool,
528 global: Option<bool>,
529 temporary: bool,
530 volatile: bool,
531 transient: bool,
532 iceberg: bool,
533 parser: &mut Parser,
534) -> Result<Statement, ParserError> {
535 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
536 let table_name = parser.parse_object_name(false)?;
537
538 let mut builder = CreateTableBuilder::new(table_name)
539 .or_replace(or_replace)
540 .if_not_exists(if_not_exists)
541 .temporary(temporary)
542 .transient(transient)
543 .volatile(volatile)
544 .iceberg(iceberg)
545 .global(global)
546 .hive_formats(Some(Default::default()));
547
548 let mut plain_options = vec![];
555
556 loop {
557 let next_token = parser.next_token();
558 match &next_token.token {
559 Token::Word(word) => match word.keyword {
560 Keyword::COPY => {
561 parser.expect_keyword_is(Keyword::GRANTS)?;
562 builder = builder.copy_grants(true);
563 }
564 Keyword::COMMENT => {
565 parser.prev_token();
567 if let Some(comment_def) = parser.parse_optional_inline_comment()? {
568 plain_options.push(SqlOption::Comment(comment_def))
569 }
570 }
571 Keyword::AS => {
572 let query = parser.parse_query()?;
573 builder = builder.query(Some(query));
574 }
575 Keyword::CLONE => {
576 let clone = parser.parse_object_name(false).ok();
577 builder = builder.clone_clause(clone);
578 }
579 Keyword::LIKE => {
580 let like = parser.parse_object_name(false).ok();
581 builder = builder.like(like);
582 }
583 Keyword::CLUSTER => {
584 parser.expect_keyword_is(Keyword::BY)?;
585 parser.expect_token(&Token::LParen)?;
586 let cluster_by = Some(WrappedCollection::Parentheses(
587 parser.parse_comma_separated(|p| p.parse_expr())?,
588 ));
589 parser.expect_token(&Token::RParen)?;
590
591 builder = builder.cluster_by(cluster_by)
592 }
593 Keyword::ENABLE_SCHEMA_EVOLUTION => {
594 parser.expect_token(&Token::Eq)?;
595 let enable_schema_evolution =
596 match parser.parse_one_of_keywords(&[Keyword::TRUE, Keyword::FALSE]) {
597 Some(Keyword::TRUE) => true,
598 Some(Keyword::FALSE) => false,
599 _ => {
600 return parser.expected("TRUE or FALSE", next_token);
601 }
602 };
603
604 builder = builder.enable_schema_evolution(Some(enable_schema_evolution));
605 }
606 Keyword::CHANGE_TRACKING => {
607 parser.expect_token(&Token::Eq)?;
608 let change_tracking =
609 match parser.parse_one_of_keywords(&[Keyword::TRUE, Keyword::FALSE]) {
610 Some(Keyword::TRUE) => true,
611 Some(Keyword::FALSE) => false,
612 _ => {
613 return parser.expected("TRUE or FALSE", next_token);
614 }
615 };
616
617 builder = builder.change_tracking(Some(change_tracking));
618 }
619 Keyword::DATA_RETENTION_TIME_IN_DAYS => {
620 parser.expect_token(&Token::Eq)?;
621 let data_retention_time_in_days = parser.parse_literal_uint()?;
622 builder =
623 builder.data_retention_time_in_days(Some(data_retention_time_in_days));
624 }
625 Keyword::MAX_DATA_EXTENSION_TIME_IN_DAYS => {
626 parser.expect_token(&Token::Eq)?;
627 let max_data_extension_time_in_days = parser.parse_literal_uint()?;
628 builder = builder
629 .max_data_extension_time_in_days(Some(max_data_extension_time_in_days));
630 }
631 Keyword::DEFAULT_DDL_COLLATION => {
632 parser.expect_token(&Token::Eq)?;
633 let default_ddl_collation = parser.parse_literal_string()?;
634 builder = builder.default_ddl_collation(Some(default_ddl_collation));
635 }
636 Keyword::WITH => {
639 parser.expect_one_of_keywords(&[
640 Keyword::AGGREGATION,
641 Keyword::TAG,
642 Keyword::ROW,
643 ])?;
644 parser.prev_token();
645 }
646 Keyword::AGGREGATION => {
647 parser.expect_keyword_is(Keyword::POLICY)?;
648 let aggregation_policy = parser.parse_object_name(false)?;
649 builder = builder.with_aggregation_policy(Some(aggregation_policy));
650 }
651 Keyword::ROW => {
652 parser.expect_keywords(&[Keyword::ACCESS, Keyword::POLICY])?;
653 let policy = parser.parse_object_name(false)?;
654 parser.expect_keyword_is(Keyword::ON)?;
655 parser.expect_token(&Token::LParen)?;
656 let columns = parser.parse_comma_separated(|p| p.parse_identifier())?;
657 parser.expect_token(&Token::RParen)?;
658
659 builder =
660 builder.with_row_access_policy(Some(RowAccessPolicy::new(policy, columns)))
661 }
662 Keyword::TAG => {
663 parser.expect_token(&Token::LParen)?;
664 let tags = parser.parse_comma_separated(Parser::parse_tag)?;
665 parser.expect_token(&Token::RParen)?;
666 builder = builder.with_tags(Some(tags));
667 }
668 Keyword::ON if parser.parse_keyword(Keyword::COMMIT) => {
669 let on_commit = Some(parser.parse_create_table_on_commit()?);
670 builder = builder.on_commit(on_commit);
671 }
672 Keyword::EXTERNAL_VOLUME => {
673 parser.expect_token(&Token::Eq)?;
674 builder.external_volume = Some(parser.parse_literal_string()?);
675 }
676 Keyword::CATALOG => {
677 parser.expect_token(&Token::Eq)?;
678 builder.catalog = Some(parser.parse_literal_string()?);
679 }
680 Keyword::BASE_LOCATION => {
681 parser.expect_token(&Token::Eq)?;
682 builder.base_location = Some(parser.parse_literal_string()?);
683 }
684 Keyword::CATALOG_SYNC => {
685 parser.expect_token(&Token::Eq)?;
686 builder.catalog_sync = Some(parser.parse_literal_string()?);
687 }
688 Keyword::STORAGE_SERIALIZATION_POLICY => {
689 parser.expect_token(&Token::Eq)?;
690
691 builder.storage_serialization_policy =
692 Some(parse_storage_serialization_policy(parser)?);
693 }
694 Keyword::IF if parser.parse_keywords(&[Keyword::NOT, Keyword::EXISTS]) => {
695 builder = builder.if_not_exists(true);
696 }
697 _ => {
698 return parser.expected("end of statement", next_token);
699 }
700 },
701 Token::LParen => {
702 parser.prev_token();
703 let (columns, constraints) = parser.parse_columns()?;
704 builder = builder.columns(columns).constraints(constraints);
705 }
706 Token::EOF => {
707 if !builder.validate_schema_info() {
708 return Err(ParserError::ParserError(
709 "unexpected end of input".to_string(),
710 ));
711 }
712
713 break;
714 }
715 Token::SemiColon => {
716 if !builder.validate_schema_info() {
717 return Err(ParserError::ParserError(
718 "unexpected end of input".to_string(),
719 ));
720 }
721
722 parser.prev_token();
723 break;
724 }
725 _ => {
726 return parser.expected("end of statement", next_token);
727 }
728 }
729 }
730 let table_options = if !plain_options.is_empty() {
731 crate::ast::CreateTableOptions::Plain(plain_options)
732 } else {
733 crate::ast::CreateTableOptions::None
734 };
735
736 builder = builder.table_options(table_options);
737
738 if iceberg && builder.base_location.is_none() {
739 return Err(ParserError::ParserError(
740 "BASE_LOCATION is required for ICEBERG tables".to_string(),
741 ));
742 }
743
744 Ok(builder.build())
745}
746
747pub fn parse_storage_serialization_policy(
748 parser: &mut Parser,
749) -> Result<StorageSerializationPolicy, ParserError> {
750 let next_token = parser.next_token();
751 match &next_token.token {
752 Token::Word(w) => match w.keyword {
753 Keyword::COMPATIBLE => Ok(StorageSerializationPolicy::Compatible),
754 Keyword::OPTIMIZED => Ok(StorageSerializationPolicy::Optimized),
755 _ => parser.expected("storage_serialization_policy", next_token),
756 },
757 _ => parser.expected("storage_serialization_policy", next_token),
758 }
759}
760
761pub fn parse_create_stage(
762 or_replace: bool,
763 temporary: bool,
764 parser: &mut Parser,
765) -> Result<Statement, ParserError> {
766 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
768 let name = parser.parse_object_name(false)?;
769 let mut directory_table_params = Vec::new();
770 let mut file_format = Vec::new();
771 let mut copy_options = Vec::new();
772 let mut comment = None;
773
774 let stage_params = parse_stage_params(parser)?;
776
777 if parser.parse_keyword(Keyword::DIRECTORY) {
779 parser.expect_token(&Token::Eq)?;
780 directory_table_params = parse_parentheses_options(parser)?;
781 }
782
783 if parser.parse_keyword(Keyword::FILE_FORMAT) {
785 parser.expect_token(&Token::Eq)?;
786 file_format = parse_parentheses_options(parser)?;
787 }
788
789 if parser.parse_keyword(Keyword::COPY_OPTIONS) {
791 parser.expect_token(&Token::Eq)?;
792 copy_options = parse_parentheses_options(parser)?;
793 }
794
795 if parser.parse_keyword(Keyword::COMMENT) {
797 parser.expect_token(&Token::Eq)?;
798 comment = Some(parser.parse_comment_value()?);
799 }
800
801 Ok(Statement::CreateStage {
802 or_replace,
803 temporary,
804 if_not_exists,
805 name,
806 stage_params,
807 directory_table_params: KeyValueOptions {
808 options: directory_table_params,
809 },
810 file_format: KeyValueOptions {
811 options: file_format,
812 },
813 copy_options: KeyValueOptions {
814 options: copy_options,
815 },
816 comment,
817 })
818}
819
820pub fn parse_stage_name_identifier(parser: &mut Parser) -> Result<Ident, ParserError> {
821 let mut ident = String::new();
822 while let Some(next_token) = parser.next_token_no_skip() {
823 match &next_token.token {
824 Token::Whitespace(_) | Token::SemiColon => break,
825 Token::Period => {
826 parser.prev_token();
827 break;
828 }
829 Token::RParen => {
830 parser.prev_token();
831 break;
832 }
833 Token::AtSign => ident.push('@'),
834 Token::Tilde => ident.push('~'),
835 Token::Mod => ident.push('%'),
836 Token::Div => ident.push('/'),
837 Token::Plus => ident.push('+'),
838 Token::Word(w) => ident.push_str(&w.to_string()),
839 _ => return parser.expected("stage name identifier", parser.peek_token()),
840 }
841 }
842 Ok(Ident::new(ident))
843}
844
845pub fn parse_snowflake_stage_name(parser: &mut Parser) -> Result<ObjectName, ParserError> {
846 match parser.next_token().token {
847 Token::AtSign => {
848 parser.prev_token();
849 let mut idents = vec![];
850 loop {
851 idents.push(parse_stage_name_identifier(parser)?);
852 if !parser.consume_token(&Token::Period) {
853 break;
854 }
855 }
856 Ok(ObjectName::from(idents))
857 }
858 _ => {
859 parser.prev_token();
860 Ok(parser.parse_object_name(false)?)
861 }
862 }
863}
864
865pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
868 let kind = match parser.peek_token().token {
869 Token::AtSign => CopyIntoSnowflakeKind::Location,
871 Token::SingleQuotedString(s) if s.contains("://") => CopyIntoSnowflakeKind::Location,
873 _ => CopyIntoSnowflakeKind::Table,
874 };
875
876 let mut files: Vec<String> = vec![];
877 let mut from_transformations: Option<Vec<StageLoadSelectItemKind>> = None;
878 let mut from_stage_alias = None;
879 let mut from_stage = None;
880 let mut stage_params = StageParamsObject {
881 url: None,
882 encryption: KeyValueOptions { options: vec![] },
883 endpoint: None,
884 storage_integration: None,
885 credentials: KeyValueOptions { options: vec![] },
886 };
887 let mut from_query = None;
888 let mut partition = None;
889 let mut file_format = Vec::new();
890 let mut pattern = None;
891 let mut validation_mode = None;
892 let mut copy_options = Vec::new();
893
894 let into: ObjectName = parse_snowflake_stage_name(parser)?;
895 if kind == CopyIntoSnowflakeKind::Location {
896 stage_params = parse_stage_params(parser)?;
897 }
898
899 let into_columns = match &parser.peek_token().token {
900 Token::LParen => Some(parser.parse_parenthesized_column_list(IsOptional::Optional, true)?),
901 _ => None,
902 };
903
904 parser.expect_keyword_is(Keyword::FROM)?;
905 match parser.next_token().token {
906 Token::LParen if kind == CopyIntoSnowflakeKind::Table => {
907 parser.expect_keyword_is(Keyword::SELECT)?;
909 from_transformations = parse_select_items_for_data_load(parser)?;
910
911 parser.expect_keyword_is(Keyword::FROM)?;
912 from_stage = Some(parse_snowflake_stage_name(parser)?);
913 stage_params = parse_stage_params(parser)?;
914
915 from_stage_alias = parser
917 .maybe_parse_table_alias()?
918 .map(|table_alias| table_alias.name);
919 parser.expect_token(&Token::RParen)?;
920 }
921 Token::LParen if kind == CopyIntoSnowflakeKind::Location => {
922 from_query = Some(parser.parse_query()?);
924 parser.expect_token(&Token::RParen)?;
925 }
926 _ => {
927 parser.prev_token();
928 from_stage = Some(parse_snowflake_stage_name(parser)?);
929 stage_params = parse_stage_params(parser)?;
930
931 from_stage_alias = if parser.parse_keyword(Keyword::AS) {
933 Some(match parser.next_token().token {
934 Token::Word(w) => Ok(Ident::new(w.value)),
935 _ => parser.expected("stage alias", parser.peek_token()),
936 }?)
937 } else {
938 None
939 };
940 }
941 }
942
943 loop {
944 if parser.parse_keyword(Keyword::FILE_FORMAT) {
946 parser.expect_token(&Token::Eq)?;
947 file_format = parse_parentheses_options(parser)?;
948 } else if parser.parse_keywords(&[Keyword::PARTITION, Keyword::BY]) {
950 partition = Some(Box::new(parser.parse_expr()?))
951 } else if parser.parse_keyword(Keyword::FILES) {
953 parser.expect_token(&Token::Eq)?;
954 parser.expect_token(&Token::LParen)?;
955 let mut continue_loop = true;
956 while continue_loop {
957 continue_loop = false;
958 let next_token = parser.next_token();
959 match next_token.token {
960 Token::SingleQuotedString(s) => files.push(s),
961 _ => parser.expected("file token", next_token)?,
962 };
963 if parser.next_token().token.eq(&Token::Comma) {
964 continue_loop = true;
965 } else {
966 parser.prev_token(); }
968 }
969 parser.expect_token(&Token::RParen)?;
970 } else if parser.parse_keyword(Keyword::PATTERN) {
972 parser.expect_token(&Token::Eq)?;
973 let next_token = parser.next_token();
974 pattern = Some(match next_token.token {
975 Token::SingleQuotedString(s) => s,
976 _ => parser.expected("pattern", next_token)?,
977 });
978 } else if parser.parse_keyword(Keyword::VALIDATION_MODE) {
980 parser.expect_token(&Token::Eq)?;
981 validation_mode = Some(parser.next_token().token.to_string());
982 } else if parser.parse_keyword(Keyword::COPY_OPTIONS) {
984 parser.expect_token(&Token::Eq)?;
985 copy_options = parse_parentheses_options(parser)?;
986 } else {
987 match parser.next_token().token {
988 Token::SemiColon | Token::EOF => break,
989 Token::Comma => continue,
990 Token::Word(key) => copy_options.push(parse_option(parser, key)?),
993 _ => return parser.expected("another copy option, ; or EOF'", parser.peek_token()),
994 }
995 }
996 }
997
998 Ok(Statement::CopyIntoSnowflake {
999 kind,
1000 into,
1001 into_columns,
1002 from_obj: from_stage,
1003 from_obj_alias: from_stage_alias,
1004 stage_params,
1005 from_transformations,
1006 from_query,
1007 files: if files.is_empty() { None } else { Some(files) },
1008 pattern,
1009 file_format: KeyValueOptions {
1010 options: file_format,
1011 },
1012 copy_options: KeyValueOptions {
1013 options: copy_options,
1014 },
1015 validation_mode,
1016 partition,
1017 })
1018}
1019
1020fn parse_select_items_for_data_load(
1021 parser: &mut Parser,
1022) -> Result<Option<Vec<StageLoadSelectItemKind>>, ParserError> {
1023 let mut select_items: Vec<StageLoadSelectItemKind> = vec![];
1024 loop {
1025 match parser.maybe_parse(parse_select_item_for_data_load)? {
1026 Some(item) => select_items.push(StageLoadSelectItemKind::StageLoadSelectItem(item)),
1028 None => select_items.push(StageLoadSelectItemKind::SelectItem(
1030 parser.parse_select_item()?,
1031 )),
1032 }
1033 if matches!(parser.peek_token_ref().token, Token::Comma) {
1034 parser.advance_token();
1035 } else {
1036 break;
1037 }
1038 }
1039 Ok(Some(select_items))
1040}
1041
1042fn parse_select_item_for_data_load(
1043 parser: &mut Parser,
1044) -> Result<StageLoadSelectItem, ParserError> {
1045 let mut alias: Option<Ident> = None;
1046 let mut file_col_num: i32 = 0;
1047 let mut element: Option<Ident> = None;
1048 let mut item_as: Option<Ident> = None;
1049
1050 let next_token = parser.next_token();
1051 match next_token.token {
1052 Token::Placeholder(w) => {
1053 file_col_num = w.to_string().split_off(1).parse::<i32>().map_err(|e| {
1054 ParserError::ParserError(format!("Could not parse '{w}' as i32: {e}"))
1055 })?;
1056 Ok(())
1057 }
1058 Token::Word(w) => {
1059 alias = Some(Ident::new(w.value));
1060 Ok(())
1061 }
1062 _ => parser.expected("alias or file_col_num", next_token),
1063 }?;
1064
1065 if alias.is_some() {
1066 parser.expect_token(&Token::Period)?;
1067 let col_num_token = parser.next_token();
1069 match col_num_token.token {
1070 Token::Placeholder(w) => {
1071 file_col_num = w.to_string().split_off(1).parse::<i32>().map_err(|e| {
1072 ParserError::ParserError(format!("Could not parse '{w}' as i32: {e}"))
1073 })?;
1074 Ok(())
1075 }
1076 _ => parser.expected("file_col_num", col_num_token),
1077 }?;
1078 }
1079
1080 match parser.next_token().token {
1082 Token::Colon => {
1083 element = Some(Ident::new(match parser.next_token().token {
1085 Token::Word(w) => Ok(w.value),
1086 _ => parser.expected("file_col_num", parser.peek_token()),
1087 }?));
1088 }
1089 _ => {
1090 parser.prev_token();
1092 }
1093 }
1094
1095 if parser.parse_keyword(Keyword::AS) {
1097 item_as = Some(match parser.next_token().token {
1098 Token::Word(w) => Ok(Ident::new(w.value)),
1099 _ => parser.expected("column item alias", parser.peek_token()),
1100 }?);
1101 }
1102
1103 Ok(StageLoadSelectItem {
1104 alias,
1105 file_col_num,
1106 element,
1107 item_as,
1108 })
1109}
1110
1111fn parse_stage_params(parser: &mut Parser) -> Result<StageParamsObject, ParserError> {
1112 let (mut url, mut storage_integration, mut endpoint) = (None, None, None);
1113 let mut encryption: KeyValueOptions = KeyValueOptions { options: vec![] };
1114 let mut credentials: KeyValueOptions = KeyValueOptions { options: vec![] };
1115
1116 if parser.parse_keyword(Keyword::URL) {
1118 parser.expect_token(&Token::Eq)?;
1119 url = Some(match parser.next_token().token {
1120 Token::SingleQuotedString(word) => Ok(word),
1121 _ => parser.expected("a URL statement", parser.peek_token()),
1122 }?)
1123 }
1124
1125 if parser.parse_keyword(Keyword::STORAGE_INTEGRATION) {
1127 parser.expect_token(&Token::Eq)?;
1128 storage_integration = Some(parser.next_token().token.to_string());
1129 }
1130
1131 if parser.parse_keyword(Keyword::ENDPOINT) {
1133 parser.expect_token(&Token::Eq)?;
1134 endpoint = Some(match parser.next_token().token {
1135 Token::SingleQuotedString(word) => Ok(word),
1136 _ => parser.expected("an endpoint statement", parser.peek_token()),
1137 }?)
1138 }
1139
1140 if parser.parse_keyword(Keyword::CREDENTIALS) {
1142 parser.expect_token(&Token::Eq)?;
1143 credentials = KeyValueOptions {
1144 options: parse_parentheses_options(parser)?,
1145 };
1146 }
1147
1148 if parser.parse_keyword(Keyword::ENCRYPTION) {
1150 parser.expect_token(&Token::Eq)?;
1151 encryption = KeyValueOptions {
1152 options: parse_parentheses_options(parser)?,
1153 };
1154 }
1155
1156 Ok(StageParamsObject {
1157 url,
1158 encryption,
1159 endpoint,
1160 storage_integration,
1161 credentials,
1162 })
1163}
1164
1165fn parse_session_options(
1170 parser: &mut Parser,
1171 set: bool,
1172) -> Result<Vec<KeyValueOption>, ParserError> {
1173 let mut options: Vec<KeyValueOption> = Vec::new();
1174 let empty = String::new;
1175 loop {
1176 let next_token = parser.peek_token();
1177 match next_token.token {
1178 Token::SemiColon | Token::EOF => break,
1179 Token::Comma => {
1180 parser.advance_token();
1181 continue;
1182 }
1183 Token::Word(key) => {
1184 parser.advance_token();
1185 if set {
1186 let option = parse_option(parser, key)?;
1187 options.push(option);
1188 } else {
1189 options.push(KeyValueOption {
1190 option_name: key.value,
1191 option_type: KeyValueOptionType::STRING,
1192 value: empty(),
1193 });
1194 }
1195 }
1196 _ => {
1197 return parser.expected("another option or end of statement", next_token);
1198 }
1199 }
1200 }
1201 if options.is_empty() {
1202 Err(ParserError::ParserError(
1203 "expected at least one option".to_string(),
1204 ))
1205 } else {
1206 Ok(options)
1207 }
1208}
1209
1210fn parse_parentheses_options(parser: &mut Parser) -> Result<Vec<KeyValueOption>, ParserError> {
1217 let mut options: Vec<KeyValueOption> = Vec::new();
1218 parser.expect_token(&Token::LParen)?;
1219 loop {
1220 match parser.next_token().token {
1221 Token::RParen => break,
1222 Token::Comma => continue,
1223 Token::Word(key) => options.push(parse_option(parser, key)?),
1224 _ => return parser.expected("another option or ')'", parser.peek_token()),
1225 };
1226 }
1227 Ok(options)
1228}
1229
1230fn parse_option(parser: &mut Parser, key: Word) -> Result<KeyValueOption, ParserError> {
1232 parser.expect_token(&Token::Eq)?;
1233 if parser.parse_keyword(Keyword::TRUE) {
1234 Ok(KeyValueOption {
1235 option_name: key.value,
1236 option_type: KeyValueOptionType::BOOLEAN,
1237 value: "TRUE".to_string(),
1238 })
1239 } else if parser.parse_keyword(Keyword::FALSE) {
1240 Ok(KeyValueOption {
1241 option_name: key.value,
1242 option_type: KeyValueOptionType::BOOLEAN,
1243 value: "FALSE".to_string(),
1244 })
1245 } else {
1246 match parser.next_token().token {
1247 Token::SingleQuotedString(value) => Ok(KeyValueOption {
1248 option_name: key.value,
1249 option_type: KeyValueOptionType::STRING,
1250 value,
1251 }),
1252 Token::Word(word) => Ok(KeyValueOption {
1253 option_name: key.value,
1254 option_type: KeyValueOptionType::ENUM,
1255 value: word.value,
1256 }),
1257 Token::Number(n, _) => Ok(KeyValueOption {
1258 option_name: key.value,
1259 option_type: KeyValueOptionType::NUMBER,
1260 value: n,
1261 }),
1262 _ => parser.expected("expected option value", parser.peek_token()),
1263 }
1264 }
1265}
1266
1267fn parse_identity_property(parser: &mut Parser) -> Result<IdentityProperty, ParserError> {
1274 let parameters = if parser.consume_token(&Token::LParen) {
1275 let seed = parser.parse_number()?;
1276 parser.expect_token(&Token::Comma)?;
1277 let increment = parser.parse_number()?;
1278 parser.expect_token(&Token::RParen)?;
1279
1280 Some(IdentityPropertyFormatKind::FunctionCall(
1281 IdentityParameters { seed, increment },
1282 ))
1283 } else if parser.parse_keyword(Keyword::START) {
1284 let seed = parser.parse_number()?;
1285 parser.expect_keyword_is(Keyword::INCREMENT)?;
1286 let increment = parser.parse_number()?;
1287
1288 Some(IdentityPropertyFormatKind::StartAndIncrement(
1289 IdentityParameters { seed, increment },
1290 ))
1291 } else {
1292 None
1293 };
1294 let order = match parser.parse_one_of_keywords(&[Keyword::ORDER, Keyword::NOORDER]) {
1295 Some(Keyword::ORDER) => Some(IdentityPropertyOrder::Order),
1296 Some(Keyword::NOORDER) => Some(IdentityPropertyOrder::NoOrder),
1297 _ => None,
1298 };
1299 Ok(IdentityProperty { parameters, order })
1300}
1301
1302fn parse_column_policy_property(
1309 parser: &mut Parser,
1310 with: bool,
1311) -> Result<ColumnPolicyProperty, ParserError> {
1312 let policy_name = parser.parse_object_name(false)?;
1313 let using_columns = if parser.parse_keyword(Keyword::USING) {
1314 parser.expect_token(&Token::LParen)?;
1315 let columns = parser.parse_comma_separated(|p| p.parse_identifier())?;
1316 parser.expect_token(&Token::RParen)?;
1317 Some(columns)
1318 } else {
1319 None
1320 };
1321
1322 Ok(ColumnPolicyProperty {
1323 with,
1324 policy_name,
1325 using_columns,
1326 })
1327}
1328
1329fn parse_column_tags(parser: &mut Parser, with: bool) -> Result<TagsColumnOption, ParserError> {
1336 parser.expect_token(&Token::LParen)?;
1337 let tags = parser.parse_comma_separated(Parser::parse_tag)?;
1338 parser.expect_token(&Token::RParen)?;
1339
1340 Ok(TagsColumnOption { with, tags })
1341}
1342
1343fn parse_show_objects(terse: bool, parser: &mut Parser) -> Result<Statement, ParserError> {
1346 let show_options = parser.parse_show_stmt_options()?;
1347 Ok(Statement::ShowObjects(ShowObjects {
1348 terse,
1349 show_options,
1350 }))
1351}