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, StageParamsObject,
24};
25use crate::ast::{
26 ColumnOption, ColumnPolicy, ColumnPolicyProperty, CopyIntoSnowflakeKind, Ident,
27 IdentityParameters, IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind,
28 IdentityPropertyOrder, ObjectName, RowAccessPolicy, ShowObjects, Statement, TagsColumnOption,
29 WrappedCollection,
30};
31use crate::dialect::{Dialect, Precedence};
32use crate::keywords::Keyword;
33use crate::parser::{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
47#[derive(Debug, Default)]
49pub struct SnowflakeDialect;
50
51impl Dialect for SnowflakeDialect {
52 fn is_identifier_start(&self, ch: char) -> bool {
54 ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch == '_'
55 }
56
57 fn supports_projection_trailing_commas(&self) -> bool {
58 true
59 }
60
61 fn supports_from_trailing_commas(&self) -> bool {
62 true
63 }
64
65 fn supports_object_name_double_dot_notation(&self) -> bool {
70 true
71 }
72
73 fn is_identifier_part(&self, ch: char) -> bool {
74 ch.is_ascii_lowercase()
75 || ch.is_ascii_uppercase()
76 || ch.is_ascii_digit()
77 || ch == '$'
78 || ch == '_'
79 }
80
81 fn supports_string_literal_backslash_escape(&self) -> bool {
83 true
84 }
85
86 fn supports_within_after_array_aggregation(&self) -> bool {
87 true
88 }
89
90 fn supports_outer_join_operator(&self) -> bool {
92 true
93 }
94
95 fn supports_connect_by(&self) -> bool {
96 true
97 }
98
99 fn supports_execute_immediate(&self) -> bool {
101 true
102 }
103
104 fn supports_match_recognize(&self) -> bool {
105 true
106 }
107
108 fn supports_dictionary_syntax(&self) -> bool {
113 true
114 }
115
116 fn supports_window_function_null_treatment_arg(&self) -> bool {
119 true
120 }
121
122 fn supports_parenthesized_set_variables(&self) -> bool {
124 true
125 }
126
127 fn supports_comment_on(&self) -> bool {
129 true
130 }
131
132 fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
133 if parser.parse_keywords(&[Keyword::ALTER, Keyword::SESSION]) {
134 let set = match parser.parse_one_of_keywords(&[Keyword::SET, Keyword::UNSET]) {
136 Some(Keyword::SET) => true,
137 Some(Keyword::UNSET) => false,
138 _ => return Some(parser.expected("SET or UNSET", parser.peek_token())),
139 };
140 return Some(parse_alter_session(parser, set));
141 }
142
143 if parser.parse_keyword(Keyword::CREATE) {
144 let or_replace = parser.parse_keywords(&[Keyword::OR, Keyword::REPLACE]);
147 let global = match parser.parse_one_of_keywords(&[Keyword::LOCAL, Keyword::GLOBAL]) {
149 Some(Keyword::LOCAL) => Some(false),
150 Some(Keyword::GLOBAL) => Some(true),
151 _ => None,
152 };
153
154 let mut temporary = false;
155 let mut volatile = false;
156 let mut transient = false;
157 let mut iceberg = false;
158
159 match parser.parse_one_of_keywords(&[
160 Keyword::TEMP,
161 Keyword::TEMPORARY,
162 Keyword::VOLATILE,
163 Keyword::TRANSIENT,
164 Keyword::ICEBERG,
165 ]) {
166 Some(Keyword::TEMP | Keyword::TEMPORARY) => temporary = true,
167 Some(Keyword::VOLATILE) => volatile = true,
168 Some(Keyword::TRANSIENT) => transient = true,
169 Some(Keyword::ICEBERG) => iceberg = true,
170 _ => {}
171 }
172
173 if parser.parse_keyword(Keyword::STAGE) {
174 return Some(parse_create_stage(or_replace, temporary, parser));
176 } else if parser.parse_keyword(Keyword::TABLE) {
177 return Some(parse_create_table(
178 or_replace, global, temporary, volatile, transient, iceberg, parser,
179 ));
180 } else {
181 let mut back = 1;
183 if or_replace {
184 back += 2
185 }
186 if temporary {
187 back += 1
188 }
189 for _i in 0..back {
190 parser.prev_token();
191 }
192 }
193 }
194 if parser.parse_keywords(&[Keyword::COPY, Keyword::INTO]) {
195 return Some(parse_copy_into(parser));
197 }
198
199 if let Some(kw) = parser.parse_one_of_keywords(&[
200 Keyword::LIST,
201 Keyword::LS,
202 Keyword::REMOVE,
203 Keyword::RM,
204 ]) {
205 return Some(parse_file_staging_command(kw, parser));
206 }
207
208 if parser.parse_keyword(Keyword::SHOW) {
209 let terse = parser.parse_keyword(Keyword::TERSE);
210 if parser.parse_keyword(Keyword::OBJECTS) {
211 return Some(parse_show_objects(terse, parser));
212 }
213 if terse {
215 parser.prev_token();
216 }
217 parser.prev_token();
219 }
220
221 None
222 }
223
224 fn parse_column_option(
225 &self,
226 parser: &mut Parser,
227 ) -> Result<Option<Result<Option<ColumnOption>, ParserError>>, ParserError> {
228 parser.maybe_parse(|parser| {
229 let with = parser.parse_keyword(Keyword::WITH);
230
231 if parser.parse_keyword(Keyword::IDENTITY) {
232 Ok(parse_identity_property(parser)
233 .map(|p| Some(ColumnOption::Identity(IdentityPropertyKind::Identity(p)))))
234 } else if parser.parse_keyword(Keyword::AUTOINCREMENT) {
235 Ok(parse_identity_property(parser).map(|p| {
236 Some(ColumnOption::Identity(IdentityPropertyKind::Autoincrement(
237 p,
238 )))
239 }))
240 } else if parser.parse_keywords(&[Keyword::MASKING, Keyword::POLICY]) {
241 Ok(parse_column_policy_property(parser, with)
242 .map(|p| Some(ColumnOption::Policy(ColumnPolicy::MaskingPolicy(p)))))
243 } else if parser.parse_keywords(&[Keyword::PROJECTION, Keyword::POLICY]) {
244 Ok(parse_column_policy_property(parser, with)
245 .map(|p| Some(ColumnOption::Policy(ColumnPolicy::ProjectionPolicy(p)))))
246 } else if parser.parse_keywords(&[Keyword::TAG]) {
247 Ok(parse_column_tags(parser, with).map(|p| Some(ColumnOption::Tags(p))))
248 } else {
249 Err(ParserError::ParserError("not found match".to_string()))
250 }
251 })
252 }
253
254 fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
255 let token = parser.peek_token();
256 match token.token {
258 Token::Colon => Some(Ok(self.prec_value(Precedence::DoubleColon))),
259 _ => None,
260 }
261 }
262
263 fn describe_requires_table_keyword(&self) -> bool {
264 true
265 }
266
267 fn allow_extract_custom(&self) -> bool {
268 true
269 }
270
271 fn allow_extract_single_quotes(&self) -> bool {
272 true
273 }
274
275 fn supports_show_like_before_in(&self) -> bool {
278 true
279 }
280
281 fn is_reserved_for_identifier(&self, kw: Keyword) -> bool {
282 if matches!(kw, Keyword::INTERVAL) {
285 false
286 } else {
287 RESERVED_FOR_IDENTIFIER.contains(&kw)
288 }
289 }
290
291 fn supports_partiql(&self) -> bool {
292 true
293 }
294
295 fn is_select_item_alias(&self, explicit: bool, kw: &Keyword, parser: &mut Parser) -> bool {
296 explicit
297 || match kw {
298 Keyword::EXCEPT
302 | Keyword::LIMIT
304 | Keyword::OFFSET
306 | Keyword::RETURNING if !matches!(parser.peek_token_ref().token, Token::Comma | Token::EOF) =>
308 {
309 false
310 }
311
312 Keyword::FETCH
315 if parser.peek_keyword(Keyword::FIRST) || parser.peek_keyword(Keyword::NEXT) =>
316 {
317 false
318 }
319
320 Keyword::FROM
324 | Keyword::GROUP
325 | Keyword::HAVING
326 | Keyword::INTERSECT
327 | Keyword::INTO
328 | Keyword::MINUS
329 | Keyword::ORDER
330 | Keyword::SELECT
331 | Keyword::UNION
332 | Keyword::WHERE
333 | Keyword::WITH => false,
334
335 _ => true,
337 }
338 }
339
340 fn supports_timestamp_versioning(&self) -> bool {
342 true
343 }
344
345 fn supports_group_by_expr(&self) -> bool {
347 true
348 }
349}
350
351fn parse_file_staging_command(kw: Keyword, parser: &mut Parser) -> Result<Statement, ParserError> {
352 let stage = parse_snowflake_stage_name(parser)?;
353 let pattern = if parser.parse_keyword(Keyword::PATTERN) {
354 parser.expect_token(&Token::Eq)?;
355 Some(parser.parse_literal_string()?)
356 } else {
357 None
358 };
359
360 match kw {
361 Keyword::LIST | Keyword::LS => Ok(Statement::List(FileStagingCommand { stage, pattern })),
362 Keyword::REMOVE | Keyword::RM => {
363 Ok(Statement::Remove(FileStagingCommand { stage, pattern }))
364 }
365 _ => Err(ParserError::ParserError(
366 "unexpected stage command, expecting LIST, LS, REMOVE or RM".to_string(),
367 )),
368 }
369}
370
371fn parse_alter_session(parser: &mut Parser, set: bool) -> Result<Statement, ParserError> {
374 let session_options = parse_session_options(parser, set)?;
375 Ok(Statement::AlterSession {
376 set,
377 session_params: KeyValueOptions {
378 options: session_options,
379 },
380 })
381}
382
383pub fn parse_create_table(
387 or_replace: bool,
388 global: Option<bool>,
389 temporary: bool,
390 volatile: bool,
391 transient: bool,
392 iceberg: bool,
393 parser: &mut Parser,
394) -> Result<Statement, ParserError> {
395 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
396 let table_name = parser.parse_object_name(false)?;
397
398 let mut builder = CreateTableBuilder::new(table_name)
399 .or_replace(or_replace)
400 .if_not_exists(if_not_exists)
401 .temporary(temporary)
402 .transient(transient)
403 .volatile(volatile)
404 .iceberg(iceberg)
405 .global(global)
406 .hive_formats(Some(Default::default()));
407
408 loop {
415 let next_token = parser.next_token();
416 match &next_token.token {
417 Token::Word(word) => match word.keyword {
418 Keyword::COPY => {
419 parser.expect_keyword_is(Keyword::GRANTS)?;
420 builder = builder.copy_grants(true);
421 }
422 Keyword::COMMENT => {
423 parser.prev_token();
425 builder = builder.comment(parser.parse_optional_inline_comment()?);
426 }
427 Keyword::AS => {
428 let query = parser.parse_query()?;
429 builder = builder.query(Some(query));
430 break;
431 }
432 Keyword::CLONE => {
433 let clone = parser.parse_object_name(false).ok();
434 builder = builder.clone_clause(clone);
435 break;
436 }
437 Keyword::LIKE => {
438 let like = parser.parse_object_name(false).ok();
439 builder = builder.like(like);
440 break;
441 }
442 Keyword::CLUSTER => {
443 parser.expect_keyword_is(Keyword::BY)?;
444 parser.expect_token(&Token::LParen)?;
445 let cluster_by = Some(WrappedCollection::Parentheses(
446 parser.parse_comma_separated(|p| p.parse_identifier())?,
447 ));
448 parser.expect_token(&Token::RParen)?;
449
450 builder = builder.cluster_by(cluster_by)
451 }
452 Keyword::ENABLE_SCHEMA_EVOLUTION => {
453 parser.expect_token(&Token::Eq)?;
454 let enable_schema_evolution =
455 match parser.parse_one_of_keywords(&[Keyword::TRUE, Keyword::FALSE]) {
456 Some(Keyword::TRUE) => true,
457 Some(Keyword::FALSE) => false,
458 _ => {
459 return parser.expected("TRUE or FALSE", next_token);
460 }
461 };
462
463 builder = builder.enable_schema_evolution(Some(enable_schema_evolution));
464 }
465 Keyword::CHANGE_TRACKING => {
466 parser.expect_token(&Token::Eq)?;
467 let change_tracking =
468 match parser.parse_one_of_keywords(&[Keyword::TRUE, Keyword::FALSE]) {
469 Some(Keyword::TRUE) => true,
470 Some(Keyword::FALSE) => false,
471 _ => {
472 return parser.expected("TRUE or FALSE", next_token);
473 }
474 };
475
476 builder = builder.change_tracking(Some(change_tracking));
477 }
478 Keyword::DATA_RETENTION_TIME_IN_DAYS => {
479 parser.expect_token(&Token::Eq)?;
480 let data_retention_time_in_days = parser.parse_literal_uint()?;
481 builder =
482 builder.data_retention_time_in_days(Some(data_retention_time_in_days));
483 }
484 Keyword::MAX_DATA_EXTENSION_TIME_IN_DAYS => {
485 parser.expect_token(&Token::Eq)?;
486 let max_data_extension_time_in_days = parser.parse_literal_uint()?;
487 builder = builder
488 .max_data_extension_time_in_days(Some(max_data_extension_time_in_days));
489 }
490 Keyword::DEFAULT_DDL_COLLATION => {
491 parser.expect_token(&Token::Eq)?;
492 let default_ddl_collation = parser.parse_literal_string()?;
493 builder = builder.default_ddl_collation(Some(default_ddl_collation));
494 }
495 Keyword::WITH => {
498 parser.expect_one_of_keywords(&[
499 Keyword::AGGREGATION,
500 Keyword::TAG,
501 Keyword::ROW,
502 ])?;
503 parser.prev_token();
504 }
505 Keyword::AGGREGATION => {
506 parser.expect_keyword_is(Keyword::POLICY)?;
507 let aggregation_policy = parser.parse_object_name(false)?;
508 builder = builder.with_aggregation_policy(Some(aggregation_policy));
509 }
510 Keyword::ROW => {
511 parser.expect_keywords(&[Keyword::ACCESS, Keyword::POLICY])?;
512 let policy = parser.parse_object_name(false)?;
513 parser.expect_keyword_is(Keyword::ON)?;
514 parser.expect_token(&Token::LParen)?;
515 let columns = parser.parse_comma_separated(|p| p.parse_identifier())?;
516 parser.expect_token(&Token::RParen)?;
517
518 builder =
519 builder.with_row_access_policy(Some(RowAccessPolicy::new(policy, columns)))
520 }
521 Keyword::TAG => {
522 parser.expect_token(&Token::LParen)?;
523 let tags = parser.parse_comma_separated(Parser::parse_tag)?;
524 parser.expect_token(&Token::RParen)?;
525 builder = builder.with_tags(Some(tags));
526 }
527 Keyword::ON if parser.parse_keyword(Keyword::COMMIT) => {
528 let on_commit = Some(parser.parse_create_table_on_commit()?);
529 builder = builder.on_commit(on_commit);
530 }
531 Keyword::EXTERNAL_VOLUME => {
532 parser.expect_token(&Token::Eq)?;
533 builder.external_volume = Some(parser.parse_literal_string()?);
534 }
535 Keyword::CATALOG => {
536 parser.expect_token(&Token::Eq)?;
537 builder.catalog = Some(parser.parse_literal_string()?);
538 }
539 Keyword::BASE_LOCATION => {
540 parser.expect_token(&Token::Eq)?;
541 builder.base_location = Some(parser.parse_literal_string()?);
542 }
543 Keyword::CATALOG_SYNC => {
544 parser.expect_token(&Token::Eq)?;
545 builder.catalog_sync = Some(parser.parse_literal_string()?);
546 }
547 Keyword::STORAGE_SERIALIZATION_POLICY => {
548 parser.expect_token(&Token::Eq)?;
549
550 builder.storage_serialization_policy =
551 Some(parse_storage_serialization_policy(parser)?);
552 }
553 _ => {
554 return parser.expected("end of statement", next_token);
555 }
556 },
557 Token::LParen => {
558 parser.prev_token();
559 let (columns, constraints) = parser.parse_columns()?;
560 builder = builder.columns(columns).constraints(constraints);
561 }
562 Token::EOF => {
563 if builder.columns.is_empty() {
564 return Err(ParserError::ParserError(
565 "unexpected end of input".to_string(),
566 ));
567 }
568
569 break;
570 }
571 Token::SemiColon => {
572 if builder.columns.is_empty() {
573 return Err(ParserError::ParserError(
574 "unexpected end of input".to_string(),
575 ));
576 }
577
578 parser.prev_token();
579 break;
580 }
581 _ => {
582 return parser.expected("end of statement", next_token);
583 }
584 }
585 }
586
587 if iceberg && builder.base_location.is_none() {
588 return Err(ParserError::ParserError(
589 "BASE_LOCATION is required for ICEBERG tables".to_string(),
590 ));
591 }
592
593 Ok(builder.build())
594}
595
596pub fn parse_storage_serialization_policy(
597 parser: &mut Parser,
598) -> Result<StorageSerializationPolicy, ParserError> {
599 let next_token = parser.next_token();
600 match &next_token.token {
601 Token::Word(w) => match w.keyword {
602 Keyword::COMPATIBLE => Ok(StorageSerializationPolicy::Compatible),
603 Keyword::OPTIMIZED => Ok(StorageSerializationPolicy::Optimized),
604 _ => parser.expected("storage_serialization_policy", next_token),
605 },
606 _ => parser.expected("storage_serialization_policy", next_token),
607 }
608}
609
610pub fn parse_create_stage(
611 or_replace: bool,
612 temporary: bool,
613 parser: &mut Parser,
614) -> Result<Statement, ParserError> {
615 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
617 let name = parser.parse_object_name(false)?;
618 let mut directory_table_params = Vec::new();
619 let mut file_format = Vec::new();
620 let mut copy_options = Vec::new();
621 let mut comment = None;
622
623 let stage_params = parse_stage_params(parser)?;
625
626 if parser.parse_keyword(Keyword::DIRECTORY) {
628 parser.expect_token(&Token::Eq)?;
629 directory_table_params = parse_parentheses_options(parser)?;
630 }
631
632 if parser.parse_keyword(Keyword::FILE_FORMAT) {
634 parser.expect_token(&Token::Eq)?;
635 file_format = parse_parentheses_options(parser)?;
636 }
637
638 if parser.parse_keyword(Keyword::COPY_OPTIONS) {
640 parser.expect_token(&Token::Eq)?;
641 copy_options = parse_parentheses_options(parser)?;
642 }
643
644 if parser.parse_keyword(Keyword::COMMENT) {
646 parser.expect_token(&Token::Eq)?;
647 comment = Some(match parser.next_token().token {
648 Token::SingleQuotedString(word) => Ok(word),
649 _ => parser.expected("a comment statement", parser.peek_token()),
650 }?)
651 }
652
653 Ok(Statement::CreateStage {
654 or_replace,
655 temporary,
656 if_not_exists,
657 name,
658 stage_params,
659 directory_table_params: KeyValueOptions {
660 options: directory_table_params,
661 },
662 file_format: KeyValueOptions {
663 options: file_format,
664 },
665 copy_options: KeyValueOptions {
666 options: copy_options,
667 },
668 comment,
669 })
670}
671
672pub fn parse_stage_name_identifier(parser: &mut Parser) -> Result<Ident, ParserError> {
673 let mut ident = String::new();
674 while let Some(next_token) = parser.next_token_no_skip() {
675 match &next_token.token {
676 Token::Whitespace(_) | Token::SemiColon => break,
677 Token::Period => {
678 parser.prev_token();
679 break;
680 }
681 Token::RParen => {
682 parser.prev_token();
683 break;
684 }
685 Token::AtSign => ident.push('@'),
686 Token::Tilde => ident.push('~'),
687 Token::Mod => ident.push('%'),
688 Token::Div => ident.push('/'),
689 Token::Word(w) => ident.push_str(&w.to_string()),
690 _ => return parser.expected("stage name identifier", parser.peek_token()),
691 }
692 }
693 Ok(Ident::new(ident))
694}
695
696pub fn parse_snowflake_stage_name(parser: &mut Parser) -> Result<ObjectName, ParserError> {
697 match parser.next_token().token {
698 Token::AtSign => {
699 parser.prev_token();
700 let mut idents = vec![];
701 loop {
702 idents.push(parse_stage_name_identifier(parser)?);
703 if !parser.consume_token(&Token::Period) {
704 break;
705 }
706 }
707 Ok(ObjectName::from(idents))
708 }
709 _ => {
710 parser.prev_token();
711 Ok(parser.parse_object_name(false)?)
712 }
713 }
714}
715
716pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
719 let kind = match parser.peek_token().token {
720 Token::AtSign => CopyIntoSnowflakeKind::Location,
722 Token::SingleQuotedString(s) if s.contains("://") => CopyIntoSnowflakeKind::Location,
724 _ => CopyIntoSnowflakeKind::Table,
725 };
726
727 let mut files: Vec<String> = vec![];
728 let mut from_transformations: Option<Vec<StageLoadSelectItem>> = None;
729 let mut from_stage_alias = None;
730 let mut from_stage = None;
731 let mut stage_params = StageParamsObject {
732 url: None,
733 encryption: KeyValueOptions { options: vec![] },
734 endpoint: None,
735 storage_integration: None,
736 credentials: KeyValueOptions { options: vec![] },
737 };
738 let mut from_query = None;
739 let mut partition = None;
740 let mut file_format = Vec::new();
741 let mut pattern = None;
742 let mut validation_mode = None;
743 let mut copy_options = Vec::new();
744
745 let into: ObjectName = parse_snowflake_stage_name(parser)?;
746 if kind == CopyIntoSnowflakeKind::Location {
747 stage_params = parse_stage_params(parser)?;
748 }
749
750 parser.expect_keyword_is(Keyword::FROM)?;
751 match parser.next_token().token {
752 Token::LParen if kind == CopyIntoSnowflakeKind::Table => {
753 parser.expect_keyword_is(Keyword::SELECT)?;
755 from_transformations = parse_select_items_for_data_load(parser)?;
756
757 parser.expect_keyword_is(Keyword::FROM)?;
758 from_stage = Some(parse_snowflake_stage_name(parser)?);
759 stage_params = parse_stage_params(parser)?;
760
761 from_stage_alias = if parser.parse_keyword(Keyword::AS) {
763 Some(match parser.next_token().token {
764 Token::Word(w) => Ok(Ident::new(w.value)),
765 _ => parser.expected("stage alias", parser.peek_token()),
766 }?)
767 } else {
768 None
769 };
770 parser.expect_token(&Token::RParen)?;
771 }
772 Token::LParen if kind == CopyIntoSnowflakeKind::Location => {
773 from_query = Some(parser.parse_query()?);
775 parser.expect_token(&Token::RParen)?;
776 }
777 _ => {
778 parser.prev_token();
779 from_stage = Some(parse_snowflake_stage_name(parser)?);
780 stage_params = parse_stage_params(parser)?;
781
782 from_stage_alias = if parser.parse_keyword(Keyword::AS) {
784 Some(match parser.next_token().token {
785 Token::Word(w) => Ok(Ident::new(w.value)),
786 _ => parser.expected("stage alias", parser.peek_token()),
787 }?)
788 } else {
789 None
790 };
791 }
792 }
793
794 loop {
795 if parser.parse_keyword(Keyword::FILE_FORMAT) {
797 parser.expect_token(&Token::Eq)?;
798 file_format = parse_parentheses_options(parser)?;
799 } else if parser.parse_keywords(&[Keyword::PARTITION, Keyword::BY]) {
801 partition = Some(Box::new(parser.parse_expr()?))
802 } else if parser.parse_keyword(Keyword::FILES) {
804 parser.expect_token(&Token::Eq)?;
805 parser.expect_token(&Token::LParen)?;
806 let mut continue_loop = true;
807 while continue_loop {
808 continue_loop = false;
809 let next_token = parser.next_token();
810 match next_token.token {
811 Token::SingleQuotedString(s) => files.push(s),
812 _ => parser.expected("file token", next_token)?,
813 };
814 if parser.next_token().token.eq(&Token::Comma) {
815 continue_loop = true;
816 } else {
817 parser.prev_token(); }
819 }
820 parser.expect_token(&Token::RParen)?;
821 } else if parser.parse_keyword(Keyword::PATTERN) {
823 parser.expect_token(&Token::Eq)?;
824 let next_token = parser.next_token();
825 pattern = Some(match next_token.token {
826 Token::SingleQuotedString(s) => s,
827 _ => parser.expected("pattern", next_token)?,
828 });
829 } else if parser.parse_keyword(Keyword::VALIDATION_MODE) {
831 parser.expect_token(&Token::Eq)?;
832 validation_mode = Some(parser.next_token().token.to_string());
833 } else if parser.parse_keyword(Keyword::COPY_OPTIONS) {
835 parser.expect_token(&Token::Eq)?;
836 copy_options = parse_parentheses_options(parser)?;
837 } else {
838 match parser.next_token().token {
839 Token::SemiColon | Token::EOF => break,
840 Token::Comma => continue,
841 Token::Word(key) => copy_options.push(parse_option(parser, key)?),
844 _ => return parser.expected("another copy option, ; or EOF'", parser.peek_token()),
845 }
846 }
847 }
848
849 Ok(Statement::CopyIntoSnowflake {
850 kind,
851 into,
852 from_obj: from_stage,
853 from_obj_alias: from_stage_alias,
854 stage_params,
855 from_transformations,
856 from_query,
857 files: if files.is_empty() { None } else { Some(files) },
858 pattern,
859 file_format: KeyValueOptions {
860 options: file_format,
861 },
862 copy_options: KeyValueOptions {
863 options: copy_options,
864 },
865 validation_mode,
866 partition,
867 })
868}
869
870fn parse_select_items_for_data_load(
871 parser: &mut Parser,
872) -> Result<Option<Vec<StageLoadSelectItem>>, ParserError> {
873 let mut select_items: Vec<StageLoadSelectItem> = vec![];
875 loop {
876 let mut alias: Option<Ident> = None;
877 let mut file_col_num: i32 = 0;
878 let mut element: Option<Ident> = None;
879 let mut item_as: Option<Ident> = None;
880
881 let next_token = parser.next_token();
882 match next_token.token {
883 Token::Placeholder(w) => {
884 file_col_num = w.to_string().split_off(1).parse::<i32>().map_err(|e| {
885 ParserError::ParserError(format!("Could not parse '{w}' as i32: {e}"))
886 })?;
887 Ok(())
888 }
889 Token::Word(w) => {
890 alias = Some(Ident::new(w.value));
891 Ok(())
892 }
893 _ => parser.expected("alias or file_col_num", next_token),
894 }?;
895
896 if alias.is_some() {
897 parser.expect_token(&Token::Period)?;
898 let col_num_token = parser.next_token();
900 match col_num_token.token {
901 Token::Placeholder(w) => {
902 file_col_num = w.to_string().split_off(1).parse::<i32>().map_err(|e| {
903 ParserError::ParserError(format!("Could not parse '{w}' as i32: {e}"))
904 })?;
905 Ok(())
906 }
907 _ => parser.expected("file_col_num", col_num_token),
908 }?;
909 }
910
911 match parser.next_token().token {
913 Token::Colon => {
914 element = Some(Ident::new(match parser.next_token().token {
916 Token::Word(w) => Ok(w.value),
917 _ => parser.expected("file_col_num", parser.peek_token()),
918 }?));
919 }
920 _ => {
921 parser.prev_token();
923 }
924 }
925
926 if parser.parse_keyword(Keyword::AS) {
928 item_as = Some(match parser.next_token().token {
929 Token::Word(w) => Ok(Ident::new(w.value)),
930 _ => parser.expected("column item alias", parser.peek_token()),
931 }?);
932 }
933
934 select_items.push(StageLoadSelectItem {
935 alias,
936 file_col_num,
937 element,
938 item_as,
939 });
940
941 match parser.next_token().token {
942 Token::Comma => {
943 }
945 _ => {
946 parser.prev_token(); break;
948 }
949 }
950 }
951 Ok(Some(select_items))
952}
953
954fn parse_stage_params(parser: &mut Parser) -> Result<StageParamsObject, ParserError> {
955 let (mut url, mut storage_integration, mut endpoint) = (None, None, None);
956 let mut encryption: KeyValueOptions = KeyValueOptions { options: vec![] };
957 let mut credentials: KeyValueOptions = KeyValueOptions { options: vec![] };
958
959 if parser.parse_keyword(Keyword::URL) {
961 parser.expect_token(&Token::Eq)?;
962 url = Some(match parser.next_token().token {
963 Token::SingleQuotedString(word) => Ok(word),
964 _ => parser.expected("a URL statement", parser.peek_token()),
965 }?)
966 }
967
968 if parser.parse_keyword(Keyword::STORAGE_INTEGRATION) {
970 parser.expect_token(&Token::Eq)?;
971 storage_integration = Some(parser.next_token().token.to_string());
972 }
973
974 if parser.parse_keyword(Keyword::ENDPOINT) {
976 parser.expect_token(&Token::Eq)?;
977 endpoint = Some(match parser.next_token().token {
978 Token::SingleQuotedString(word) => Ok(word),
979 _ => parser.expected("an endpoint statement", parser.peek_token()),
980 }?)
981 }
982
983 if parser.parse_keyword(Keyword::CREDENTIALS) {
985 parser.expect_token(&Token::Eq)?;
986 credentials = KeyValueOptions {
987 options: parse_parentheses_options(parser)?,
988 };
989 }
990
991 if parser.parse_keyword(Keyword::ENCRYPTION) {
993 parser.expect_token(&Token::Eq)?;
994 encryption = KeyValueOptions {
995 options: parse_parentheses_options(parser)?,
996 };
997 }
998
999 Ok(StageParamsObject {
1000 url,
1001 encryption,
1002 endpoint,
1003 storage_integration,
1004 credentials,
1005 })
1006}
1007
1008fn parse_session_options(
1013 parser: &mut Parser,
1014 set: bool,
1015) -> Result<Vec<KeyValueOption>, ParserError> {
1016 let mut options: Vec<KeyValueOption> = Vec::new();
1017 let empty = String::new;
1018 loop {
1019 match parser.next_token().token {
1020 Token::Comma => continue,
1021 Token::Word(key) => {
1022 if set {
1023 let option = parse_option(parser, key)?;
1024 options.push(option);
1025 } else {
1026 options.push(KeyValueOption {
1027 option_name: key.value,
1028 option_type: KeyValueOptionType::STRING,
1029 value: empty(),
1030 });
1031 }
1032 }
1033 _ => {
1034 if parser.peek_token().token == Token::EOF {
1035 break;
1036 }
1037 return parser.expected("another option", parser.peek_token());
1038 }
1039 }
1040 }
1041 options
1042 .is_empty()
1043 .then(|| {
1044 Err(ParserError::ParserError(
1045 "expected at least one option".to_string(),
1046 ))
1047 })
1048 .unwrap_or(Ok(options))
1049}
1050
1051fn parse_parentheses_options(parser: &mut Parser) -> Result<Vec<KeyValueOption>, ParserError> {
1058 let mut options: Vec<KeyValueOption> = Vec::new();
1059 parser.expect_token(&Token::LParen)?;
1060 loop {
1061 match parser.next_token().token {
1062 Token::RParen => break,
1063 Token::Comma => continue,
1064 Token::Word(key) => options.push(parse_option(parser, key)?),
1065 _ => return parser.expected("another option or ')'", parser.peek_token()),
1066 };
1067 }
1068 Ok(options)
1069}
1070
1071fn parse_option(parser: &mut Parser, key: Word) -> Result<KeyValueOption, ParserError> {
1073 parser.expect_token(&Token::Eq)?;
1074 if parser.parse_keyword(Keyword::TRUE) {
1075 Ok(KeyValueOption {
1076 option_name: key.value,
1077 option_type: KeyValueOptionType::BOOLEAN,
1078 value: "TRUE".to_string(),
1079 })
1080 } else if parser.parse_keyword(Keyword::FALSE) {
1081 Ok(KeyValueOption {
1082 option_name: key.value,
1083 option_type: KeyValueOptionType::BOOLEAN,
1084 value: "FALSE".to_string(),
1085 })
1086 } else {
1087 match parser.next_token().token {
1088 Token::SingleQuotedString(value) => Ok(KeyValueOption {
1089 option_name: key.value,
1090 option_type: KeyValueOptionType::STRING,
1091 value,
1092 }),
1093 Token::Word(word) => Ok(KeyValueOption {
1094 option_name: key.value,
1095 option_type: KeyValueOptionType::ENUM,
1096 value: word.value,
1097 }),
1098 Token::Number(n, _) => Ok(KeyValueOption {
1099 option_name: key.value,
1100 option_type: KeyValueOptionType::NUMBER,
1101 value: n,
1102 }),
1103 _ => parser.expected("expected option value", parser.peek_token()),
1104 }
1105 }
1106}
1107
1108fn parse_identity_property(parser: &mut Parser) -> Result<IdentityProperty, ParserError> {
1115 let parameters = if parser.consume_token(&Token::LParen) {
1116 let seed = parser.parse_number()?;
1117 parser.expect_token(&Token::Comma)?;
1118 let increment = parser.parse_number()?;
1119 parser.expect_token(&Token::RParen)?;
1120
1121 Some(IdentityPropertyFormatKind::FunctionCall(
1122 IdentityParameters { seed, increment },
1123 ))
1124 } else if parser.parse_keyword(Keyword::START) {
1125 let seed = parser.parse_number()?;
1126 parser.expect_keyword_is(Keyword::INCREMENT)?;
1127 let increment = parser.parse_number()?;
1128
1129 Some(IdentityPropertyFormatKind::StartAndIncrement(
1130 IdentityParameters { seed, increment },
1131 ))
1132 } else {
1133 None
1134 };
1135 let order = match parser.parse_one_of_keywords(&[Keyword::ORDER, Keyword::NOORDER]) {
1136 Some(Keyword::ORDER) => Some(IdentityPropertyOrder::Order),
1137 Some(Keyword::NOORDER) => Some(IdentityPropertyOrder::NoOrder),
1138 _ => None,
1139 };
1140 Ok(IdentityProperty { parameters, order })
1141}
1142
1143fn parse_column_policy_property(
1150 parser: &mut Parser,
1151 with: bool,
1152) -> Result<ColumnPolicyProperty, ParserError> {
1153 let policy_name = parser.parse_identifier()?;
1154 let using_columns = if parser.parse_keyword(Keyword::USING) {
1155 parser.expect_token(&Token::LParen)?;
1156 let columns = parser.parse_comma_separated(|p| p.parse_identifier())?;
1157 parser.expect_token(&Token::RParen)?;
1158 Some(columns)
1159 } else {
1160 None
1161 };
1162
1163 Ok(ColumnPolicyProperty {
1164 with,
1165 policy_name,
1166 using_columns,
1167 })
1168}
1169
1170fn parse_column_tags(parser: &mut Parser, with: bool) -> Result<TagsColumnOption, ParserError> {
1177 parser.expect_token(&Token::LParen)?;
1178 let tags = parser.parse_comma_separated(Parser::parse_tag)?;
1179 parser.expect_token(&Token::RParen)?;
1180
1181 Ok(TagsColumnOption { with, tags })
1182}
1183
1184fn parse_show_objects(terse: bool, parser: &mut Parser) -> Result<Statement, ParserError> {
1187 let show_options = parser.parse_show_stmt_options()?;
1188 Ok(Statement::ShowObjects(ShowObjects {
1189 terse,
1190 show_options,
1191 }))
1192}