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