1#[cfg(not(feature = "std"))]
19use crate::alloc::string::ToString;
20use crate::ast::helpers::stmt_create_table::CreateTableBuilder;
21use crate::ast::helpers::stmt_data_loading::{
22 DataLoadingOption, DataLoadingOptionType, DataLoadingOptions, StageLoadSelectItem,
23 StageParamsObject,
24};
25use crate::ast::{
26 ColumnOption, ColumnPolicy, ColumnPolicyProperty, Ident, IdentityParameters, IdentityProperty,
27 IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, ObjectName,
28 RowAccessPolicy, Statement, TagsColumnOption, WrappedCollection,
29};
30use crate::dialect::{Dialect, Precedence};
31use crate::keywords::Keyword;
32use crate::parser::{Parser, ParserError};
33use crate::tokenizer::Token;
34#[cfg(not(feature = "std"))]
35use alloc::string::String;
36#[cfg(not(feature = "std"))]
37use alloc::vec::Vec;
38#[cfg(not(feature = "std"))]
39use alloc::{format, vec};
40
41use super::keywords::RESERVED_FOR_IDENTIFIER;
42
43#[derive(Debug, Default)]
45pub struct SnowflakeDialect;
46
47impl Dialect for SnowflakeDialect {
48 fn is_identifier_start(&self, ch: char) -> bool {
50 ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch == '_'
51 }
52
53 fn supports_projection_trailing_commas(&self) -> bool {
54 true
55 }
56
57 fn supports_object_name_double_dot_notation(&self) -> bool {
62 true
63 }
64
65 fn is_identifier_part(&self, ch: char) -> bool {
66 ch.is_ascii_lowercase()
67 || ch.is_ascii_uppercase()
68 || ch.is_ascii_digit()
69 || ch == '$'
70 || ch == '_'
71 }
72
73 fn supports_string_literal_backslash_escape(&self) -> bool {
75 true
76 }
77
78 fn supports_within_after_array_aggregation(&self) -> bool {
79 true
80 }
81
82 fn supports_connect_by(&self) -> bool {
83 true
84 }
85
86 fn supports_match_recognize(&self) -> bool {
87 true
88 }
89
90 fn supports_dictionary_syntax(&self) -> bool {
95 true
96 }
97
98 fn supports_window_function_null_treatment_arg(&self) -> bool {
101 true
102 }
103
104 fn supports_parenthesized_set_variables(&self) -> bool {
106 true
107 }
108
109 fn supports_comment_on(&self) -> bool {
111 true
112 }
113
114 fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
115 if parser.parse_keyword(Keyword::CREATE) {
116 let or_replace = parser.parse_keywords(&[Keyword::OR, Keyword::REPLACE]);
119 let global = match parser.parse_one_of_keywords(&[Keyword::LOCAL, Keyword::GLOBAL]) {
121 Some(Keyword::LOCAL) => Some(false),
122 Some(Keyword::GLOBAL) => Some(true),
123 _ => None,
124 };
125
126 let mut temporary = false;
127 let mut volatile = false;
128 let mut transient = false;
129
130 match parser.parse_one_of_keywords(&[
131 Keyword::TEMP,
132 Keyword::TEMPORARY,
133 Keyword::VOLATILE,
134 Keyword::TRANSIENT,
135 ]) {
136 Some(Keyword::TEMP | Keyword::TEMPORARY) => temporary = true,
137 Some(Keyword::VOLATILE) => volatile = true,
138 Some(Keyword::TRANSIENT) => transient = true,
139 _ => {}
140 }
141
142 if parser.parse_keyword(Keyword::STAGE) {
143 return Some(parse_create_stage(or_replace, temporary, parser));
145 } else if parser.parse_keyword(Keyword::TABLE) {
146 return Some(parse_create_table(
147 or_replace, global, temporary, volatile, transient, parser,
148 ));
149 } else {
150 let mut back = 1;
152 if or_replace {
153 back += 2
154 }
155 if temporary {
156 back += 1
157 }
158 for _i in 0..back {
159 parser.prev_token();
160 }
161 }
162 }
163 if parser.parse_keywords(&[Keyword::COPY, Keyword::INTO]) {
164 return Some(parse_copy_into(parser));
166 }
167
168 None
169 }
170
171 fn parse_column_option(
172 &self,
173 parser: &mut Parser,
174 ) -> Result<Option<Result<Option<ColumnOption>, ParserError>>, ParserError> {
175 parser.maybe_parse(|parser| {
176 let with = parser.parse_keyword(Keyword::WITH);
177
178 if parser.parse_keyword(Keyword::IDENTITY) {
179 Ok(parse_identity_property(parser)
180 .map(|p| Some(ColumnOption::Identity(IdentityPropertyKind::Identity(p)))))
181 } else if parser.parse_keyword(Keyword::AUTOINCREMENT) {
182 Ok(parse_identity_property(parser).map(|p| {
183 Some(ColumnOption::Identity(IdentityPropertyKind::Autoincrement(
184 p,
185 )))
186 }))
187 } else if parser.parse_keywords(&[Keyword::MASKING, Keyword::POLICY]) {
188 Ok(parse_column_policy_property(parser, with)
189 .map(|p| Some(ColumnOption::Policy(ColumnPolicy::MaskingPolicy(p)))))
190 } else if parser.parse_keywords(&[Keyword::PROJECTION, Keyword::POLICY]) {
191 Ok(parse_column_policy_property(parser, with)
192 .map(|p| Some(ColumnOption::Policy(ColumnPolicy::ProjectionPolicy(p)))))
193 } else if parser.parse_keywords(&[Keyword::TAG]) {
194 Ok(parse_column_tags(parser, with).map(|p| Some(ColumnOption::Tags(p))))
195 } else {
196 Err(ParserError::ParserError("not found match".to_string()))
197 }
198 })
199 }
200
201 fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
202 let token = parser.peek_token();
203 match token.token {
205 Token::Colon => Some(Ok(self.prec_value(Precedence::DoubleColon))),
206 _ => None,
207 }
208 }
209
210 fn describe_requires_table_keyword(&self) -> bool {
211 true
212 }
213
214 fn allow_extract_custom(&self) -> bool {
215 true
216 }
217
218 fn allow_extract_single_quotes(&self) -> bool {
219 true
220 }
221
222 fn supports_show_like_before_in(&self) -> bool {
225 true
226 }
227
228 fn is_reserved_for_identifier(&self, kw: Keyword) -> bool {
229 if matches!(kw, Keyword::INTERVAL) {
232 false
233 } else {
234 RESERVED_FOR_IDENTIFIER.contains(&kw)
235 }
236 }
237}
238
239pub fn parse_create_table(
242 or_replace: bool,
243 global: Option<bool>,
244 temporary: bool,
245 volatile: bool,
246 transient: bool,
247 parser: &mut Parser,
248) -> Result<Statement, ParserError> {
249 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
250 let table_name = parser.parse_object_name(false)?;
251
252 let mut builder = CreateTableBuilder::new(table_name)
253 .or_replace(or_replace)
254 .if_not_exists(if_not_exists)
255 .temporary(temporary)
256 .transient(transient)
257 .volatile(volatile)
258 .global(global)
259 .hive_formats(Some(Default::default()));
260
261 loop {
268 let next_token = parser.next_token();
269 match &next_token.token {
270 Token::Word(word) => match word.keyword {
271 Keyword::COPY => {
272 parser.expect_keyword(Keyword::GRANTS)?;
273 builder = builder.copy_grants(true);
274 }
275 Keyword::COMMENT => {
276 parser.prev_token();
278 builder = builder.comment(parser.parse_optional_inline_comment()?);
279 }
280 Keyword::AS => {
281 let query = parser.parse_query()?;
282 builder = builder.query(Some(query));
283 break;
284 }
285 Keyword::CLONE => {
286 let clone = parser.parse_object_name(false).ok();
287 builder = builder.clone_clause(clone);
288 break;
289 }
290 Keyword::LIKE => {
291 let like = parser.parse_object_name(false).ok();
292 builder = builder.like(like);
293 break;
294 }
295 Keyword::CLUSTER => {
296 parser.expect_keyword(Keyword::BY)?;
297 parser.expect_token(&Token::LParen)?;
298 let cluster_by = Some(WrappedCollection::Parentheses(
299 parser.parse_comma_separated(|p| p.parse_identifier(false))?,
300 ));
301 parser.expect_token(&Token::RParen)?;
302
303 builder = builder.cluster_by(cluster_by)
304 }
305 Keyword::ENABLE_SCHEMA_EVOLUTION => {
306 parser.expect_token(&Token::Eq)?;
307 let enable_schema_evolution =
308 match parser.parse_one_of_keywords(&[Keyword::TRUE, Keyword::FALSE]) {
309 Some(Keyword::TRUE) => true,
310 Some(Keyword::FALSE) => false,
311 _ => {
312 return parser.expected("TRUE or FALSE", next_token);
313 }
314 };
315
316 builder = builder.enable_schema_evolution(Some(enable_schema_evolution));
317 }
318 Keyword::CHANGE_TRACKING => {
319 parser.expect_token(&Token::Eq)?;
320 let change_tracking =
321 match parser.parse_one_of_keywords(&[Keyword::TRUE, Keyword::FALSE]) {
322 Some(Keyword::TRUE) => true,
323 Some(Keyword::FALSE) => false,
324 _ => {
325 return parser.expected("TRUE or FALSE", next_token);
326 }
327 };
328
329 builder = builder.change_tracking(Some(change_tracking));
330 }
331 Keyword::DATA_RETENTION_TIME_IN_DAYS => {
332 parser.expect_token(&Token::Eq)?;
333 let data_retention_time_in_days = parser.parse_literal_uint()?;
334 builder =
335 builder.data_retention_time_in_days(Some(data_retention_time_in_days));
336 }
337 Keyword::MAX_DATA_EXTENSION_TIME_IN_DAYS => {
338 parser.expect_token(&Token::Eq)?;
339 let max_data_extension_time_in_days = parser.parse_literal_uint()?;
340 builder = builder
341 .max_data_extension_time_in_days(Some(max_data_extension_time_in_days));
342 }
343 Keyword::DEFAULT_DDL_COLLATION => {
344 parser.expect_token(&Token::Eq)?;
345 let default_ddl_collation = parser.parse_literal_string()?;
346 builder = builder.default_ddl_collation(Some(default_ddl_collation));
347 }
348 Keyword::WITH => {
351 parser.expect_one_of_keywords(&[
352 Keyword::AGGREGATION,
353 Keyword::TAG,
354 Keyword::ROW,
355 ])?;
356 parser.prev_token();
357 }
358 Keyword::AGGREGATION => {
359 parser.expect_keyword(Keyword::POLICY)?;
360 let aggregation_policy = parser.parse_object_name(false)?;
361 builder = builder.with_aggregation_policy(Some(aggregation_policy));
362 }
363 Keyword::ROW => {
364 parser.expect_keywords(&[Keyword::ACCESS, Keyword::POLICY])?;
365 let policy = parser.parse_object_name(false)?;
366 parser.expect_keyword(Keyword::ON)?;
367 parser.expect_token(&Token::LParen)?;
368 let columns = parser.parse_comma_separated(|p| p.parse_identifier(false))?;
369 parser.expect_token(&Token::RParen)?;
370
371 builder =
372 builder.with_row_access_policy(Some(RowAccessPolicy::new(policy, columns)))
373 }
374 Keyword::TAG => {
375 parser.expect_token(&Token::LParen)?;
376 let tags = parser.parse_comma_separated(Parser::parse_tag)?;
377 parser.expect_token(&Token::RParen)?;
378 builder = builder.with_tags(Some(tags));
379 }
380 _ => {
381 return parser.expected("end of statement", next_token);
382 }
383 },
384 Token::LParen => {
385 parser.prev_token();
386 let (columns, constraints) = parser.parse_columns()?;
387 builder = builder.columns(columns).constraints(constraints);
388 }
389 Token::EOF => {
390 if builder.columns.is_empty() {
391 return Err(ParserError::ParserError(
392 "unexpected end of input".to_string(),
393 ));
394 }
395
396 break;
397 }
398 Token::SemiColon => {
399 if builder.columns.is_empty() {
400 return Err(ParserError::ParserError(
401 "unexpected end of input".to_string(),
402 ));
403 }
404
405 parser.prev_token();
406 break;
407 }
408 _ => {
409 return parser.expected("end of statement", next_token);
410 }
411 }
412 }
413
414 Ok(builder.build())
415}
416
417pub fn parse_create_stage(
418 or_replace: bool,
419 temporary: bool,
420 parser: &mut Parser,
421) -> Result<Statement, ParserError> {
422 let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
424 let name = parser.parse_object_name(false)?;
425 let mut directory_table_params = Vec::new();
426 let mut file_format = Vec::new();
427 let mut copy_options = Vec::new();
428 let mut comment = None;
429
430 let stage_params = parse_stage_params(parser)?;
432
433 if parser.parse_keyword(Keyword::DIRECTORY) {
435 parser.expect_token(&Token::Eq)?;
436 directory_table_params = parse_parentheses_options(parser)?;
437 }
438
439 if parser.parse_keyword(Keyword::FILE_FORMAT) {
441 parser.expect_token(&Token::Eq)?;
442 file_format = parse_parentheses_options(parser)?;
443 }
444
445 if parser.parse_keyword(Keyword::COPY_OPTIONS) {
447 parser.expect_token(&Token::Eq)?;
448 copy_options = parse_parentheses_options(parser)?;
449 }
450
451 if parser.parse_keyword(Keyword::COMMENT) {
453 parser.expect_token(&Token::Eq)?;
454 comment = Some(match parser.next_token().token {
455 Token::SingleQuotedString(word) => Ok(word),
456 _ => parser.expected("a comment statement", parser.peek_token()),
457 }?)
458 }
459
460 Ok(Statement::CreateStage {
461 or_replace,
462 temporary,
463 if_not_exists,
464 name,
465 stage_params,
466 directory_table_params: DataLoadingOptions {
467 options: directory_table_params,
468 },
469 file_format: DataLoadingOptions {
470 options: file_format,
471 },
472 copy_options: DataLoadingOptions {
473 options: copy_options,
474 },
475 comment,
476 })
477}
478
479pub fn parse_stage_name_identifier(parser: &mut Parser) -> Result<Ident, ParserError> {
480 let mut ident = String::new();
481 while let Some(next_token) = parser.next_token_no_skip() {
482 match &next_token.token {
483 Token::Whitespace(_) => break,
484 Token::Period => {
485 parser.prev_token();
486 break;
487 }
488 Token::RParen => {
489 parser.prev_token();
490 break;
491 }
492 Token::AtSign => ident.push('@'),
493 Token::Tilde => ident.push('~'),
494 Token::Mod => ident.push('%'),
495 Token::Div => ident.push('/'),
496 Token::Word(w) => ident.push_str(&w.value),
497 _ => return parser.expected("stage name identifier", parser.peek_token()),
498 }
499 }
500 Ok(Ident::new(ident))
501}
502
503pub fn parse_snowflake_stage_name(parser: &mut Parser) -> Result<ObjectName, ParserError> {
504 match parser.next_token().token {
505 Token::AtSign => {
506 parser.prev_token();
507 let mut idents = vec![];
508 loop {
509 idents.push(parse_stage_name_identifier(parser)?);
510 if !parser.consume_token(&Token::Period) {
511 break;
512 }
513 }
514 Ok(ObjectName(idents))
515 }
516 _ => {
517 parser.prev_token();
518 Ok(parser.parse_object_name(false)?)
519 }
520 }
521}
522
523pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
524 let into: ObjectName = parse_snowflake_stage_name(parser)?;
525 let mut files: Vec<String> = vec![];
526 let mut from_transformations: Option<Vec<StageLoadSelectItem>> = None;
527 let from_stage_alias;
528 let from_stage: ObjectName;
529 let stage_params: StageParamsObject;
530
531 parser.expect_keyword(Keyword::FROM)?;
532 match parser.next_token().token {
534 Token::LParen => {
535 parser.expect_keyword(Keyword::SELECT)?;
537 from_transformations = parse_select_items_for_data_load(parser)?;
538
539 parser.expect_keyword(Keyword::FROM)?;
540 from_stage = parse_snowflake_stage_name(parser)?;
541 stage_params = parse_stage_params(parser)?;
542
543 from_stage_alias = if parser.parse_keyword(Keyword::AS) {
545 Some(match parser.next_token().token {
546 Token::Word(w) => Ok(Ident::new(w.value)),
547 _ => parser.expected("stage alias", parser.peek_token()),
548 }?)
549 } else {
550 None
551 };
552 parser.expect_token(&Token::RParen)?;
553 }
554 _ => {
555 parser.prev_token();
556 from_stage = parse_snowflake_stage_name(parser)?;
557 stage_params = parse_stage_params(parser)?;
558
559 from_stage_alias = if parser.parse_keyword(Keyword::AS) {
561 Some(match parser.next_token().token {
562 Token::Word(w) => Ok(Ident::new(w.value)),
563 _ => parser.expected("stage alias", parser.peek_token()),
564 }?)
565 } else {
566 None
567 };
568 }
569 };
570
571 if parser.parse_keyword(Keyword::FILES) {
573 parser.expect_token(&Token::Eq)?;
574 parser.expect_token(&Token::LParen)?;
575 let mut continue_loop = true;
576 while continue_loop {
577 continue_loop = false;
578 let next_token = parser.next_token();
579 match next_token.token {
580 Token::SingleQuotedString(s) => files.push(s),
581 _ => parser.expected("file token", next_token)?,
582 };
583 if parser.next_token().token.eq(&Token::Comma) {
584 continue_loop = true;
585 } else {
586 parser.prev_token(); }
588 }
589 parser.expect_token(&Token::RParen)?;
590 }
591
592 let mut pattern = None;
594 if parser.parse_keyword(Keyword::PATTERN) {
595 parser.expect_token(&Token::Eq)?;
596 let next_token = parser.next_token();
597 pattern = Some(match next_token.token {
598 Token::SingleQuotedString(s) => s,
599 _ => parser.expected("pattern", next_token)?,
600 });
601 }
602
603 let mut file_format = Vec::new();
605 if parser.parse_keyword(Keyword::FILE_FORMAT) {
606 parser.expect_token(&Token::Eq)?;
607 file_format = parse_parentheses_options(parser)?;
608 }
609
610 let mut copy_options = Vec::new();
612 if parser.parse_keyword(Keyword::COPY_OPTIONS) {
613 parser.expect_token(&Token::Eq)?;
614 copy_options = parse_parentheses_options(parser)?;
615 }
616
617 let mut validation_mode = None;
619 if parser.parse_keyword(Keyword::VALIDATION_MODE) {
620 parser.expect_token(&Token::Eq)?;
621 validation_mode = Some(parser.next_token().token.to_string());
622 }
623
624 Ok(Statement::CopyIntoSnowflake {
625 into,
626 from_stage,
627 from_stage_alias,
628 stage_params,
629 from_transformations,
630 files: if files.is_empty() { None } else { Some(files) },
631 pattern,
632 file_format: DataLoadingOptions {
633 options: file_format,
634 },
635 copy_options: DataLoadingOptions {
636 options: copy_options,
637 },
638 validation_mode,
639 })
640}
641
642fn parse_select_items_for_data_load(
643 parser: &mut Parser,
644) -> Result<Option<Vec<StageLoadSelectItem>>, ParserError> {
645 let mut select_items: Vec<StageLoadSelectItem> = vec![];
647 loop {
648 let mut alias: Option<Ident> = None;
649 let mut file_col_num: i32 = 0;
650 let mut element: Option<Ident> = None;
651 let mut item_as: Option<Ident> = None;
652
653 let next_token = parser.next_token();
654 match next_token.token {
655 Token::Placeholder(w) => {
656 file_col_num = w.to_string().split_off(1).parse::<i32>().map_err(|e| {
657 ParserError::ParserError(format!("Could not parse '{w}' as i32: {e}"))
658 })?;
659 Ok(())
660 }
661 Token::Word(w) => {
662 alias = Some(Ident::new(w.value));
663 Ok(())
664 }
665 _ => parser.expected("alias or file_col_num", next_token),
666 }?;
667
668 if alias.is_some() {
669 parser.expect_token(&Token::Period)?;
670 let col_num_token = parser.next_token();
672 match col_num_token.token {
673 Token::Placeholder(w) => {
674 file_col_num = w.to_string().split_off(1).parse::<i32>().map_err(|e| {
675 ParserError::ParserError(format!("Could not parse '{w}' as i32: {e}"))
676 })?;
677 Ok(())
678 }
679 _ => parser.expected("file_col_num", col_num_token),
680 }?;
681 }
682
683 match parser.next_token().token {
685 Token::Colon => {
686 element = Some(Ident::new(match parser.next_token().token {
688 Token::Word(w) => Ok(w.value),
689 _ => parser.expected("file_col_num", parser.peek_token()),
690 }?));
691 }
692 _ => {
693 parser.prev_token();
695 }
696 }
697
698 if parser.parse_keyword(Keyword::AS) {
700 item_as = Some(match parser.next_token().token {
701 Token::Word(w) => Ok(Ident::new(w.value)),
702 _ => parser.expected("column item alias", parser.peek_token()),
703 }?);
704 }
705
706 select_items.push(StageLoadSelectItem {
707 alias,
708 file_col_num,
709 element,
710 item_as,
711 });
712
713 match parser.next_token().token {
714 Token::Comma => {
715 }
717 _ => {
718 parser.prev_token(); break;
720 }
721 }
722 }
723 Ok(Some(select_items))
724}
725
726fn parse_stage_params(parser: &mut Parser) -> Result<StageParamsObject, ParserError> {
727 let (mut url, mut storage_integration, mut endpoint) = (None, None, None);
728 let mut encryption: DataLoadingOptions = DataLoadingOptions { options: vec![] };
729 let mut credentials: DataLoadingOptions = DataLoadingOptions { options: vec![] };
730
731 if parser.parse_keyword(Keyword::URL) {
733 parser.expect_token(&Token::Eq)?;
734 url = Some(match parser.next_token().token {
735 Token::SingleQuotedString(word) => Ok(word),
736 _ => parser.expected("a URL statement", parser.peek_token()),
737 }?)
738 }
739
740 if parser.parse_keyword(Keyword::STORAGE_INTEGRATION) {
742 parser.expect_token(&Token::Eq)?;
743 storage_integration = Some(parser.next_token().token.to_string());
744 }
745
746 if parser.parse_keyword(Keyword::ENDPOINT) {
748 parser.expect_token(&Token::Eq)?;
749 endpoint = Some(match parser.next_token().token {
750 Token::SingleQuotedString(word) => Ok(word),
751 _ => parser.expected("an endpoint statement", parser.peek_token()),
752 }?)
753 }
754
755 if parser.parse_keyword(Keyword::CREDENTIALS) {
757 parser.expect_token(&Token::Eq)?;
758 credentials = DataLoadingOptions {
759 options: parse_parentheses_options(parser)?,
760 };
761 }
762
763 if parser.parse_keyword(Keyword::ENCRYPTION) {
765 parser.expect_token(&Token::Eq)?;
766 encryption = DataLoadingOptions {
767 options: parse_parentheses_options(parser)?,
768 };
769 }
770
771 Ok(StageParamsObject {
772 url,
773 encryption,
774 endpoint,
775 storage_integration,
776 credentials,
777 })
778}
779
780fn parse_parentheses_options(parser: &mut Parser) -> Result<Vec<DataLoadingOption>, ParserError> {
787 let mut options: Vec<DataLoadingOption> = Vec::new();
788
789 parser.expect_token(&Token::LParen)?;
790 loop {
791 match parser.next_token().token {
792 Token::RParen => break,
793 Token::Word(key) => {
794 parser.expect_token(&Token::Eq)?;
795 if parser.parse_keyword(Keyword::TRUE) {
796 options.push(DataLoadingOption {
797 option_name: key.value,
798 option_type: DataLoadingOptionType::BOOLEAN,
799 value: "TRUE".to_string(),
800 });
801 Ok(())
802 } else if parser.parse_keyword(Keyword::FALSE) {
803 options.push(DataLoadingOption {
804 option_name: key.value,
805 option_type: DataLoadingOptionType::BOOLEAN,
806 value: "FALSE".to_string(),
807 });
808 Ok(())
809 } else {
810 match parser.next_token().token {
811 Token::SingleQuotedString(value) => {
812 options.push(DataLoadingOption {
813 option_name: key.value,
814 option_type: DataLoadingOptionType::STRING,
815 value,
816 });
817 Ok(())
818 }
819 Token::Word(word) => {
820 options.push(DataLoadingOption {
821 option_name: key.value,
822 option_type: DataLoadingOptionType::ENUM,
823 value: word.value,
824 });
825 Ok(())
826 }
827 _ => parser.expected("expected option value", parser.peek_token()),
828 }
829 }
830 }
831 _ => parser.expected("another option or ')'", parser.peek_token()),
832 }?;
833 }
834 Ok(options)
835}
836
837fn parse_identity_property(parser: &mut Parser) -> Result<IdentityProperty, ParserError> {
844 let parameters = if parser.consume_token(&Token::LParen) {
845 let seed = parser.parse_number()?;
846 parser.expect_token(&Token::Comma)?;
847 let increment = parser.parse_number()?;
848 parser.expect_token(&Token::RParen)?;
849
850 Some(IdentityPropertyFormatKind::FunctionCall(
851 IdentityParameters { seed, increment },
852 ))
853 } else if parser.parse_keyword(Keyword::START) {
854 let seed = parser.parse_number()?;
855 parser.expect_keyword(Keyword::INCREMENT)?;
856 let increment = parser.parse_number()?;
857
858 Some(IdentityPropertyFormatKind::StartAndIncrement(
859 IdentityParameters { seed, increment },
860 ))
861 } else {
862 None
863 };
864 let order = match parser.parse_one_of_keywords(&[Keyword::ORDER, Keyword::NOORDER]) {
865 Some(Keyword::ORDER) => Some(IdentityPropertyOrder::Order),
866 Some(Keyword::NOORDER) => Some(IdentityPropertyOrder::NoOrder),
867 _ => None,
868 };
869 Ok(IdentityProperty { parameters, order })
870}
871
872fn parse_column_policy_property(
879 parser: &mut Parser,
880 with: bool,
881) -> Result<ColumnPolicyProperty, ParserError> {
882 let policy_name = parser.parse_identifier(false)?;
883 let using_columns = if parser.parse_keyword(Keyword::USING) {
884 parser.expect_token(&Token::LParen)?;
885 let columns = parser.parse_comma_separated(|p| p.parse_identifier(false))?;
886 parser.expect_token(&Token::RParen)?;
887 Some(columns)
888 } else {
889 None
890 };
891
892 Ok(ColumnPolicyProperty {
893 with,
894 policy_name,
895 using_columns,
896 })
897}
898
899fn parse_column_tags(parser: &mut Parser, with: bool) -> Result<TagsColumnOption, ParserError> {
906 parser.expect_token(&Token::LParen)?;
907 let tags = parser.parse_comma_separated(Parser::parse_tag)?;
908 parser.expect_token(&Token::RParen)?;
909
910 Ok(TagsColumnOption { with, tags })
911}