databend_common_ast/parser/
statement.rs

1// Copyright 2021 Datafuse Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::collections::BTreeMap;
16use std::time::Duration;
17
18use educe::Educe;
19use nom::branch::alt;
20use nom::combinator::consumed;
21use nom::combinator::map;
22use nom::combinator::not;
23use nom::combinator::value;
24use nom::Slice;
25use nom_rule::rule;
26
27use super::sequence::sequence;
28use crate::ast::*;
29use crate::parser::comment::comment;
30use crate::parser::common::*;
31use crate::parser::copy::copy_into;
32use crate::parser::copy::copy_into_table;
33use crate::parser::data_mask::data_mask_policy;
34use crate::parser::dynamic_table::dynamic_table;
35use crate::parser::expr::subexpr;
36use crate::parser::expr::*;
37use crate::parser::input::Input;
38use crate::parser::query::*;
39use crate::parser::stage::*;
40use crate::parser::stream::stream_table;
41use crate::parser::token::*;
42use crate::parser::Error;
43use crate::parser::ErrorKind;
44use crate::span::merge_span;
45
46pub enum ShowGrantOption {
47    PrincipalIdentity(PrincipalIdentity),
48    GrantObjectName(GrantObjectName),
49    OfRole(String),
50}
51
52// (tenant, share name, endpoint name)
53pub type ShareDatabaseParams = (ShareNameIdent, Identifier);
54
55#[derive(Clone)]
56pub enum CreateDatabaseOption {
57    DatabaseEngine(DatabaseEngine),
58}
59
60pub fn statement_body(i: Input) -> IResult<Statement> {
61    let explain = map_res(
62        rule! {
63            EXPLAIN ~ ( "(" ~ #comma_separated_list1(explain_option) ~ ")" )? ~ ( AST | SYNTAX | PIPELINE | JOIN | GRAPH | FRAGMENTS | RAW | OPTIMIZED | MEMO | DECORRELATED | PERF)? ~ #statement
64        },
65        |(_, options, opt_kind, statement)| {
66            Ok(Statement::Explain {
67                kind: match opt_kind.map(|token| token.kind) {
68                    Some(TokenKind::SYNTAX) | Some(TokenKind::AST) => {
69                        let pretty_stmt = statement.stmt.to_string();
70                        ExplainKind::Syntax(pretty_stmt)
71                    }
72                    Some(TokenKind::PIPELINE) => ExplainKind::Pipeline,
73                    Some(TokenKind::JOIN) => ExplainKind::Join,
74                    Some(TokenKind::GRAPH) => ExplainKind::Graph,
75                    Some(TokenKind::FRAGMENTS) => ExplainKind::Fragments,
76                    Some(TokenKind::RAW) => ExplainKind::Raw,
77                    Some(TokenKind::OPTIMIZED) => ExplainKind::Optimized,
78                    Some(TokenKind::DECORRELATED) => ExplainKind::Decorrelated,
79                    Some(TokenKind::MEMO) => ExplainKind::Memo("".to_string()),
80                    Some(TokenKind::GRAPHICAL) => ExplainKind::Graphical,
81                    Some(TokenKind::PERF) => ExplainKind::Perf,
82                    None => ExplainKind::Plan,
83                    _ => unreachable!(),
84                },
85                options: options
86                    .map(|(a, opts, b)| (merge_span(Some(a.span), Some(b.span)), opts))
87                    .unwrap_or_default(),
88                query: Box::new(statement.stmt),
89            })
90        },
91    );
92
93    let query_setting = map_res(
94        rule! {
95            SETTINGS ~ #query_statement_setting? ~ #statement_body
96        },
97        |(_, opt_settings, statement)| {
98            Ok(Statement::StatementWithSettings {
99                settings: opt_settings,
100                stmt: Box::new(statement),
101            })
102        },
103    );
104    let explain_analyze = map(
105        rule! {
106            EXPLAIN ~ ANALYZE ~ (PARTIAL|GRAPHICAL)? ~ #statement
107        },
108        |(_, _, opt_partial_or_graphical, statement)| {
109            let (partial, graphical) = match opt_partial_or_graphical {
110                Some(Token {
111                    kind: TokenKind::PARTIAL,
112                    ..
113                }) => (true, false),
114                Some(Token {
115                    kind: TokenKind::GRAPHICAL,
116                    ..
117                }) => (false, true),
118                _ => (false, false),
119            };
120            Statement::ExplainAnalyze {
121                partial,
122                graphical,
123                query: Box::new(statement.stmt),
124            }
125        },
126    );
127
128    let report = map_res(rule! { REPORT ~ ISSUE ~ #rest_str }, |(_, _, (sql, _))| {
129        Ok(Statement::ReportIssue(sql))
130    });
131
132    let create_task = map_res(
133        rule! {
134            CREATE ~ ( OR ~ ^REPLACE )? ~ TASK ~ ( IF ~ ^NOT ~ ^EXISTS )?
135            ~ #ident
136            ~ #create_task_option*
137            ~ #set_table_option?
138            ~ AS ~ #task_sql_block
139        },
140        |(
141            _,
142            opt_or_replace,
143            _,
144            opt_if_not_exists,
145            task,
146            create_task_opts,
147            session_opts,
148            _,
149            sql,
150        )| {
151            let session_opts = session_opts.unwrap_or_default();
152            let create_option =
153                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
154
155            let mut stmt = CreateTaskStmt {
156                create_option,
157                name: task.to_string(),
158                warehouse: None,
159                schedule_opts: None,
160                suspend_task_after_num_failures: None,
161                comments: None,
162                after: vec![],
163                error_integration: None,
164                when_condition: None,
165                sql,
166                session_parameters: session_opts,
167            };
168            for opt in create_task_opts {
169                stmt.apply_opt(opt);
170            }
171            Ok(Statement::CreateTask(stmt))
172        },
173    );
174
175    let alter_task = map(
176        rule! {
177            ALTER ~ TASK ~ ( IF ~ ^EXISTS )?
178            ~ #ident ~ #alter_task_option
179        },
180        |(_, _, opt_if_exists, task, options)| {
181            Statement::AlterTask(AlterTaskStmt {
182                if_exists: opt_if_exists.is_some(),
183                name: task.to_string(),
184                options,
185            })
186        },
187    );
188
189    let drop_task = map(
190        rule! {
191            DROP ~ TASK ~ ( IF ~ ^EXISTS )?
192            ~ #ident
193        },
194        |(_, _, opt_if_exists, task)| {
195            Statement::DropTask(DropTaskStmt {
196                if_exists: opt_if_exists.is_some(),
197                name: task.to_string(),
198            })
199        },
200    );
201    let show_tasks = map(
202        rule! {
203            SHOW ~ TASKS ~ #show_limit?
204        },
205        |(_, _, limit)| Statement::ShowTasks(ShowTasksStmt { limit }),
206    );
207
208    let execute_task = map(
209        rule! {
210            EXECUTE ~ TASK ~ #ident
211        },
212        |(_, _, task)| {
213            Statement::ExecuteTask(ExecuteTaskStmt {
214                name: task.to_string(),
215            })
216        },
217    );
218
219    let desc_task = map(
220        rule! {
221            ( DESC | DESCRIBE ) ~ TASK ~ #ident
222        },
223        |(_, _, task)| {
224            Statement::DescribeTask(DescribeTaskStmt {
225                name: task.to_string(),
226            })
227        },
228    );
229
230    let merge = map(
231        rule! {
232            MERGE ~ #hint?
233            ~ INTO ~ #dot_separated_idents_1_to_3 ~ #table_alias?
234            ~ USING ~ #mutation_source
235            ~ ON ~ #expr ~ (#match_clause | #unmatch_clause)*
236        },
237        |(
238            _,
239            opt_hints,
240            _,
241            (catalog, database, table),
242            target_alias,
243            _,
244            source,
245            _,
246            join_expr,
247            merge_options,
248        )| {
249            Statement::MergeInto(MergeIntoStmt {
250                hints: opt_hints,
251                catalog,
252                database,
253                table_ident: table,
254                source,
255                target_alias,
256                join_expr,
257                merge_options,
258            })
259        },
260    );
261
262    let delete = map(
263        rule! {
264            #with? ~ DELETE ~ #hint? ~ FROM ~ #table_reference_with_alias ~ ( WHERE ~ ^#expr )?
265        },
266        |(with, _, hints, _, table, opt_selection)| {
267            Statement::Delete(DeleteStmt {
268                hints,
269                table,
270                selection: opt_selection.map(|(_, selection)| selection),
271                with,
272            })
273        },
274    );
275
276    let update = map(
277        rule! {
278            #with? ~ UPDATE ~ #hint? ~ #dot_separated_idents_1_to_3 ~ #table_alias?
279            ~ SET ~ ^#comma_separated_list1(mutation_update_expr)
280            ~ ( FROM ~ #mutation_source )?
281            ~ ( WHERE ~ ^#expr )?
282        },
283        |(
284            with,
285            _,
286            hints,
287            (catalog, database, table),
288            table_alias,
289            _,
290            update_list,
291            from,
292            opt_selection,
293        )| {
294            Statement::Update(UpdateStmt {
295                hints,
296                catalog,
297                database,
298                table,
299                table_alias,
300                update_list,
301                from: from.map(|(_, table)| table),
302                selection: opt_selection.map(|(_, selection)| selection),
303                with,
304            })
305        },
306    );
307
308    let show_settings = map(
309        rule! {
310            SHOW ~ SETTINGS ~ #show_options?
311        },
312        |(_, _, show_options)| Statement::ShowSettings { show_options },
313    );
314    let show_variables = map(
315        rule! {
316            SHOW ~ VARIABLES ~ #show_options?
317        },
318        |(_, _, show_options)| Statement::ShowVariables { show_options },
319    );
320    let show_stages = map(
321        rule! {
322            SHOW ~ STAGES ~ #show_options?
323        },
324        |(_, _, show_options)| Statement::ShowStages { show_options },
325    );
326    let show_process_list = map(
327        rule! {
328            SHOW ~ PROCESSLIST ~ #show_options?
329        },
330        |(_, _, show_options)| Statement::ShowProcessList { show_options },
331    );
332    let show_metrics = map(
333        rule! {
334            SHOW ~ METRICS ~ #show_options?
335        },
336        |(_, _, show_options)| Statement::ShowMetrics { show_options },
337    );
338    let show_engines = map(
339        rule! {
340            SHOW ~ ENGINES ~ #show_options?
341        },
342        |(_, _, show_options)| Statement::ShowEngines { show_options },
343    );
344    let show_functions = map(
345        rule! {
346            SHOW ~ FUNCTIONS ~ #show_options?
347        },
348        |(_, _, show_options)| Statement::ShowFunctions { show_options },
349    );
350    let show_user_functions = map(
351        rule! {
352            SHOW ~ USER ~ FUNCTIONS ~ #show_options?
353        },
354        |(_, _, _, show_options)| Statement::ShowUserFunctions { show_options },
355    );
356    let show_table_functions = map(
357        rule! {
358            SHOW ~ TABLE_FUNCTIONS ~ #show_options?
359        },
360        |(_, _, show_options)| Statement::ShowTableFunctions { show_options },
361    );
362    let show_indexes = map(
363        rule! {
364            SHOW ~ INDEXES ~ #show_options?
365        },
366        |(_, _, show_options)| Statement::ShowIndexes { show_options },
367    );
368    let show_locks = map(
369        rule! {
370            SHOW ~ LOCKS ~ ( IN ~ ^ACCOUNT )? ~ #limit_where?
371        },
372        |(_, _, opt_in_account, limit)| {
373            Statement::ShowLocks(ShowLocksStmt {
374                in_account: opt_in_account.is_some(),
375                limit,
376            })
377        },
378    );
379
380    // kill query 199;
381    let kill_stmt = map(
382        rule! {
383            KILL ~ #kill_target ~ #parameter_to_string
384        },
385        |(_, kill_target, object_id)| Statement::KillStmt {
386            kill_target,
387            object_id,
388        },
389    );
390
391    let set_priority = map(
392        rule! {
393            SET ~ PRIORITY ~  #priority  ~ #parameter_to_string
394        },
395        |(_, _, priority, object_id)| Statement::SetPriority {
396            object_id,
397            priority,
398        },
399    );
400
401    let unset_stmt = map(
402        rule! {
403            UNSET ~ #set_type ~ #unset_source
404        },
405        |(_, unset_type, identifiers)| Statement::UnSetStmt {
406            settings: Settings {
407                set_type: unset_type,
408                identifiers,
409                values: SetValues::None,
410            },
411        },
412    );
413
414    let set_role = map(
415        rule! {
416            SET ~ DEFAULT? ~ ROLE ~ #role_name
417        },
418        |(_, opt_is_default, _, role_name)| Statement::SetRole {
419            is_default: opt_is_default.is_some(),
420            role_name,
421        },
422    );
423
424    let set_secondary_roles = map(
425        rule! {
426            SET ~ SECONDARY ~ ROLES ~ (ALL | NONE)
427        },
428        |(_, _, _, token)| {
429            let option = match token.kind {
430                TokenKind::ALL => SecondaryRolesOption::All,
431                TokenKind::NONE => SecondaryRolesOption::None,
432                _ => unreachable!(),
433            };
434            Statement::SetSecondaryRoles { option }
435        },
436    );
437
438    let set_secondary_specify_roles = map(
439        rule! {
440            SET ~ SECONDARY ~ ROLES ~ #comma_separated_list1(role_name)
441        },
442        |(_, _, _, roles)| Statement::SetSecondaryRoles {
443            option: SecondaryRolesOption::SpecifyRole(roles),
444        },
445    );
446
447    let set_stmt = alt((
448        map(
449            rule! {
450                SET ~ #set_type ~ #ident ~ "=" ~ #subexpr(0)
451            },
452            |(_, set_type, var, _, value)| Statement::SetStmt {
453                settings: Settings {
454                    set_type,
455                    identifiers: vec![var],
456                    values: SetValues::Expr(vec![Box::new(value)]),
457                },
458            },
459        ),
460        map_res(
461            rule! {
462                SET ~ #set_type ~ "(" ~ #comma_separated_list0(ident) ~ ")" ~ "="
463                ~ "(" ~ #comma_separated_list0(subexpr(0)) ~ ")"
464            },
465            |(_, set_type, _, ids, _, _, _, values, _)| {
466                if ids.len() == values.len() {
467                    Ok(Statement::SetStmt {
468                        settings: Settings {
469                            set_type,
470                            identifiers: ids,
471                            values: SetValues::Expr(values.into_iter().map(|x| x.into()).collect()),
472                        },
473                    })
474                } else {
475                    Err(nom::Err::Failure(ErrorKind::Other(
476                        "inconsistent number of variables and values",
477                    )))
478                }
479            },
480        ),
481        map(
482            rule! {
483                SET ~ #set_type ~ #ident ~ "=" ~ #query
484            },
485            |(_, set_type, var, _, query)| Statement::SetStmt {
486                settings: Settings {
487                    set_type,
488                    identifiers: vec![var],
489                    values: SetValues::Query(Box::new(query)),
490                },
491            },
492        ),
493        map(
494            rule! {
495                SET ~ #set_type ~ "(" ~ #comma_separated_list0(ident) ~ ")" ~ "=" ~ #query
496            },
497            |(_, set_type, _, vars, _, _, query)| Statement::SetStmt {
498                settings: Settings {
499                    set_type,
500                    identifiers: vars,
501                    values: SetValues::Query(Box::new(query)),
502                },
503            },
504        ),
505    ));
506
507    // catalogs
508    let show_catalogs = map(
509        rule! {
510            SHOW ~ CATALOGS ~ #show_limit?
511        },
512        |(_, _, limit)| Statement::ShowCatalogs(ShowCatalogsStmt { limit }),
513    );
514    let show_create_catalog = map(
515        rule! {
516            SHOW ~ CREATE ~ CATALOG ~ #ident
517        },
518        |(_, _, _, catalog)| Statement::ShowCreateCatalog(ShowCreateCatalogStmt { catalog }),
519    );
520    // TODO: support `COMMENT` in create catalog
521    // TODO: use a more specific option struct instead of BTreeMap
522    let create_catalog = map(
523        rule! {
524            CREATE ~ CATALOG ~ ( IF ~ ^NOT ~ ^EXISTS )?
525            ~ #ident
526            ~ TYPE ~ "=" ~ #catalog_type
527            ~ CONNECTION ~ "=" ~ #connection_options
528        },
529        |(_, _, opt_if_not_exists, catalog, _, _, ty, _, _, options)| {
530            Statement::CreateCatalog(CreateCatalogStmt {
531                if_not_exists: opt_if_not_exists.is_some(),
532                catalog_name: catalog.to_string(),
533                catalog_type: ty,
534                catalog_options: options,
535            })
536        },
537    );
538    let drop_catalog = map(
539        rule! {
540            DROP ~ CATALOG ~ ( IF ~ ^EXISTS )? ~ #ident
541        },
542        |(_, _, opt_if_exists, catalog)| {
543            Statement::DropCatalog(DropCatalogStmt {
544                if_exists: opt_if_exists.is_some(),
545                catalog,
546            })
547        },
548    );
549    let use_catalog = map(
550        rule! {
551            (SET | USE)?  ~ CATALOG ~ #ident
552        },
553        |(_, _, catalog)| Statement::UseCatalog { catalog },
554    );
555
556    let show_online_nodes = map(
557        rule! {
558            SHOW ~ ONLINE ~ NODES
559        },
560        |(_, _, _)| Statement::ShowOnlineNodes(ShowOnlineNodesStmt {}),
561    );
562
563    let show_warehouses = map(
564        rule! {
565            SHOW ~ WAREHOUSES
566        },
567        |(_, _)| Statement::ShowWarehouses(ShowWarehousesStmt {}),
568    );
569
570    let use_warehouse = map(
571        rule! {
572            USE ~ WAREHOUSE ~ #ident
573        },
574        |(_, _, warehouse)| Statement::UseWarehouse(UseWarehouseStmt { warehouse }),
575    );
576
577    let create_warehouse = map(
578        rule! {
579            CREATE ~ WAREHOUSE ~ #ident ~ ("(" ~ #assign_nodes_list ~ ")")? ~ (WITH ~ #warehouse_cluster_option)?
580        },
581        |(_, _, warehouse, nodes, options)| {
582            Statement::CreateWarehouse(CreateWarehouseStmt {
583                warehouse,
584                node_list: nodes.map(|(_, nodes, _)| nodes).unwrap_or_else(Vec::new),
585                options: options.map(|(_, x)| x).unwrap_or_else(BTreeMap::new),
586            })
587        },
588    );
589
590    let drop_warehouse = map(
591        rule! {
592            DROP ~ WAREHOUSE ~ #ident
593        },
594        |(_, _, warehouse)| Statement::DropWarehouse(DropWarehouseStmt { warehouse }),
595    );
596
597    let rename_warehouse = map(
598        rule! {
599            RENAME ~ WAREHOUSE ~ #ident ~ TO ~ #ident
600        },
601        |(_, _, warehouse, _, new_warehouse)| {
602            Statement::RenameWarehouse(RenameWarehouseStmt {
603                warehouse,
604                new_warehouse,
605            })
606        },
607    );
608
609    let resume_warehouse = map(
610        rule! {
611            RESUME ~ WAREHOUSE ~ #ident
612        },
613        |(_, _, warehouse)| Statement::ResumeWarehouse(ResumeWarehouseStmt { warehouse }),
614    );
615
616    let suspend_warehouse = map(
617        rule! {
618            SUSPEND ~ WAREHOUSE ~ #ident
619        },
620        |(_, _, warehouse)| Statement::SuspendWarehouse(SuspendWarehouseStmt { warehouse }),
621    );
622
623    let inspect_warehouse = map(
624        rule! {
625            INSPECT ~ WAREHOUSE ~ #ident
626        },
627        |(_, _, warehouse)| Statement::InspectWarehouse(InspectWarehouseStmt { warehouse }),
628    );
629
630    let add_warehouse_cluster = map(
631        rule! {
632            ALTER ~ WAREHOUSE ~ #ident ~ ADD ~ CLUSTER ~ #ident ~ ("(" ~ #assign_nodes_list ~ ")")? ~ (WITH ~ #warehouse_cluster_option)?
633        },
634        |(_, _, warehouse, _, _, cluster, nodes, options)| {
635            Statement::AddWarehouseCluster(AddWarehouseClusterStmt {
636                warehouse,
637                cluster,
638                node_list: nodes.map(|(_, nodes, _)| nodes).unwrap_or_else(Vec::new),
639                options: options.map(|(_, x)| x).unwrap_or_else(BTreeMap::new),
640            })
641        },
642    );
643
644    let drop_warehouse_cluster = map(
645        rule! {
646            ALTER ~ WAREHOUSE ~ #ident ~ DROP ~ CLUSTER ~ #ident
647        },
648        |(_, _, warehouse, _, _, cluster)| {
649            Statement::DropWarehouseCluster(DropWarehouseClusterStmt { warehouse, cluster })
650        },
651    );
652
653    let rename_warehouse_cluster = map(
654        rule! {
655            ALTER ~ WAREHOUSE ~ #ident ~ RENAME ~ CLUSTER ~ #ident ~ TO ~ #ident
656        },
657        |(_, _, warehouse, _, _, cluster, _, new_cluster)| {
658            Statement::RenameWarehouseCluster(RenameWarehouseClusterStmt {
659                warehouse,
660                cluster,
661                new_cluster,
662            })
663        },
664    );
665
666    let assign_warehouse_nodes = map(
667        rule! {
668            ALTER ~ WAREHOUSE ~ #ident ~ ASSIGN ~ NODES ~ "(" ~ #assign_warehouse_nodes_list ~ ")"
669        },
670        |(_, _, warehouse, _, _, _, nodes, _)| {
671            Statement::AssignWarehouseNodes(AssignWarehouseNodesStmt {
672                warehouse,
673                node_list: nodes,
674            })
675        },
676    );
677
678    let unassign_warehouse_nodes = map(
679        rule! {
680            ALTER ~ WAREHOUSE ~ #ident ~ UNASSIGN ~ NODES ~ "(" ~ #unassign_warehouse_nodes_list ~ ")"
681        },
682        |(_, _, warehouse, _, _, _, nodes, _)| {
683            Statement::UnassignWarehouseNodes(UnassignWarehouseNodesStmt {
684                warehouse,
685                node_list: nodes,
686            })
687        },
688    );
689
690    let show_workload_groups = map(
691        rule! {
692            SHOW ~ WORKLOAD ~ GROUPS
693        },
694        |(_, _, _)| Statement::ShowWorkloadGroups(ShowWorkloadGroupsStmt {}),
695    );
696
697    let create_workload_group = map(
698        rule! {
699            CREATE ~ WORKLOAD ~ GROUP ~ ( IF ~ ^NOT ~ ^EXISTS )? ~ #ident ~ WITH ~ #workload_quotas
700        },
701        |(_, _, _, if_not_exists, name, _, quotas)| {
702            Statement::CreateWorkloadGroup(CreateWorkloadGroupStmt {
703                name,
704                quotas,
705                if_not_exists: if_not_exists.is_some(),
706            })
707        },
708    );
709
710    let drop_workload_group = map(
711        rule! {
712            DROP ~ WORKLOAD ~ GROUP ~ ( IF ~ ^EXISTS )? ~ #ident
713        },
714        |(_, _, _, if_exists, name)| {
715            Statement::DropWorkloadGroup(DropWorkloadGroupStmt {
716                name,
717                if_exists: if_exists.is_some(),
718            })
719        },
720    );
721
722    let rename_workload_group = map(
723        rule! {
724            RENAME ~ WORKLOAD ~ GROUP ~ #ident ~ TO ~ #ident
725        },
726        |(_, _, _, name, _, new_name)| {
727            Statement::RenameWorkloadGroup(RenameWorkloadGroupStmt { name, new_name })
728        },
729    );
730
731    let set_workload_group_quotas = map(
732        rule! {
733            ALTER ~ WORKLOAD ~ GROUP ~ #ident ~ SET ~ #workload_quotas
734        },
735        |(_, _, _, name, _, quotas)| {
736            Statement::SetWorkloadQuotasGroup(SetWorkloadGroupQuotasStmt { name, quotas })
737        },
738    );
739
740    let unset_workload_group_quotas = map(
741        rule! {
742            ALTER ~ WORKLOAD ~ GROUP ~ #ident ~ UNSET ~ #unset_source
743        },
744        |(_, _, _, name, _, quotas)| {
745            Statement::UnsetWorkloadQuotasGroup(UnsetWorkloadGroupQuotasStmt { name, quotas })
746        },
747    );
748
749    let show_databases = map(
750        rule! {
751            SHOW ~ FULL? ~ ( DATABASES | SCHEMAS ) ~ ( ( FROM | IN ) ~ ^#ident )? ~ #show_limit?
752        },
753        |(_, opt_full, _, opt_catalog, limit)| {
754            Statement::ShowDatabases(ShowDatabasesStmt {
755                catalog: opt_catalog.map(|(_, catalog)| catalog),
756                full: opt_full.is_some(),
757                limit,
758            })
759        },
760    );
761
762    let show_drop_databases = map(
763        rule! {
764            SHOW ~ DROP ~ ( DATABASES | DATABASES ) ~ ( FROM ~ ^#ident )? ~ #show_limit?
765        },
766        |(_, _, _, opt_catalog, limit)| {
767            Statement::ShowDropDatabases(ShowDropDatabasesStmt {
768                catalog: opt_catalog.map(|(_, catalog)| catalog),
769                limit,
770            })
771        },
772    );
773
774    let show_create_database = map(
775        rule! {
776            SHOW ~ CREATE ~ ( DATABASE | SCHEMA ) ~ #dot_separated_idents_1_to_2
777        },
778        |(_, _, _, (catalog, database))| {
779            Statement::ShowCreateDatabase(ShowCreateDatabaseStmt { catalog, database })
780        },
781    );
782
783    let create_database = map_res(
784        rule! {
785            CREATE
786            ~ ( OR ~ ^REPLACE )?
787            ~ ( DATABASE | SCHEMA )
788            ~ ( IF ~ ^NOT ~ ^EXISTS )?
789            ~ #database_ref
790            ~ #create_database_option?
791        },
792        |(_, opt_or_replace, _, opt_if_not_exists, database, create_database_option)| {
793            let create_option =
794                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
795
796            let statement = match create_database_option {
797                Some(CreateDatabaseOption::DatabaseEngine(engine)) => {
798                    Statement::CreateDatabase(CreateDatabaseStmt {
799                        create_option,
800                        database,
801                        engine: Some(engine),
802                        options: vec![],
803                    })
804                }
805                None => Statement::CreateDatabase(CreateDatabaseStmt {
806                    create_option,
807                    database,
808                    engine: None,
809                    options: vec![],
810                }),
811            };
812
813            Ok(statement)
814        },
815    );
816
817    let drop_database = map(
818        rule! {
819            DROP ~ ( DATABASE | SCHEMA ) ~ ( IF ~ ^EXISTS )? ~ #dot_separated_idents_1_to_2
820        },
821        |(_, _, opt_if_exists, (catalog, database))| {
822            Statement::DropDatabase(DropDatabaseStmt {
823                if_exists: opt_if_exists.is_some(),
824                catalog,
825                database,
826            })
827        },
828    );
829
830    let undrop_database = map(
831        rule! {
832            UNDROP ~ DATABASE ~ #dot_separated_idents_1_to_2
833        },
834        |(_, _, (catalog, database))| {
835            Statement::UndropDatabase(UndropDatabaseStmt { catalog, database })
836        },
837    );
838
839    let alter_database = map(
840        rule! {
841            ALTER ~ DATABASE ~ ( IF ~ ^EXISTS )? ~ #dot_separated_idents_1_to_2 ~ #alter_database_action
842        },
843        |(_, _, opt_if_exists, (catalog, database), action)| {
844            Statement::AlterDatabase(AlterDatabaseStmt {
845                if_exists: opt_if_exists.is_some(),
846                catalog,
847                database,
848                action,
849            })
850        },
851    );
852    let use_database = map(
853        rule! {
854            USE ~ #ident
855        },
856        |(_, database)| Statement::UseDatabase { database },
857    );
858    let show_tables = map(
859        rule! {
860            SHOW ~ FULL? ~ TABLES ~ HISTORY? ~ ( ( FROM | IN ) ~ #dot_separated_idents_1_to_2 )? ~ #show_limit?
861        },
862        |(_, opt_full, _, opt_history, ctl_db, limit)| {
863            let (catalog, database) = match ctl_db {
864                Some((_, (Some(c), d))) => (Some(c), Some(d)),
865                Some((_, (None, d))) => (None, Some(d)),
866                _ => (None, None),
867            };
868            Statement::ShowTables(ShowTablesStmt {
869                catalog,
870                database,
871                full: opt_full.is_some(),
872                limit,
873                with_history: opt_history.is_some(),
874            })
875        },
876    );
877
878    pub fn from_tables(i: Input) -> IResult<(Option<Identifier>, Option<Identifier>, Identifier)> {
879        let from_dot_table = map(
880            rule! {
881               ( FROM | IN ) ~ ^#dot_separated_idents_1_to_3
882            },
883            |(_, (catalog, database, table))| (catalog, database, table),
884        );
885
886        let from_table = map(
887            rule! {
888                ( FROM | IN ) ~ #ident
889                ~ ( FROM | IN ) ~ ^#dot_separated_idents_1_to_2
890            },
891            |(_, table, _, (catalog, database))| (catalog, Some(database), table),
892        );
893
894        rule!(
895            #from_table
896            | #from_dot_table
897        )(i)
898    }
899
900    let show_columns = map(
901        rule! {
902            SHOW
903            ~ FULL? ~ COLUMNS
904            ~ #from_tables
905            ~ #show_limit?
906        },
907        |(_, opt_full, _, (catalog, database, table), limit)| {
908            Statement::ShowColumns(ShowColumnsStmt {
909                catalog,
910                database,
911                table,
912                full: opt_full.is_some(),
913                limit,
914            })
915        },
916    );
917    let show_create_table = map(
918        rule! {
919            SHOW ~ CREATE ~ TABLE ~ #dot_separated_idents_1_to_3 ~ ( WITH ~ ^QUOTED_IDENTIFIERS )?
920        },
921        |(_, _, _, (catalog, database, table), comment_opt)| {
922            Statement::ShowCreateTable(ShowCreateTableStmt {
923                catalog,
924                database,
925                table,
926                with_quoted_ident: comment_opt.is_some(),
927            })
928        },
929    );
930    let describe_table = map(
931        rule! {
932            ( DESC | DESCRIBE ) ~ TABLE? ~ #dot_separated_idents_1_to_3
933        },
934        |(_, _, (catalog, database, table))| {
935            Statement::DescribeTable(DescribeTableStmt {
936                catalog,
937                database,
938                table,
939            })
940        },
941    );
942
943    // parse `show fields from` statement
944    let show_fields = map(
945        rule! {
946            SHOW ~ FIELDS ~ FROM ~ #dot_separated_idents_1_to_3
947        },
948        |(_, _, _, (catalog, database, table))| {
949            Statement::DescribeTable(DescribeTableStmt {
950                catalog,
951                database,
952                table,
953            })
954        },
955    );
956
957    let show_tables_status = map(
958        rule! {
959            SHOW ~ ( TABLES | TABLE ) ~ STATUS ~ ( FROM ~ ^#ident )? ~ #show_limit?
960        },
961        |(_, _, _, opt_database, limit)| {
962            Statement::ShowTablesStatus(ShowTablesStatusStmt {
963                database: opt_database.map(|(_, database)| database),
964                limit,
965            })
966        },
967    );
968    let show_drop_tables_status = map(
969        rule! {
970            SHOW ~ DROP ~ ( TABLES | TABLE ) ~ ( FROM ~ ^#ident )? ~ #show_limit?
971        },
972        |(_, _, _, opt_database, limit)| {
973            Statement::ShowDropTables(ShowDropTablesStmt {
974                database: opt_database.map(|(_, database)| database),
975                limit,
976            })
977        },
978    );
979
980    let attach_table = map(
981        rule! {
982            ATTACH ~ TABLE ~ #dot_separated_idents_1_to_3 ~ ("(" ~ #comma_separated_list1(ident) ~ ")")? ~ #uri_location
983        },
984        |(_, _, (catalog, database, table), columns_opt, uri_location)| {
985            let columns_opt = columns_opt.map(|(_, v, _)| v);
986            Statement::AttachTable(AttachTableStmt {
987                catalog,
988                database,
989                table,
990                columns_opt,
991                uri_location,
992            })
993        },
994    );
995    let create_table = map_res(
996        rule! {
997            CREATE ~ ( OR ~ ^REPLACE )? ~ (TEMP| TEMPORARY|TRANSIENT)? ~ TABLE ~ ( IF ~ ^NOT ~ ^EXISTS )?
998            ~ #dot_separated_idents_1_to_3
999            ~ #create_table_source?
1000            ~ ( #engine )?
1001            ~ ( #uri_location )?
1002            ~ ( CLUSTER ~ ^BY ~ ( #cluster_type )? ~ ^"(" ~ ^#comma_separated_list1(expr) ~ ^")" )?
1003            ~ ( #table_option )?
1004            ~ ( PARTITION ~ ^BY ~ ^"(" ~ ^#comma_separated_list1(ident) ~ ^")" )?
1005            ~ ( PROPERTIES ~  #connection_options )?
1006            ~ ( AS ~ ^#query )?
1007        },
1008        |(
1009            _,
1010            opt_or_replace,
1011            opt_type,
1012            _,
1013            opt_if_not_exists,
1014            (catalog, database, table),
1015            source,
1016            engine,
1017            uri_location,
1018            opt_cluster_by,
1019            opt_table_options,
1020            opt_iceberg_table_partition_by,
1021            opt_table_properties,
1022            opt_as_query,
1023        )| {
1024            let create_option =
1025                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
1026            let table_type = match opt_type.map(|t| t.kind) {
1027                None => TableType::Normal,
1028                Some(TRANSIENT) => TableType::Transient,
1029                Some(TEMP) | Some(TEMPORARY) => TableType::Temporary,
1030                _ => unreachable!(),
1031            };
1032            Ok(Statement::CreateTable(CreateTableStmt {
1033                create_option,
1034                catalog,
1035                database,
1036                table,
1037                source,
1038                engine,
1039                uri_location,
1040                cluster_by: opt_cluster_by.map(|(_, _, typ, _, exprs, _)| ClusterOption {
1041                    cluster_type: typ.unwrap_or(ClusterType::Linear),
1042                    cluster_exprs: exprs,
1043                }),
1044                table_options: opt_table_options.unwrap_or_default(),
1045                iceberg_table_partition: opt_iceberg_table_partition_by
1046                    .map(|(_, _, _, cols, _)| cols),
1047                table_properties: opt_table_properties.map(|(_, properties)| properties),
1048                as_query: opt_as_query.map(|(_, query)| Box::new(query)),
1049                table_type,
1050            }))
1051        },
1052    );
1053    let drop_table = map(
1054        rule! {
1055            DROP ~ TABLE ~ ( IF ~ ^EXISTS )? ~ #dot_separated_idents_1_to_3 ~ ALL?
1056        },
1057        |(_, _, opt_if_exists, (catalog, database, table), opt_all)| {
1058            Statement::DropTable(DropTableStmt {
1059                if_exists: opt_if_exists.is_some(),
1060                catalog,
1061                database,
1062                table,
1063                all: opt_all.is_some(),
1064            })
1065        },
1066    );
1067    let undrop_table = map(
1068        rule! {
1069            UNDROP ~ TABLE ~ #dot_separated_idents_1_to_3
1070        },
1071        |(_, _, (catalog, database, table))| {
1072            Statement::UndropTable(UndropTableStmt {
1073                catalog,
1074                database,
1075                table,
1076            })
1077        },
1078    );
1079    let alter_table = map(
1080        rule! {
1081            ALTER ~ TABLE ~ ( IF ~ ^EXISTS )? ~ #table_reference_only ~ #alter_table_action
1082        },
1083        |(_, _, opt_if_exists, table_reference, action)| {
1084            Statement::AlterTable(AlterTableStmt {
1085                if_exists: opt_if_exists.is_some(),
1086                table_reference,
1087                action,
1088            })
1089        },
1090    );
1091    let rename_table = map(
1092        rule! {
1093            RENAME ~ TABLE ~ ( IF ~ ^EXISTS )? ~ #dot_separated_idents_1_to_3 ~ TO ~ #dot_separated_idents_1_to_3
1094        },
1095        |(
1096            _,
1097            _,
1098            opt_if_exists,
1099            (catalog, database, table),
1100            _,
1101            (new_catalog, new_database, new_table),
1102        )| {
1103            Statement::RenameTable(RenameTableStmt {
1104                if_exists: opt_if_exists.is_some(),
1105                catalog,
1106                database,
1107                table,
1108                new_catalog,
1109                new_database,
1110                new_table,
1111            })
1112        },
1113    );
1114    let truncate_table = map(
1115        rule! {
1116            TRUNCATE ~ TABLE ~ #dot_separated_idents_1_to_3
1117        },
1118        |(_, _, (catalog, database, table))| {
1119            Statement::TruncateTable(TruncateTableStmt {
1120                catalog,
1121                database,
1122                table,
1123            })
1124        },
1125    );
1126    let optimize_table = map(
1127        rule! {
1128            OPTIMIZE ~ TABLE ~ #dot_separated_idents_1_to_3 ~ #optimize_table_action ~ ( LIMIT ~ #literal_u64 )?
1129        },
1130        |(_, _, (catalog, database, table), action, opt_limit)| {
1131            Statement::OptimizeTable(OptimizeTableStmt {
1132                catalog,
1133                database,
1134                table,
1135                action,
1136                limit: opt_limit.map(|(_, limit)| limit),
1137            })
1138        },
1139    );
1140    let vacuum_temp_files = map(
1141        rule! {
1142            VACUUM ~ TEMPORARY ~ FILES ~ (RETAIN ~ #literal_duration)? ~ (LIMIT ~ #literal_u64)?
1143        },
1144        |(_, _, _, retain, opt_limit)| {
1145            Statement::VacuumTemporaryFiles(VacuumTemporaryFiles {
1146                limit: opt_limit.map(|(_, limit)| limit),
1147                retain: retain.map(|(_, reatin)| reatin),
1148            })
1149        },
1150    );
1151    let vacuum_table = map(
1152        rule! {
1153            VACUUM ~ TABLE ~ #dot_separated_idents_1_to_3 ~ #vacuum_table_option
1154        },
1155        |(_, _, (catalog, database, table), option)| {
1156            Statement::VacuumTable(VacuumTableStmt {
1157                catalog,
1158                database,
1159                table,
1160                option,
1161            })
1162        },
1163    );
1164    let vacuum_drop_table = map(
1165        rule! {
1166            VACUUM ~ DROP ~ TABLE ~ (FROM ~ ^#dot_separated_idents_1_to_2)? ~ #vacuum_drop_table_option
1167        },
1168        |(_, _, _, database_option, option)| {
1169            let (catalog, database) = database_option.map_or_else(
1170                || (None, None),
1171                |(_, catalog_database)| (catalog_database.0, Some(catalog_database.1)),
1172            );
1173            Statement::VacuumDropTable(VacuumDropTableStmt {
1174                catalog,
1175                database,
1176                option,
1177            })
1178        },
1179    );
1180    let analyze_table = map(
1181        rule! {
1182            ANALYZE ~ TABLE ~ #dot_separated_idents_1_to_3 ~ NOSCAN?
1183        },
1184        |(_, _, (catalog, database, table), no_scan)| {
1185            Statement::AnalyzeTable(AnalyzeTableStmt {
1186                catalog,
1187                database,
1188                table,
1189                no_scan: no_scan.is_some(),
1190            })
1191        },
1192    );
1193    let exists_table = map(
1194        rule! {
1195            EXISTS ~ TABLE ~ #dot_separated_idents_1_to_3
1196        },
1197        |(_, _, (catalog, database, table))| {
1198            Statement::ExistsTable(ExistsTableStmt {
1199                catalog,
1200                database,
1201                table,
1202            })
1203        },
1204    );
1205
1206    // DICTIONARY
1207    let create_dictionary = map_res(
1208        rule! {
1209            CREATE ~ ( OR ~ ^REPLACE )? ~ DICTIONARY ~ ( IF ~ ^NOT ~ ^EXISTS )?
1210            ~ #dot_separated_idents_1_to_3
1211            ~ "(" ~ ^#comma_separated_list1(column_def) ~ ^")"
1212            ~ PRIMARY ~ ^KEY  ~ ^#comma_separated_list1(ident)
1213            ~ ^SOURCE ~ ^"(" ~ ^#ident ~ ^"("
1214            ~ ( #table_option )?
1215            ~ ^")" ~ ^")"
1216            ~ ( COMMENT ~ ^#literal_string )?
1217        },
1218        |(
1219            _,
1220            opt_or_replace,
1221            _,
1222            opt_if_not_exists,
1223            (catalog, database, dictionary_name),
1224            _,
1225            columns,
1226            _,
1227            _,
1228            _,
1229            primary_keys,
1230            _,
1231            _,
1232            source_name,
1233            _,
1234            opt_source_options,
1235            _,
1236            _,
1237            opt_comment,
1238        )| {
1239            let create_option =
1240                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
1241            Ok(Statement::CreateDictionary(CreateDictionaryStmt {
1242                create_option,
1243                catalog,
1244                database,
1245                dictionary_name,
1246                columns,
1247                primary_keys,
1248                source_name,
1249                source_options: opt_source_options.unwrap_or_default(),
1250                comment: opt_comment.map(|(_, comment)| comment),
1251            }))
1252        },
1253    );
1254    let drop_dictionary = map(
1255        rule! {
1256            DROP ~ DICTIONARY ~ ( IF ~ ^EXISTS )? ~ #dot_separated_idents_1_to_3
1257        },
1258        |(_, _, opt_if_exists, (catalog, database, dictionary_name))| {
1259            Statement::DropDictionary(DropDictionaryStmt {
1260                if_exists: opt_if_exists.is_some(),
1261                catalog,
1262                database,
1263                dictionary_name,
1264            })
1265        },
1266    );
1267    let show_dictionaries = map(
1268        rule! {
1269            SHOW ~ DICTIONARIES ~ ((FROM|IN) ~ #ident)? ~ #show_limit?
1270        },
1271        |(_, _, db, limit)| {
1272            let database = match db {
1273                Some((_, d)) => Some(d),
1274                _ => None,
1275            };
1276            Statement::ShowDictionaries(ShowDictionariesStmt { database, limit })
1277        },
1278    );
1279    let show_create_dictionary = map(
1280        rule! {
1281            SHOW ~ CREATE ~ DICTIONARY ~ #dot_separated_idents_1_to_3
1282        },
1283        |(_, _, _, (catalog, database, dictionary_name))| {
1284            Statement::ShowCreateDictionary(ShowCreateDictionaryStmt {
1285                catalog,
1286                database,
1287                dictionary_name,
1288            })
1289        },
1290    );
1291    let rename_dictionary = map(
1292        rule! {
1293            RENAME ~ DICTIONARY ~ ( IF ~ ^EXISTS )? ~ #dot_separated_idents_1_to_3 ~ TO ~ #dot_separated_idents_1_to_3
1294        },
1295        |(
1296            _,
1297            _,
1298            opt_if_exists,
1299            (catalog, database, dictionary),
1300            _,
1301            (new_catalog, new_database, new_dictionary),
1302        )| {
1303            Statement::RenameDictionary(RenameDictionaryStmt {
1304                if_exists: opt_if_exists.is_some(),
1305                catalog,
1306                database,
1307                dictionary,
1308                new_catalog,
1309                new_database,
1310                new_dictionary,
1311            })
1312        },
1313    );
1314
1315    let create_view = map_res(
1316        rule! {
1317            CREATE ~ ( OR ~ ^REPLACE )? ~ VIEW ~ ( IF ~ ^NOT ~ ^EXISTS )?
1318            ~ #dot_separated_idents_1_to_3
1319            ~ ( "(" ~ #comma_separated_list1(ident) ~ ")" )?
1320            ~ AS ~ #query
1321        },
1322        |(
1323            _,
1324            opt_or_replace,
1325            _,
1326            opt_if_not_exists,
1327            (catalog, database, view),
1328            opt_columns,
1329            _,
1330            query,
1331        )| {
1332            let create_option =
1333                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
1334            Ok(Statement::CreateView(CreateViewStmt {
1335                create_option,
1336                catalog,
1337                database,
1338                view,
1339                columns: opt_columns
1340                    .map(|(_, columns, _)| columns)
1341                    .unwrap_or_default(),
1342                query: Box::new(query),
1343            }))
1344        },
1345    );
1346    let drop_view = map(
1347        rule! {
1348            DROP ~ VIEW ~ ( IF ~ ^EXISTS )? ~ #dot_separated_idents_1_to_3
1349        },
1350        |(_, _, opt_if_exists, (catalog, database, view))| {
1351            Statement::DropView(DropViewStmt {
1352                if_exists: opt_if_exists.is_some(),
1353                catalog,
1354                database,
1355                view,
1356            })
1357        },
1358    );
1359    let alter_view = map(
1360        rule! {
1361            ALTER ~ VIEW
1362            ~ #dot_separated_idents_1_to_3
1363            ~ ( "(" ~ #comma_separated_list1(ident) ~ ")" )?
1364            ~ AS ~ #query
1365        },
1366        |(_, _, (catalog, database, view), opt_columns, _, query)| {
1367            Statement::AlterView(AlterViewStmt {
1368                catalog,
1369                database,
1370                view,
1371                columns: opt_columns
1372                    .map(|(_, columns, _)| columns)
1373                    .unwrap_or_default(),
1374                query: Box::new(query),
1375            })
1376        },
1377    );
1378    let show_views = map(
1379        rule! {
1380            SHOW ~ FULL? ~ VIEWS ~ HISTORY? ~ ( ( FROM | IN ) ~ #dot_separated_idents_1_to_2 )? ~ #show_limit?
1381        },
1382        |(_, opt_full, _, opt_history, ctl_db, limit)| {
1383            let (catalog, database) = match ctl_db {
1384                Some((_, (Some(c), d))) => (Some(c), Some(d)),
1385                Some((_, (None, d))) => (None, Some(d)),
1386                _ => (None, None),
1387            };
1388            Statement::ShowViews(ShowViewsStmt {
1389                catalog,
1390                database,
1391                full: opt_full.is_some(),
1392                limit,
1393                with_history: opt_history.is_some(),
1394            })
1395        },
1396    );
1397    let describe_view = map(
1398        rule! {
1399            ( DESC | DESCRIBE ) ~ VIEW ~ #dot_separated_idents_1_to_3
1400        },
1401        |(_, _, (catalog, database, view))| {
1402            Statement::DescribeView(DescribeViewStmt {
1403                catalog,
1404                database,
1405                view,
1406            })
1407        },
1408    );
1409
1410    let create_index = map_res(
1411        rule! {
1412            CREATE
1413            ~ ( OR ~ ^REPLACE )?
1414            ~ ASYNC?
1415            ~ AGGREGATING ~ INDEX
1416            ~ ( IF ~ ^NOT ~ ^EXISTS )?
1417            ~ #ident
1418            ~ AS ~ #query
1419        },
1420        |(_, opt_or_replace, opt_async, _, _, opt_if_not_exists, index_name, _, query)| {
1421            let create_option =
1422                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
1423            Ok(Statement::CreateIndex(CreateIndexStmt {
1424                index_type: TableIndexType::Aggregating,
1425                create_option,
1426                index_name,
1427                query: Box::new(query),
1428                sync_creation: opt_async.is_none(),
1429            }))
1430        },
1431    );
1432
1433    let drop_index = map(
1434        rule! {
1435            DROP ~ AGGREGATING ~ INDEX ~ ( IF ~ ^EXISTS )? ~ #ident
1436        },
1437        |(_, _, _, opt_if_exists, index)| {
1438            Statement::DropIndex(DropIndexStmt {
1439                if_exists: opt_if_exists.is_some(),
1440                index,
1441            })
1442        },
1443    );
1444
1445    let refresh_index = map(
1446        rule! {
1447            REFRESH ~ AGGREGATING ~ INDEX ~ #ident ~ ( LIMIT ~ #literal_u64 )?
1448        },
1449        |(_, _, _, index, opt_limit)| {
1450            Statement::RefreshIndex(RefreshIndexStmt {
1451                index,
1452                limit: opt_limit.map(|(_, limit)| limit),
1453            })
1454        },
1455    );
1456
1457    let create_table_index = map_res(
1458        rule! {
1459            CREATE
1460            ~ ( OR ~ ^REPLACE )?
1461            ~ ASYNC?
1462            ~ #index_type ~ ^INDEX
1463            ~ ( IF ~ ^NOT ~ ^EXISTS )?
1464            ~ #ident
1465            ~ ON ~ #dot_separated_idents_1_to_3
1466            ~ ^"(" ~ ^#comma_separated_list1(ident) ~ ^")"
1467            ~ ( #table_option )?
1468        },
1469        |(
1470            _,
1471            opt_or_replace,
1472            opt_async,
1473            index_type,
1474            _,
1475            opt_if_not_exists,
1476            index_name,
1477            _,
1478            (catalog, database, table),
1479            _,
1480            columns,
1481            _,
1482            opt_index_options,
1483        )| {
1484            let create_option =
1485                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
1486            Ok(Statement::CreateTableIndex(CreateTableIndexStmt {
1487                create_option,
1488                index_name,
1489                index_type,
1490                catalog,
1491                database,
1492                table,
1493                columns,
1494                sync_creation: opt_async.is_none(),
1495                index_options: opt_index_options.unwrap_or_default(),
1496            }))
1497        },
1498    );
1499
1500    let drop_table_index = map(
1501        rule! {
1502            DROP ~ #index_type ~ ^INDEX ~ ( IF ~ ^EXISTS )? ~ #ident
1503            ~ ON ~ #dot_separated_idents_1_to_3
1504        },
1505        |(_, index_type, _, opt_if_exists, index_name, _, (catalog, database, table))| {
1506            Statement::DropTableIndex(DropTableIndexStmt {
1507                if_exists: opt_if_exists.is_some(),
1508                index_name,
1509                index_type,
1510                catalog,
1511                database,
1512                table,
1513            })
1514        },
1515    );
1516
1517    let refresh_table_index = map(
1518        rule! {
1519            REFRESH ~ #index_type ~ ^INDEX ~ #ident ~ ON ~ #dot_separated_idents_1_to_3 ~ ( LIMIT ~ #literal_u64 )?
1520        },
1521        |(_, index_type, _, index_name, _, (catalog, database, table), opt_limit)| {
1522            Statement::RefreshTableIndex(RefreshTableIndexStmt {
1523                index_name,
1524                index_type,
1525                catalog,
1526                database,
1527                table,
1528                limit: opt_limit.map(|(_, limit)| limit),
1529            })
1530        },
1531    );
1532
1533    let refresh_virtual_column = map(
1534        rule! {
1535            REFRESH ~ VIRTUAL ~ COLUMN ~ FOR ~ #dot_separated_idents_1_to_3
1536        },
1537        |(_, _, _, _, (catalog, database, table))| {
1538            Statement::RefreshVirtualColumn(RefreshVirtualColumnStmt {
1539                catalog,
1540                database,
1541                table,
1542            })
1543        },
1544    );
1545
1546    let show_virtual_columns = map(
1547        rule! {
1548            SHOW ~ VIRTUAL ~ COLUMNS ~ ( ( FROM | IN ) ~ #ident )? ~ ( ( FROM | IN ) ~ ^#dot_separated_idents_1_to_2 )? ~ #show_limit?
1549        },
1550        |(_, _, _, opt_table, opt_db, limit)| {
1551            let table = opt_table.map(|(_, table)| table);
1552            let (catalog, database) = match opt_db {
1553                Some((_, (Some(c), d))) => (Some(c), Some(d)),
1554                Some((_, (None, d))) => (None, Some(d)),
1555                _ => (None, None),
1556            };
1557            Statement::ShowVirtualColumns(ShowVirtualColumnsStmt {
1558                catalog,
1559                database,
1560                table,
1561                limit,
1562            })
1563        },
1564    );
1565
1566    let show_users = map(
1567        rule! {
1568            SHOW ~ USERS ~ #show_options?
1569        },
1570        |(_, _, show_options)| Statement::ShowUsers { show_options },
1571    );
1572
1573    let describe_user = map(
1574        rule! {
1575            ( DESC | DESCRIBE ) ~ USER ~ ^#user_identity
1576        },
1577        |(_, _, user)| Statement::DescribeUser { user },
1578    );
1579    let create_user = map_res(
1580        rule! {
1581            CREATE ~  ( OR ~ ^REPLACE )? ~ USER ~ ( IF ~ ^NOT ~ ^EXISTS )?
1582            ~ #user_identity
1583            ~ IDENTIFIED ~ ( WITH ~ ^#auth_type )? ~ ( BY ~ ^#literal_string )?
1584            ~ ( WITH ~ ^#comma_separated_list1(user_option))?
1585        },
1586        |(
1587            _,
1588            opt_or_replace,
1589            _,
1590            opt_if_not_exists,
1591            user,
1592            _,
1593            opt_auth_type,
1594            opt_password,
1595            opt_user_option,
1596        )| {
1597            let create_option =
1598                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
1599            Ok(Statement::CreateUser(CreateUserStmt {
1600                create_option,
1601                user,
1602                auth_option: AuthOption {
1603                    auth_type: opt_auth_type.map(|(_, auth_type)| auth_type),
1604                    password: opt_password.map(|(_, password)| password),
1605                },
1606                user_options: opt_user_option
1607                    .map(|(_, user_options)| user_options)
1608                    .unwrap_or_default(),
1609            }))
1610        },
1611    );
1612    let alter_user = map(
1613        rule! {
1614            ALTER ~ USER ~ ( #map(rule! { USER ~ "(" ~ ")" }, |_| None) | #map(user_identity, Some) )
1615            ~ ( IDENTIFIED ~ ( WITH ~ ^#auth_type )? ~ ( BY ~ ^#literal_string )? )?
1616            ~ ( WITH ~ ^#comma_separated_list1(user_option) )?
1617        },
1618        |(_, _, user, opt_auth_option, opt_user_option)| {
1619            Statement::AlterUser(AlterUserStmt {
1620                user,
1621                auth_option: opt_auth_option.map(|(_, opt_auth_type, opt_password)| AuthOption {
1622                    auth_type: opt_auth_type.map(|(_, auth_type)| auth_type),
1623                    password: opt_password.map(|(_, password)| password),
1624                }),
1625                user_options: opt_user_option
1626                    .map(|(_, user_options)| user_options)
1627                    .unwrap_or_default(),
1628            })
1629        },
1630    );
1631    let drop_user = map(
1632        rule! {
1633            DROP ~ USER ~ ( IF ~ ^EXISTS )? ~ #user_identity
1634        },
1635        |(_, _, opt_if_exists, user)| Statement::DropUser {
1636            if_exists: opt_if_exists.is_some(),
1637            user,
1638        },
1639    );
1640    let show_roles = map(
1641        rule! {
1642            SHOW ~ ROLES ~ #show_options?
1643        },
1644        |(_, _, show_options)| Statement::ShowRoles { show_options },
1645    );
1646    let create_role = map(
1647        rule! {
1648            CREATE ~ ROLE ~ ( IF ~ ^NOT ~ ^EXISTS )? ~ #role_name
1649        },
1650        |(_, _, opt_if_not_exists, role_name)| Statement::CreateRole {
1651            if_not_exists: opt_if_not_exists.is_some(),
1652            role_name,
1653        },
1654    );
1655    let drop_role = map(
1656        rule! {
1657            DROP ~ ROLE ~ ( IF ~ ^EXISTS )? ~ #role_name
1658        },
1659        |(_, _, opt_if_exists, role_name)| Statement::DropRole {
1660            if_exists: opt_if_exists.is_some(),
1661            role_name,
1662        },
1663    );
1664    let grant = map(
1665        rule! {
1666            GRANT ~ #grant_source ~ TO ~ #grant_option
1667        },
1668        |(_, source, _, grant_option)| {
1669            Statement::Grant(GrantStmt {
1670                source,
1671                principal: grant_option,
1672            })
1673        },
1674    );
1675    let grant_ownership = map(
1676        rule! {
1677            GRANT ~ OWNERSHIP ~ ON ~ #grant_ownership_level  ~ TO ~ ROLE ~ #role_name
1678        },
1679        |(_, _, _, level, _, _, role_name)| {
1680            Statement::Grant(GrantStmt {
1681                source: AccountMgrSource::Privs {
1682                    privileges: vec![UserPrivilegeType::Ownership],
1683                    level,
1684                },
1685                principal: PrincipalIdentity::Role(role_name),
1686            })
1687        },
1688    );
1689    let show_grants = map(
1690        rule! {
1691            SHOW ~ GRANTS ~ #show_grant_option? ~ ^#show_options?
1692        },
1693        |(_, _, show_grant_option, opt_limit)| match show_grant_option {
1694            Some(ShowGrantOption::PrincipalIdentity(principal)) => Statement::ShowGrants {
1695                principal: Some(principal),
1696                show_options: opt_limit,
1697            },
1698            None => Statement::ShowGrants {
1699                principal: None,
1700                show_options: opt_limit,
1701            },
1702            Some(ShowGrantOption::GrantObjectName(object)) => {
1703                Statement::ShowObjectPrivileges(ShowObjectPrivilegesStmt {
1704                    object,
1705                    show_option: opt_limit,
1706                })
1707            }
1708            Some(ShowGrantOption::OfRole(name)) => {
1709                Statement::ShowGrantsOfRole(ShowGranteesOfRoleStmt {
1710                    name,
1711                    show_option: opt_limit,
1712                })
1713            }
1714        },
1715    );
1716    let revoke = map(
1717        rule! {
1718            REVOKE ~ #grant_source ~ FROM ~ #grant_option
1719        },
1720        |(_, source, _, grant_option)| {
1721            Statement::Revoke(RevokeStmt {
1722                source,
1723                principal: grant_option,
1724            })
1725        },
1726    );
1727    let create_udf = map_res(
1728        rule! {
1729            CREATE ~ ( OR ~ ^REPLACE )? ~ FUNCTION ~ ( IF ~ ^NOT ~ ^EXISTS )?
1730            ~ #ident ~ #udf_definition
1731            ~ ( DESC ~ ^"=" ~ ^#literal_string )?
1732        },
1733        |(_, opt_or_replace, _, opt_if_not_exists, udf_name, definition, opt_description)| {
1734            let create_option =
1735                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
1736            Ok(Statement::CreateUDF(CreateUDFStmt {
1737                create_option,
1738                udf_name,
1739                description: opt_description.map(|(_, _, description)| description),
1740                definition,
1741            }))
1742        },
1743    );
1744    let drop_udf = map(
1745        rule! {
1746            DROP ~ FUNCTION ~ ( IF ~ ^EXISTS )? ~ #ident
1747        },
1748        |(_, _, opt_if_exists, udf_name)| Statement::DropUDF {
1749            if_exists: opt_if_exists.is_some(),
1750            udf_name,
1751        },
1752    );
1753    let alter_udf = map(
1754        rule! {
1755            ALTER ~ FUNCTION
1756            ~ #ident ~ #udf_definition
1757            ~ ( DESC ~ ^"=" ~ ^#literal_string )?
1758        },
1759        |(_, _, udf_name, definition, opt_description)| {
1760            Statement::AlterUDF(AlterUDFStmt {
1761                udf_name,
1762                description: opt_description.map(|(_, _, description)| description),
1763                definition,
1764            })
1765        },
1766    );
1767
1768    // stages
1769    let create_stage = map_res(
1770        rule! {
1771            CREATE ~ ( OR ~ ^REPLACE )? ~ STAGE ~ ( IF ~ ^NOT ~ ^EXISTS )?
1772            ~ ( #stage_name )
1773            ~ ( (URL ~ ^"=")? ~ #uri_location )?
1774            ~ ( #file_format_clause )?
1775            ~ ( (COMMENT | COMMENTS) ~ ^"=" ~ ^#literal_string )?
1776        },
1777        |(
1778            _,
1779            opt_or_replace,
1780            _,
1781            opt_if_not_exists,
1782            stage,
1783            url_opt,
1784            file_format_opt,
1785            comment_opt,
1786        )| {
1787            let create_option =
1788                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
1789            Ok(Statement::CreateStage(CreateStageStmt {
1790                create_option,
1791                stage_name: stage.to_string(),
1792                location: url_opt.map(|(_, location)| location),
1793                file_format_options: file_format_opt.unwrap_or_default(),
1794                comments: comment_opt.map(|v| v.2).unwrap_or_default(),
1795            }))
1796        },
1797    );
1798
1799    let list_stage = map(
1800        rule! {
1801            LIST ~ #at_string ~ (PATTERN ~ "=" ~ #literal_string)?
1802        },
1803        |(_, location, opt_pattern)| Statement::ListStage {
1804            location,
1805            pattern: opt_pattern.map(|v| v.2),
1806        },
1807    );
1808
1809    let remove_stage = map(
1810        rule! {
1811            REMOVE ~ #at_string ~ (PATTERN ~ "=" ~ #literal_string)?
1812        },
1813        |(_, location, opt_pattern)| Statement::RemoveStage {
1814            location,
1815            pattern: opt_pattern.map(|v| v.2).unwrap_or_default(),
1816        },
1817    );
1818
1819    let drop_stage = map(
1820        rule! {
1821            DROP ~ STAGE ~ ( IF ~ ^EXISTS )? ~ #stage_name
1822        },
1823        |(_, _, opt_if_exists, stage_name)| Statement::DropStage {
1824            if_exists: opt_if_exists.is_some(),
1825            stage_name: stage_name.to_string(),
1826        },
1827    );
1828
1829    let desc_stage = map(
1830        rule! {
1831            (DESC | DESCRIBE) ~ STAGE ~ #ident
1832        },
1833        |(_, _, stage_name)| Statement::DescribeStage {
1834            stage_name: stage_name.to_string(),
1835        },
1836    );
1837
1838    // connections
1839    let connection_opt = connection_opt("=");
1840    let create_connection = map_res(
1841        rule! {
1842            CREATE ~ ( OR ~ ^REPLACE )? ~ CONNECTION ~ ( IF ~ ^NOT ~ ^EXISTS )?
1843            ~ #ident ~ STORAGE_TYPE ~ "=" ~  #literal_string ~ #connection_opt*
1844        },
1845        |(
1846            _,
1847            opt_or_replace,
1848            _,
1849            opt_if_not_exists,
1850            connection_name,
1851            _,
1852            _,
1853            storage_type,
1854            options,
1855        )| {
1856            let create_option =
1857                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
1858            let options =
1859                BTreeMap::from_iter(options.iter().map(|(k, v)| (k.to_lowercase(), v.clone())));
1860            Ok(Statement::CreateConnection(CreateConnectionStmt {
1861                create_option,
1862                name: connection_name,
1863                storage_type,
1864                storage_params: options,
1865            }))
1866        },
1867    );
1868
1869    let drop_connection = map(
1870        rule! {
1871            DROP ~ CONNECTION ~ ( IF ~ ^EXISTS )? ~ #ident
1872        },
1873        |(_, _, opt_if_exists, connection_name)| {
1874            Statement::DropConnection(DropConnectionStmt {
1875                if_exists: opt_if_exists.is_some(),
1876                name: connection_name,
1877            })
1878        },
1879    );
1880
1881    let desc_connection = map(
1882        rule! {
1883            (DESC | DESCRIBE) ~ CONNECTION ~ #ident
1884        },
1885        |(_, _, name)| Statement::DescribeConnection(DescribeConnectionStmt { name }),
1886    );
1887
1888    let show_connections = map(
1889        rule! {
1890            SHOW ~ CONNECTIONS
1891        },
1892        |(_, _)| Statement::ShowConnections(ShowConnectionsStmt {}),
1893    );
1894
1895    let call = map(
1896        rule! {
1897            CALL ~ #ident ~ "(" ~ #comma_separated_list0(parameter_to_string) ~ ")"
1898        },
1899        |(_, name, _, args, _)| {
1900            Statement::Call(CallStmt {
1901                name: name.to_string(),
1902                args,
1903            })
1904        },
1905    );
1906
1907    let vacuum_temporary_tables = map(
1908        rule! {
1909            VACUUM ~ TEMPORARY ~ TABLES ~ ( LIMIT ~ ^#literal_u64 )?
1910        },
1911        |(_, _, _, opt_limit)| {
1912            Statement::Call(CallStmt {
1913                name: "fuse_vacuum_temporary_table".to_string(),
1914                args: opt_limit.map(|v| v.1.to_string()).into_iter().collect(),
1915            })
1916        },
1917    );
1918
1919    let presign = map(
1920        rule! {
1921            PRESIGN ~ ( #presign_action )?
1922                ~ #presign_location
1923                ~ ( #presign_option )*
1924        },
1925        |(_, action, location, opts)| {
1926            let mut presign_stmt = PresignStmt {
1927                action: action.unwrap_or_default(),
1928                location,
1929                expire: Duration::from_secs(3600),
1930                content_type: None,
1931            };
1932            for opt in opts {
1933                presign_stmt.apply_option(opt);
1934            }
1935            Statement::Presign(presign_stmt)
1936        },
1937    );
1938
1939    let create_file_format = map_res(
1940        rule! {
1941            CREATE ~ ( OR ~ ^REPLACE )? ~ FILE ~ FORMAT ~ ( IF ~ ^NOT ~ ^EXISTS )?
1942            ~ #ident ~ #format_options
1943        },
1944        |(_, opt_or_replace, _, _, opt_if_not_exists, name, file_format_options)| {
1945            let create_option =
1946                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
1947            Ok(Statement::CreateFileFormat {
1948                create_option,
1949                name: name.to_string(),
1950                file_format_options,
1951            })
1952        },
1953    );
1954
1955    let drop_file_format = map(
1956        rule! {
1957            DROP ~ FILE ~ FORMAT ~ ( IF ~  EXISTS )? ~ #ident
1958        },
1959        |(_, _, _, opt_if_exists, name)| Statement::DropFileFormat {
1960            if_exists: opt_if_exists.is_some(),
1961            name: name.to_string(),
1962        },
1963    );
1964
1965    let show_file_formats = value(Statement::ShowFileFormats, rule! { SHOW ~ FILE ~ FORMATS });
1966
1967    // data mark policy
1968    let create_data_mask_policy = map_res(
1969        rule! {
1970            CREATE ~ ( OR ~ ^REPLACE )? ~ MASKING ~ POLICY ~ ( IF ~ ^NOT ~ ^EXISTS )? ~ #ident ~ #data_mask_policy
1971        },
1972        |(_, opt_or_replace, _, _, opt_if_not_exists, name, policy)| {
1973            let create_option =
1974                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
1975            let stmt = CreateDatamaskPolicyStmt {
1976                create_option,
1977                name: name.to_string(),
1978                policy,
1979            };
1980            Ok(Statement::CreateDatamaskPolicy(stmt))
1981        },
1982    );
1983    let drop_data_mask_policy = map(
1984        rule! {
1985            DROP ~ MASKING ~ POLICY ~ ( IF ~ ^EXISTS )? ~ #ident
1986        },
1987        |(_, _, _, opt_if_exists, name)| {
1988            let stmt = DropDatamaskPolicyStmt {
1989                if_exists: opt_if_exists.is_some(),
1990                name: name.to_string(),
1991            };
1992            Statement::DropDatamaskPolicy(stmt)
1993        },
1994    );
1995    let describe_data_mask_policy = map(
1996        rule! {
1997            ( DESC | DESCRIBE ) ~ MASKING ~ POLICY ~ #ident
1998        },
1999        |(_, _, _, name)| {
2000            Statement::DescDatamaskPolicy(DescDatamaskPolicyStmt {
2001                name: name.to_string(),
2002            })
2003        },
2004    );
2005
2006    let create_network_policy = map_res(
2007        rule! {
2008            CREATE ~  ( OR ~ ^REPLACE )? ~ NETWORK ~ ^POLICY ~ ( IF ~ ^NOT ~ ^EXISTS )? ~ ^#ident
2009             ~ ALLOWED_IP_LIST ~ ^Eq ~ ^"(" ~ ^#comma_separated_list0(literal_string) ~ ^")"
2010             ~ ( BLOCKED_IP_LIST ~ ^Eq ~ ^"(" ~ ^#comma_separated_list0(literal_string) ~ ^")" ) ?
2011             ~ ( COMMENT ~ ^Eq ~ ^#literal_string)?
2012        },
2013        |(
2014            _,
2015            opt_or_replace,
2016            _,
2017            _,
2018            opt_if_not_exists,
2019            name,
2020            _,
2021            _,
2022            _,
2023            allowed_ip_list,
2024            _,
2025            opt_blocked_ip_list,
2026            opt_comment,
2027        )| {
2028            let create_option =
2029                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
2030            let stmt = CreateNetworkPolicyStmt {
2031                create_option,
2032                name: name.to_string(),
2033                allowed_ip_list,
2034                blocked_ip_list: match opt_blocked_ip_list {
2035                    Some(opt) => Some(opt.3),
2036                    None => None,
2037                },
2038                comment: match opt_comment {
2039                    Some(opt) => Some(opt.2),
2040                    None => None,
2041                },
2042            };
2043            Ok(Statement::CreateNetworkPolicy(stmt))
2044        },
2045    );
2046    let alter_network_policy = map(
2047        rule! {
2048            ALTER ~ NETWORK ~ ^POLICY ~ ( IF ~ ^EXISTS )? ~ ^#ident ~ SET
2049             ~ ( ALLOWED_IP_LIST ~ ^Eq ~ ^"(" ~ ^#comma_separated_list0(literal_string) ~ ^")" ) ?
2050             ~ ( BLOCKED_IP_LIST ~ ^Eq ~ ^"(" ~ ^#comma_separated_list0(literal_string) ~ ^")" ) ?
2051             ~ ( COMMENT ~ ^Eq ~ ^#literal_string)?
2052        },
2053        |(
2054            _,
2055            _,
2056            _,
2057            opt_if_exists,
2058            name,
2059            _,
2060            opt_allowed_ip_list,
2061            opt_blocked_ip_list,
2062            opt_comment,
2063        )| {
2064            let stmt = AlterNetworkPolicyStmt {
2065                if_exists: opt_if_exists.is_some(),
2066                name: name.to_string(),
2067                allowed_ip_list: match opt_allowed_ip_list {
2068                    Some(opt) => Some(opt.3),
2069                    None => None,
2070                },
2071                blocked_ip_list: match opt_blocked_ip_list {
2072                    Some(opt) => Some(opt.3),
2073                    None => None,
2074                },
2075                comment: match opt_comment {
2076                    Some(opt) => Some(opt.2),
2077                    None => None,
2078                },
2079            };
2080            Statement::AlterNetworkPolicy(stmt)
2081        },
2082    );
2083    let drop_network_policy = map(
2084        rule! {
2085            DROP ~ NETWORK ~ ^POLICY ~ ( IF ~ ^EXISTS )? ~ ^#ident
2086        },
2087        |(_, _, _, opt_if_exists, name)| {
2088            let stmt = DropNetworkPolicyStmt {
2089                if_exists: opt_if_exists.is_some(),
2090                name: name.to_string(),
2091            };
2092            Statement::DropNetworkPolicy(stmt)
2093        },
2094    );
2095    let describe_network_policy = map(
2096        rule! {
2097            ( DESC | DESCRIBE ) ~ NETWORK ~ ^POLICY ~ ^#ident
2098        },
2099        |(_, _, _, name)| {
2100            Statement::DescNetworkPolicy(DescNetworkPolicyStmt {
2101                name: name.to_string(),
2102            })
2103        },
2104    );
2105    let show_network_policies = value(
2106        Statement::ShowNetworkPolicies,
2107        rule! { SHOW ~ NETWORK ~ ^POLICIES },
2108    );
2109
2110    let create_password_policy = map_res(
2111        rule! {
2112            CREATE ~ ( OR ~ ^REPLACE )? ~ PASSWORD ~ ^POLICY ~ ( IF ~ ^NOT ~ ^EXISTS )? ~ ^#ident
2113             ~ #password_set_options
2114        },
2115        |(_, opt_or_replace, _, _, opt_if_not_exists, name, set_options)| {
2116            let create_option =
2117                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
2118            let stmt = CreatePasswordPolicyStmt {
2119                create_option,
2120                name: name.to_string(),
2121                set_options,
2122            };
2123            Ok(Statement::CreatePasswordPolicy(stmt))
2124        },
2125    );
2126    let alter_password_policy = map(
2127        rule! {
2128            ALTER ~ PASSWORD ~ ^POLICY ~ ( IF ~ ^EXISTS )? ~ ^#ident
2129             ~ #alter_password_action
2130        },
2131        |(_, _, _, opt_if_exists, name, action)| {
2132            let stmt = AlterPasswordPolicyStmt {
2133                if_exists: opt_if_exists.is_some(),
2134                name: name.to_string(),
2135                action,
2136            };
2137            Statement::AlterPasswordPolicy(stmt)
2138        },
2139    );
2140    let drop_password_policy = map(
2141        rule! {
2142            DROP ~ PASSWORD ~ ^POLICY ~ ( IF ~ ^EXISTS )? ~ ^#ident
2143        },
2144        |(_, _, _, opt_if_exists, name)| {
2145            let stmt = DropPasswordPolicyStmt {
2146                if_exists: opt_if_exists.is_some(),
2147                name: name.to_string(),
2148            };
2149            Statement::DropPasswordPolicy(stmt)
2150        },
2151    );
2152    let describe_password_policy = map(
2153        rule! {
2154            ( DESC | DESCRIBE ) ~ PASSWORD ~ ^POLICY ~ ^#ident
2155        },
2156        |(_, _, _, name)| {
2157            Statement::DescPasswordPolicy(DescPasswordPolicyStmt {
2158                name: name.to_string(),
2159            })
2160        },
2161    );
2162    let show_password_policies = map(
2163        rule! {
2164            SHOW ~ PASSWORD ~ ^POLICIES ~ ^#show_options?
2165        },
2166        |(_, _, _, show_options)| Statement::ShowPasswordPolicies { show_options },
2167    );
2168
2169    let create_pipe = map(
2170        rule! {
2171            CREATE ~ PIPE ~ ( IF ~ ^NOT ~ ^EXISTS )?
2172            ~ #ident
2173            ~ ( AUTO_INGEST ~ "=" ~ #literal_bool )?
2174            ~ ( (COMMENT | COMMENTS) ~ ^"=" ~ ^#literal_string )?
2175            ~ AS ~ #copy_into_table
2176        },
2177        |(_, _, opt_if_not_exists, pipe, ingest, comment_opt, _, copy_stmt)| {
2178            let copy_stmt = match copy_stmt {
2179                Statement::CopyIntoTable(stmt) => stmt,
2180                _ => {
2181                    unreachable!()
2182                }
2183            };
2184            Statement::CreatePipe(CreatePipeStmt {
2185                if_not_exists: opt_if_not_exists.is_some(),
2186                name: pipe.to_string(),
2187                auto_ingest: ingest.map(|v| v.2).unwrap_or_default(),
2188                comments: comment_opt.map(|v| v.2).unwrap_or_default(),
2189                copy_stmt,
2190            })
2191        },
2192    );
2193
2194    let alter_pipe = map(
2195        rule! {
2196            ALTER ~ PIPE ~ ( IF ~ ^EXISTS )?
2197            ~ #ident ~ #alter_pipe_option
2198        },
2199        |(_, _, opt_if_exists, task, options)| {
2200            Statement::AlterPipe(AlterPipeStmt {
2201                if_exists: opt_if_exists.is_some(),
2202                name: task.to_string(),
2203                options,
2204            })
2205        },
2206    );
2207
2208    let drop_pipe = map(
2209        rule! {
2210            DROP ~ PIPE ~ ( IF ~ ^EXISTS )?
2211            ~ #ident
2212        },
2213        |(_, _, opt_if_exists, task)| {
2214            Statement::DropPipe(DropPipeStmt {
2215                if_exists: opt_if_exists.is_some(),
2216                name: task.to_string(),
2217            })
2218        },
2219    );
2220
2221    let desc_pipe = map(
2222        rule! {
2223            ( DESC | DESCRIBE ) ~ PIPE ~ #ident
2224        },
2225        |(_, _, task)| {
2226            Statement::DescribePipe(DescribePipeStmt {
2227                name: task.to_string(),
2228            })
2229        },
2230    );
2231    let create_notification = map(
2232        rule! {
2233            CREATE ~ NOTIFICATION ~ INTEGRATION
2234            ~ ( IF ~ ^NOT ~ ^EXISTS )?
2235            ~ #ident
2236            ~ TYPE ~ "=" ~ #ident
2237            ~ ENABLED ~ "=" ~ #literal_bool
2238            ~ #notification_webhook_clause?
2239            ~ ( (COMMENT | COMMENTS) ~ ^"=" ~ ^#literal_string )?
2240        },
2241        |(
2242            _,
2243            _,
2244            _,
2245            if_not_exists,
2246            name,
2247            _,
2248            _,
2249            notification_type,
2250            _,
2251            _,
2252            enabled,
2253            webhook,
2254            comment,
2255        )| {
2256            Statement::CreateNotification(CreateNotificationStmt {
2257                if_not_exists: if_not_exists.is_some(),
2258                name: name.to_string(),
2259                notification_type: notification_type.to_string(),
2260                enabled,
2261                webhook_opts: webhook,
2262                comments: comment.map(|(_, _, comments)| comments),
2263            })
2264        },
2265    );
2266
2267    let drop_notification = map(
2268        rule! {
2269            DROP ~ NOTIFICATION ~ INTEGRATION ~ ( IF ~ ^EXISTS )?
2270            ~ #ident
2271        },
2272        |(_, _, _, if_exists, name)| {
2273            Statement::DropNotification(DropNotificationStmt {
2274                if_exists: if_exists.is_some(),
2275                name: name.to_string(),
2276            })
2277        },
2278    );
2279
2280    let alter_notification = map(
2281        rule! {
2282            ALTER ~ NOTIFICATION ~ INTEGRATION ~ ( IF ~ ^EXISTS )?
2283            ~ #ident
2284            ~ #alter_notification_options
2285        },
2286        |(_, _, _, if_exists, name, options)| {
2287            Statement::AlterNotification(AlterNotificationStmt {
2288                if_exists: if_exists.is_some(),
2289                name: name.to_string(),
2290                options,
2291            })
2292        },
2293    );
2294
2295    let desc_notification = map(
2296        rule! {
2297            ( DESC | DESCRIBE ) ~ NOTIFICATION ~ INTEGRATION ~ #ident
2298        },
2299        |(_, _, _, name)| {
2300            Statement::DescribeNotification(DescribeNotificationStmt {
2301                name: name.to_string(),
2302            })
2303        },
2304    );
2305
2306    let begin = value(Statement::Begin, rule! { BEGIN ~ TRANSACTION? });
2307    let commit = value(Statement::Commit, rule! { COMMIT });
2308    let abort = value(Statement::Abort, rule! { ABORT | ROLLBACK });
2309
2310    let execute_immediate = map(
2311        rule! {
2312            EXECUTE ~ IMMEDIATE ~ #code_string
2313        },
2314        |(_, _, script)| Statement::ExecuteImmediate(ExecuteImmediateStmt { script }),
2315    );
2316
2317    let system_action = map(
2318        rule! {
2319            SYSTEM ~ #action
2320        },
2321        |(_, action)| Statement::System(SystemStmt { action }),
2322    );
2323
2324    pub fn procedure_type(i: Input) -> IResult<ProcedureType> {
2325        map(rule! { #ident ~ #type_name }, |(name, data_type)| {
2326            ProcedureType {
2327                name: Some(name.to_string()),
2328                data_type,
2329            }
2330        })(i)
2331    }
2332
2333    fn procedure_return(i: Input) -> IResult<Vec<ProcedureType>> {
2334        let procedure_table_return = map(
2335            rule! {
2336                TABLE ~ "(" ~ #comma_separated_list1(procedure_type) ~ ")"
2337            },
2338            |(_, _, test, _)| test,
2339        );
2340        let procedure_single_return = map(rule! { #type_name }, |data_type| {
2341            vec![ProcedureType {
2342                name: None,
2343                data_type,
2344            }]
2345        });
2346        rule!(#procedure_single_return: "<type_name>"
2347            | #procedure_table_return: "TABLE(<var_name> <type_name>, ...)")(i)
2348    }
2349
2350    fn procedure_arg(i: Input) -> IResult<Option<Vec<ProcedureType>>> {
2351        let procedure_args = map(
2352            rule! {
2353                "(" ~ #comma_separated_list1(procedure_type) ~ ")"
2354            },
2355            |(_, args, _)| Some(args),
2356        );
2357        let procedure_empty_args = map(
2358            rule! {
2359                "(" ~ ")"
2360            },
2361            |(_, _)| None,
2362        );
2363        rule!(#procedure_empty_args: "()"
2364            | #procedure_args: "(<var_name> <type_name>, ...)")(i)
2365    }
2366
2367    // CREATE [ OR REPLACE ] PROCEDURE <name> ()
2368    // RETURNS { <result_data_type> }[ NOT NULL ]
2369    // LANGUAGE SQL
2370    // [ COMMENT = '<string_literal>' ] AS <procedure_definition>
2371    let create_procedure = map_res(
2372        rule! {
2373            CREATE ~ ( OR ~ ^REPLACE )? ~ PROCEDURE ~ ( IF ~ ^NOT ~ ^EXISTS )? ~ #ident ~ #procedure_arg ~ RETURNS ~ #procedure_return ~ LANGUAGE ~ SQL  ~ (COMMENT ~ "=" ~ #literal_string)? ~ AS ~ #code_string
2374        },
2375        |(
2376            _,
2377            opt_or_replace,
2378            _,
2379            opt_if_not_exists,
2380            name,
2381            args,
2382            _,
2383            return_type,
2384            _,
2385            _,
2386            opt_comment,
2387            _,
2388            script,
2389        )| {
2390            let create_option =
2391                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
2392
2393            let name = ProcedureIdentity {
2394                name: name.to_string(),
2395                args_type: if let Some(args) = &args {
2396                    args.iter()
2397                        .map(|arg| arg.data_type.to_string())
2398                        .collect::<Vec<String>>()
2399                        .join(",")
2400                } else {
2401                    "".to_string()
2402                },
2403            };
2404            let stmt = CreateProcedureStmt {
2405                create_option,
2406                name,
2407                args,
2408                return_type,
2409                language: ProcedureLanguage::SQL,
2410                comment: match opt_comment {
2411                    Some(opt) => Some(opt.2),
2412                    None => None,
2413                },
2414                script,
2415            };
2416            Ok(Statement::CreateProcedure(stmt))
2417        },
2418    );
2419
2420    let show_procedures = map(
2421        rule! {
2422            SHOW ~ PROCEDURES ~ #show_options?
2423        },
2424        |(_, _, show_options)| Statement::ShowProcedures { show_options },
2425    );
2426
2427    fn procedure_type_name(i: Input) -> IResult<Vec<TypeName>> {
2428        let procedure_type_names = map(
2429            rule! {
2430                "(" ~ #comma_separated_list1(type_name) ~ ")"
2431            },
2432            |(_, args, _)| args,
2433        );
2434        let procedure_empty_types = map(
2435            rule! {
2436                "(" ~ ")"
2437            },
2438            |(_, _)| vec![],
2439        );
2440        rule!(#procedure_empty_types: "()"
2441            | #procedure_type_names: "(<type_name>, ...)")(i)
2442    }
2443
2444    let call_procedure = map(
2445        rule! {
2446            CALL ~ PROCEDURE ~ #ident ~ "(" ~ #comma_separated_list0(subexpr(0))? ~ ")"
2447        },
2448        |(_, _, name, _, opt_args, _)| {
2449            Statement::CallProcedure(CallProcedureStmt {
2450                name: name.to_string(),
2451                args: opt_args.unwrap_or_default(),
2452            })
2453        },
2454    );
2455
2456    let drop_procedure = map(
2457        rule! {
2458            DROP ~ PROCEDURE ~ ( IF ~ ^EXISTS )? ~ #ident ~ #procedure_type_name
2459        },
2460        |(_, _, opt_if_exists, name, args)| {
2461            Statement::DropProcedure(DropProcedureStmt {
2462                if_exists: opt_if_exists.is_some(),
2463                name: ProcedureIdentity {
2464                    name: name.to_string(),
2465                    args_type: if args.is_empty() {
2466                        "".to_string()
2467                    } else {
2468                        args.iter()
2469                            .map(|arg| arg.to_string())
2470                            .collect::<Vec<String>>()
2471                            .join(",")
2472                    },
2473                },
2474            })
2475        },
2476    );
2477
2478    let describe_procedure = map(
2479        rule! {
2480            ( DESC | DESCRIBE ) ~ PROCEDURE ~ #ident ~ #procedure_type_name
2481        },
2482        |(_, _, name, args)| {
2483            Statement::DescProcedure(DescProcedureStmt {
2484                name: ProcedureIdentity {
2485                    name: name.to_string(),
2486                    args_type: if args.is_empty() {
2487                        "".to_string()
2488                    } else {
2489                        args.iter()
2490                            .map(|arg| arg.to_string())
2491                            .collect::<Vec<String>>()
2492                            .join(",")
2493                    },
2494                },
2495            })
2496        },
2497    );
2498
2499    alt((
2500        // query, explain, report, show
2501        rule!(
2502            #map(query, |query| Statement::Query(Box::new(query)))
2503            | #explain : "`EXPLAIN [PIPELINE | GRAPH] <statement>`"
2504            | #explain_analyze : "`EXPLAIN ANALYZE <statement>`"
2505            | #report: "`REPORT ISSUE <statement>`"
2506            | #show_settings : "`SHOW SETTINGS [<show_limit>]`"
2507            | #show_variables : "`SHOW VARIABLES [<show_limit>]`"
2508            | #show_stages : "`SHOW STAGES`"
2509            | #show_engines : "`SHOW ENGINES`"
2510            | #show_process_list : "`SHOW PROCESSLIST`"
2511            | #show_metrics : "`SHOW METRICS`"
2512            | #show_functions : "`SHOW FUNCTIONS [<show_limit>]`"
2513            | #show_indexes : "`SHOW INDEXES`"
2514            | #show_locks : "`SHOW LOCKS [IN ACCOUNT] [WHERE ...]`"
2515            | #kill_stmt : "`KILL (QUERY | CONNECTION) <object_id>`"
2516            | #vacuum_temp_files : "VACUUM TEMPORARY FILES [RETAIN number SECONDS|DAYS] [LIMIT number]"
2517            | #set_priority: "`SET PRIORITY (HIGH | MEDIUM | LOW) <object_id>`"
2518            | #system_action: "`SYSTEM (ENABLE | DISABLE) EXCEPTION_BACKTRACE`"
2519        ),
2520        // use
2521        rule!(
2522                #use_catalog: "`USE CATALOG <catalog>`"
2523                | #use_warehouse: "`USE WAREHOUSE <warehouse>`"
2524                | #use_database : "`USE <database>`"
2525        ),
2526        // warehouse
2527        rule!(
2528            #show_warehouses: "`SHOW WAREHOUSES`"
2529            | #show_online_nodes: "`SHOW ONLINE NODES`"
2530            | #create_warehouse: "`CREATE WAREHOUSE <warehouse> [(ASSIGN <node_size> NODES [FROM <node_group>] [, ...])] WITH [warehouse_size = <warehouse_size>]`"
2531            | #drop_warehouse: "`DROP WAREHOUSE <warehouse>`"
2532            | #rename_warehouse: "`RENAME WAREHOUSE <warehouse> TO <new_warehouse>`"
2533            | #resume_warehouse: "`RESUME WAREHOUSE <warehouse>`"
2534            | #suspend_warehouse: "`SUSPEND WAREHOUSE <warehouse>`"
2535            | #inspect_warehouse: "`INSPECT WAREHOUSE <warehouse>`"
2536            | #add_warehouse_cluster: "`ALTER WAREHOUSE <warehouse> ADD CLUSTER <cluster> [(ASSIGN <node_size> NODES [FROM <node_group>] [, ...])] WITH [cluster_size = <cluster_size>]`"
2537            | #drop_warehouse_cluster: "`ALTER WAREHOUSE <warehouse> DROP CLUSTER <cluster>`"
2538            | #rename_warehouse_cluster: "`ALTER WAREHOUSE <warehouse> RENAME CLUSTER <cluster> TO <new_cluster>`"
2539            | #assign_warehouse_nodes: "`ALTER WAREHOUSE <warehouse> ASSIGN NODES ( ASSIGN <node_size> NODES [FROM <node_group>] FOR <cluster> [, ...] )`"
2540            | #unassign_warehouse_nodes: "`ALTER WAREHOUSE <warehouse> UNASSIGN NODES ( UNASSIGN <node_size> NODES [FROM <node_group>] FOR <cluster> [, ...] )`"
2541        ),
2542        // workload group
2543        rule!(
2544            #show_workload_groups: "`SHOW WORKLOAD GROUPS`"
2545            | #create_workload_group: "`CREATE WORKLOAD GROUP [IF NOT EXISTS] <name> WITH [<workload_group_quotas>]`"
2546            | #drop_workload_group: "`DROP WORKLOAD GROUP [IF EXISTS] <name>`"
2547            | #rename_workload_group: "`RENAME WORKLOAD GROUP <old_name> TO <new_name>`"
2548            | #set_workload_group_quotas: "`ALTER WORKLOAD GROUP <name> SET [<workload_group_quotas>]`"
2549            | #unset_workload_group_quotas: "`ALTER WORKLOAD GROUP <name> UNSET {<name> | (<name>, ...)}`"
2550        ),
2551        // database
2552        rule!(
2553            #show_databases : "`SHOW [FULL] DATABASES [(FROM | IN) <catalog>] [<show_limit>]`"
2554            | #undrop_database : "`UNDROP DATABASE <database>`"
2555            | #show_create_database : "`SHOW CREATE DATABASE <database>`"
2556            | #show_drop_databases : "`SHOW DROP DATABASES [FROM <database>] [<show_limit>]`"
2557            | #create_database : "`CREATE [OR REPLACE] DATABASE [IF NOT EXISTS] <database> [ENGINE = <engine>]`"
2558            | #drop_database : "`DROP DATABASE [IF EXISTS] <database>`"
2559            | #alter_database : "`ALTER DATABASE [IF EXISTS] <action>`"
2560        ),
2561        // network policy / password policy
2562        rule!(
2563            #create_network_policy: "`CREATE NETWORK POLICY [IF NOT EXISTS] name ALLOWED_IP_LIST = ('ip1' [, 'ip2']) [BLOCKED_IP_LIST = ('ip1' [, 'ip2'])] [COMMENT = '<string_literal>']`"
2564            | #alter_network_policy: "`ALTER NETWORK POLICY [IF EXISTS] name SET [ALLOWED_IP_LIST = ('ip1' [, 'ip2'])] [BLOCKED_IP_LIST = ('ip1' [, 'ip2'])] [COMMENT = '<string_literal>']`"
2565            | #drop_network_policy: "`DROP NETWORK POLICY [IF EXISTS] name`"
2566            | #describe_network_policy: "`DESC NETWORK POLICY name`"
2567            | #show_network_policies: "`SHOW NETWORK POLICIES`"
2568            | #create_password_policy: "`CREATE PASSWORD POLICY [IF NOT EXISTS] name [PASSWORD_MIN_LENGTH = <u64_literal>] ... [COMMENT = '<string_literal>']`"
2569            | #alter_password_policy: "`ALTER PASSWORD POLICY [IF EXISTS] name SET [PASSWORD_MIN_LENGTH = <u64_literal>] ... [COMMENT = '<string_literal>']`"
2570            | #drop_password_policy: "`DROP PASSWORD POLICY [IF EXISTS] name`"
2571            | #describe_password_policy: "`DESC PASSWORD POLICY name`"
2572            | #show_password_policies: "`SHOW PASSWORD POLICIES [<show_options>]`"
2573        ),
2574        rule!(
2575            #conditional_multi_table_insert() : "`INSERT [OVERWRITE] {FIRST|ALL} { WHEN <condition> THEN intoClause [ ... ] } [ ... ] [ ELSE intoClause ] <subquery>`"
2576            | #unconditional_multi_table_insert() : "`INSERT [OVERWRITE] ALL intoClause [ ... ] <subquery>`"
2577            | #insert_stmt(false, false) : "`INSERT INTO [TABLE] <table> [(<column>, ...)] (VALUES <values> | <query>)`"
2578            | #replace_stmt(false) : "`REPLACE INTO [TABLE] <table> [(<column>, ...)] (FORMAT <format> | VALUES <values> | <query>)`"
2579            | #merge : "`MERGE INTO <target_table> USING <source> ON <join_expr> { matchedClause | notMatchedClause } [ ... ]`"
2580            | #delete : "`DELETE FROM <table> [WHERE ...]`"
2581            | #update : "`UPDATE <table> SET <column> = <expr> [, <column> = <expr> , ... ] [WHERE ...]`"
2582            | #begin
2583            | #commit
2584            | #abort
2585        ),
2586        rule!(
2587            #show_users : "`SHOW USERS`"
2588            | #describe_user: "`DESCRIBE USER <user_name>`"
2589            | #create_user : "`CREATE [OR REPLACE] USER [IF NOT EXISTS] '<username>' IDENTIFIED [WITH <auth_type>] [BY <password>] [WITH <user_option>, ...]`"
2590            | #alter_user : "`ALTER USER ('<username>' | USER()) [IDENTIFIED [WITH <auth_type>] [BY <password>]] [WITH <user_option>, ...]`"
2591            | #drop_user : "`DROP USER [IF EXISTS] '<username>'`"
2592            | #show_roles : "`SHOW ROLES`"
2593            | #create_role : "`CREATE ROLE [IF NOT EXISTS] <role_name>`"
2594            | #drop_role : "`DROP ROLE [IF EXISTS] <role_name>`"
2595            | #create_udf : "`CREATE [OR REPLACE] FUNCTION [IF NOT EXISTS] <udf_name> <udf_definition> [DESC = <description>]`"
2596            | #drop_udf : "`DROP FUNCTION [IF EXISTS] <udf_name>`"
2597            | #alter_udf : "`ALTER FUNCTION <udf_name> <udf_definition> [DESC = <description>]`"
2598            | #set_role: "`SET [DEFAULT] ROLE <role>`"
2599            | #set_secondary_roles: "`SET SECONDARY ROLES (ALL | NONE)`"
2600            | #set_secondary_specify_roles: "`SET SECONDARY ROLES [role_name,...]`"
2601            | #show_user_functions : "`SHOW USER FUNCTIONS [<show_limit>]`"
2602        ),
2603        rule!(
2604            #show_tables : "`SHOW [FULL] TABLES [FROM <database>] [<show_limit>]`"
2605            | #show_columns : "`SHOW [FULL] COLUMNS FROM <table> [FROM|IN <catalog>.<database>] [<show_limit>]`"
2606            | #show_create_table : "`SHOW CREATE TABLE [<database>.]<table>`"
2607            | #describe_view : "`DESCRIBE VIEW [<database>.]<view>`"
2608            | #describe_table : "`DESCRIBE [<database>.]<table>`"
2609            | #show_fields : "`SHOW FIELDS FROM [<database>.]<table>`"
2610            | #show_tables_status : "`SHOW TABLES STATUS [FROM <database>] [<show_limit>]`"
2611            | #show_drop_tables_status : "`SHOW DROP TABLES [FROM <database>]`"
2612            | #attach_table : "`ATTACH TABLE [<database>.]<table> <uri>`"
2613            | #create_table : "`CREATE [OR REPLACE] TABLE [IF NOT EXISTS] [<database>.]<table> [<source>] [<table_options>]`"
2614            | #drop_table : "`DROP TABLE [IF EXISTS] [<database>.]<table>`"
2615            | #undrop_table : "`UNDROP TABLE [<database>.]<table>`"
2616            | #alter_table : "`ALTER TABLE [<database>.]<table> <action>`"
2617            | #rename_table : "`RENAME TABLE [<database>.]<table> TO <new_table>`"
2618            | #truncate_table : "`TRUNCATE TABLE [<database>.]<table>`"
2619            | #optimize_table : "`OPTIMIZE TABLE [<database>.]<table> (ALL | PURGE | COMPACT [SEGMENT])`"
2620            | #vacuum_table : "`VACUUM TABLE [<database>.]<table> [RETAIN number HOURS] [DRY RUN | DRY RUN SUMMARY]`"
2621            | #vacuum_drop_table : "`VACUUM DROP TABLE [FROM [<catalog>.]<database>] [RETAIN number HOURS] [DRY RUN | DRY RUN SUMMARY]`"
2622            | #analyze_table : "`ANALYZE TABLE [<database>.]<table>`"
2623            | #exists_table : "`EXISTS TABLE [<database>.]<table>`"
2624            | #show_table_functions : "`SHOW TABLE_FUNCTIONS [<show_limit>]`"
2625        ),
2626        // dictionary
2627        rule!(
2628            #create_dictionary : "`CREATE [OR REPLACE] DICTIONARY [IF NOT EXISTS] <dictionary_name> [(<column>, ...)] PRIMARY KEY [<primary_key>, ...] SOURCE (<source_name> ([<source_options>])) [COMMENT <comment>] `"
2629            | #drop_dictionary : "`DROP DICTIONARY [IF EXISTS] <dictionary_name>`"
2630            | #show_create_dictionary : "`SHOW CREATE DICTIONARY <dictionary_name> `"
2631            | #show_dictionaries : "`SHOW DICTIONARIES [<show_option>, ...]`"
2632            | #rename_dictionary: "`RENAME DICTIONARY [<database>.]<old_dict_name> TO <new_dict_name>`"
2633        ),
2634        // view,index
2635        rule!(
2636            #create_view : "`CREATE [OR REPLACE] VIEW [IF NOT EXISTS] [<database>.]<view> [(<column>, ...)] AS SELECT ...`"
2637            | #drop_view : "`DROP VIEW [IF EXISTS] [<database>.]<view>`"
2638            | #alter_view : "`ALTER VIEW [<database>.]<view> [(<column>, ...)] AS SELECT ...`"
2639            | #show_views : "`SHOW [FULL] VIEWS [FROM <database>] [<show_limit>]`"
2640            | #create_index: "`CREATE [OR REPLACE] AGGREGATING INDEX [IF NOT EXISTS] <index> AS SELECT ...`"
2641            | #drop_index: "`DROP <index_type> INDEX [IF EXISTS] <index>`"
2642            | #refresh_index: "`REFRESH <index_type> INDEX <index> [LIMIT <limit>]`"
2643            | #create_table_index: "`CREATE [OR REPLACE] <index_type> INDEX [IF NOT EXISTS] <index> ON [<database>.]<table>(<column>, ...)`"
2644            | #drop_table_index: "`DROP <index_type> INDEX [IF EXISTS] <index> ON [<database>.]<table>`"
2645            | #refresh_table_index: "`REFRESH <index_type> INDEX <index> ON [<database>.]<table> [LIMIT <limit>]`"
2646            | #refresh_virtual_column: "`REFRESH VIRTUAL COLUMN FOR [<database>.]<table>`"
2647            | #show_virtual_columns : "`SHOW VIRTUAL COLUMNS FROM <table> [FROM|IN <catalog>.<database>] [<show_limit>]`"
2648            | #sequence
2649        ),
2650        rule!(
2651            #create_stage: "`CREATE [OR REPLACE] STAGE [ IF NOT EXISTS ] <stage_name>
2652                [ FILE_FORMAT = ( { TYPE = { CSV | PARQUET } [ formatTypeOptions ] ) } ]
2653                [ COPY_OPTIONS = ( copyOptions ) ]
2654                [ COMMENT = '<string_literal>' ]`"
2655            | #desc_stage: "`DESC STAGE <stage_name>`"
2656            | #list_stage: "`LIST @<stage_name> [pattern = '<pattern>']`"
2657            | #remove_stage: "`REMOVE @<stage_name> [pattern = '<pattern>']`"
2658            | #drop_stage: "`DROP STAGE <stage_name>`"
2659            | #create_file_format: "`CREATE FILE FORMAT [ IF NOT EXISTS ] <format_name> formatTypeOptions`"
2660            | #show_file_formats: "`SHOW FILE FORMATS`"
2661            | #drop_file_format: "`DROP FILE FORMAT  [ IF EXISTS ] <format_name>`"
2662            | #copy_into
2663            | #call: "`CALL <procedure_name>(<parameter>, ...)`"
2664            | #grant : "`GRANT { ROLE <role_name> | schemaObjectPrivileges | ALL [ PRIVILEGES ] ON <privileges_level> } TO { [ROLE <role_name>] | [USER] <user> }`"
2665            | #show_grants : "`SHOW GRANTS {FOR  { ROLE <role_name> | USER <user> }] | ON {DATABASE <db_name> | TABLE <db_name>.<table_name>} }`"
2666            | #revoke : "`REVOKE { ROLE <role_name> | schemaObjectPrivileges | ALL [ PRIVILEGES ] ON <privileges_level> } FROM { [ROLE <role_name>] | [USER] <user> }`"
2667            | #grant_ownership : "GRANT OWNERSHIP ON <privileges_level> TO ROLE <role_name>"
2668            | #presign: "`PRESIGN [{DOWNLOAD | UPLOAD}] <location> [EXPIRE = 3600]`"
2669        ),
2670        // data mask
2671        rule!(
2672            #create_data_mask_policy: "`CREATE MASKING POLICY [IF NOT EXISTS] mask_name as (val1 val_type1 [, val type]) return type -> case`"
2673            | #drop_data_mask_policy: "`DROP MASKING POLICY [IF EXISTS] mask_name`"
2674            | #describe_data_mask_policy: "`DESC MASKING POLICY mask_name`"
2675        ),
2676        rule!(
2677            #set_stmt : "`SET [variable] {<name> = <value> | (<name>, ...) = (<value>, ...)}`"
2678            | #unset_stmt : "`UNSET [variable] {<name> | (<name>, ...)}`"
2679            | #query_setting : "SETTINGS ( {<name> = <value> | (<name>, ...) = (<value>, ...)} )  Statement"
2680        ),
2681        // catalog
2682        rule!(
2683         #show_catalogs : "`SHOW CATALOGS [<show_limit>]`"
2684        | #show_create_catalog : "`SHOW CREATE CATALOG <catalog>`"
2685        | #create_catalog: "`CREATE CATALOG [IF NOT EXISTS] <catalog> TYPE=<catalog_type> CONNECTION=<catalog_options>`"
2686        | #drop_catalog: "`DROP CATALOG [IF EXISTS] <catalog>`"
2687        ),
2688        rule!(
2689            #create_task : "`CREATE TASK [ IF NOT EXISTS ] <name>
2690  [ { WAREHOUSE = <string> } ]
2691  [ SCHEDULE = { <num> MINUTE | USING CRON <expr> <time_zone> } ]
2692  [ AFTER <string>, <string>...]
2693  [ WHEN boolean_expr ]
2694  [ SUSPEND_TASK_AFTER_NUM_FAILURES = <num> ]
2695  [ ERROR_INTEGRATION = <string_literal> ]
2696  [ COMMENT = '<string_literal>' ]
2697AS
2698  <sql>`"
2699         | #drop_task : "`DROP TASK [ IF EXISTS ] <name>`"
2700         | #alter_task : "`ALTER TASK [ IF EXISTS ] <name> SUSPEND | RESUME | SET <option> = <value>` | UNSET <option> | MODIFY AS <sql> | MODIFY WHEN <boolean_expr> | ADD/REMOVE AFTER <string>, <string>...`"
2701         | #show_tasks : "`SHOW TASKS [<show_limit>]`"
2702         | #desc_task : "`DESC | DESCRIBE TASK <name>`"
2703         | #execute_task: "`EXECUTE TASK <name>`"
2704        ),
2705        // stream, dynamic tables.
2706        rule!(
2707            #stream_table
2708            | #dynamic_table
2709        ),
2710        rule!(
2711            #create_pipe : "`CREATE PIPE [ IF NOT EXISTS ] <name>
2712  [ AUTO_INGEST = [ TRUE | FALSE ] ]
2713  [ COMMENT = '<string_literal>' ]
2714AS
2715  <copy_sql>`"
2716            | #drop_pipe : "`DROP PIPE [ IF EXISTS ] <name>`"
2717            | #alter_pipe : "`ALTER PIPE [ IF EXISTS ] <name> SET <option> = <value>` | REFRESH <option> = <value>`"
2718            | #desc_pipe : "`DESC | DESCRIBE PIPE <name>`"
2719            | #create_notification : "`CREATE NOTIFICATION INTEGRATION [ IF NOT EXISTS ] <name>
2720    TYPE = <type>
2721    ENABLED = <bool>
2722    [ WEBHOOK = ( url = <string_literal>, method = <string_literal>, authorization_header = <string_literal> ) ]
2723    [ COMMENT = '<string_literal>' ]`"
2724            | #alter_notification : "`ALTER NOTIFICATION INTEGRATION [ IF EXISTS ] <name> SET <option> = <value>`"
2725            | #desc_notification : "`DESC | DESCRIBE NOTIFICATION INTEGRATION <name>`"
2726            | #drop_notification : "`DROP NOTIFICATION INTEGRATION [ IF EXISTS ] <name>`"
2727        ),
2728        rule!(
2729            #create_connection: "`CREATE [OR REPLACE] CONNECTION [IF NOT EXISTS] <connection_name> STORAGE_TYPE = <type> <storage_configs>`"
2730            | #drop_connection: "`DROP CONNECTION [IF EXISTS] <connection_name>`"
2731            | #desc_connection: "`DESC | DESCRIBE CONNECTION  <connection_name>`"
2732            | #show_connections: "`SHOW CONNECTIONS`"
2733            | #execute_immediate : "`EXECUTE IMMEDIATE $$ <script> $$`"
2734            | #create_procedure : "`CREATE [ OR REPLACE ] PROCEDURE <procedure_name>() RETURNS { <result_data_type> [ NOT NULL ] | TABLE(<var_name> <data_type>, ...)} LANGUAGE SQL [ COMMENT = '<string_literal>' ] AS <procedure_definition>`"
2735            | #drop_procedure : "`DROP PROCEDURE <procedure_name>()`"
2736            | #show_procedures : "`SHOW PROCEDURES [<show_options>]()`"
2737            | #describe_procedure : "`DESC PROCEDURE <procedure_name>()`"
2738            | #call_procedure : "`CALL PROCEDURE <procedure_name>()`"
2739        ),
2740        rule!(#comment),
2741        rule!(#vacuum_temporary_tables),
2742    ))(i)
2743}
2744
2745pub fn statement(i: Input) -> IResult<StatementWithFormat> {
2746    map(
2747        rule! {
2748            #statement_body ~ ( FORMAT ~ ^#ident )? ~ ";"? ~ &EOI
2749        },
2750        |(stmt, opt_format, _, _)| StatementWithFormat {
2751            stmt,
2752            format: opt_format.map(|(_, format)| format.name),
2753        },
2754    )(i)
2755}
2756
2757pub fn parse_create_option(
2758    opt_or_replace: bool,
2759    opt_if_not_exists: bool,
2760) -> Result<CreateOption, nom::Err<ErrorKind>> {
2761    match (opt_or_replace, opt_if_not_exists) {
2762        (false, false) => Ok(CreateOption::Create),
2763        (true, false) => Ok(CreateOption::CreateOrReplace),
2764        (false, true) => Ok(CreateOption::CreateIfNotExists),
2765        (true, true) => Err(nom::Err::Failure(ErrorKind::Other(
2766            "option IF NOT EXISTS and OR REPLACE are incompatible.",
2767        ))),
2768    }
2769}
2770
2771pub fn insert_stmt(
2772    allow_raw: bool,
2773    in_streaming_load: bool,
2774) -> impl FnMut(Input) -> IResult<Statement> {
2775    move |i| {
2776        let insert_source_parser = if in_streaming_load {
2777            insert_source_file
2778        } else if allow_raw {
2779            insert_source_fast_values
2780        } else {
2781            insert_source
2782        };
2783        map_res(
2784            rule! {
2785                #with? ~ INSERT ~ #hint? ~ OVERWRITE? ~ INTO?  ~ TABLE?
2786                ~ #dot_separated_idents_1_to_3
2787                ~ ( "(" ~ #comma_separated_list1(ident) ~ ")" )?
2788                ~ #insert_source_parser
2789            },
2790            |(
2791                with,
2792                _,
2793                opt_hints,
2794                overwrite,
2795                into,
2796                _,
2797                (catalog, database, table),
2798                opt_columns,
2799                source,
2800            )| {
2801                if overwrite.is_none() && into.is_none() {
2802                    return Err(nom::Err::Failure(ErrorKind::Other(
2803                        "INSERT statement must be followed by 'overwrite' or 'into'",
2804                    )));
2805                }
2806                Ok(Statement::Insert(InsertStmt {
2807                    hints: opt_hints,
2808                    with,
2809                    catalog,
2810                    database,
2811                    table,
2812                    columns: opt_columns
2813                        .map(|(_, columns, _)| columns)
2814                        .unwrap_or_default(),
2815                    source,
2816                    overwrite: overwrite.is_some(),
2817                }))
2818            },
2819        )(i)
2820    }
2821}
2822
2823pub fn conditional_multi_table_insert() -> impl FnMut(Input) -> IResult<Statement> {
2824    move |i| {
2825        map(
2826            rule! {
2827                INSERT ~ OVERWRITE? ~ (FIRST | ALL) ~ (#when_clause)+ ~ (#else_clause)? ~ #query
2828            },
2829            |(_, overwrite, kind, when_clauses, opt_else, source)| {
2830                Statement::InsertMultiTable(InsertMultiTableStmt {
2831                    overwrite: overwrite.is_some(),
2832                    is_first: matches!(kind.kind, FIRST),
2833                    when_clauses,
2834                    else_clause: opt_else,
2835                    into_clauses: vec![],
2836                    source,
2837                })
2838            },
2839        )(i)
2840    }
2841}
2842
2843pub fn unconditional_multi_table_insert() -> impl FnMut(Input) -> IResult<Statement> {
2844    move |i| {
2845        map(
2846            rule! {
2847                INSERT ~ OVERWRITE? ~ ALL ~ (#into_clause)+ ~ #query
2848            },
2849            |(_, overwrite, _, into_clauses, source)| {
2850                Statement::InsertMultiTable(InsertMultiTableStmt {
2851                    overwrite: overwrite.is_some(),
2852                    is_first: false,
2853                    when_clauses: vec![],
2854                    else_clause: None,
2855                    into_clauses,
2856                    source,
2857                })
2858            },
2859        )(i)
2860    }
2861}
2862
2863fn when_clause(i: Input) -> IResult<WhenClause> {
2864    map(
2865        rule! {
2866            WHEN ~ ^#expr ~ THEN ~ (#into_clause)+
2867        },
2868        |(_, expr, _, into_clauses)| WhenClause {
2869            condition: expr,
2870            into_clauses,
2871        },
2872    )(i)
2873}
2874
2875fn into_clause(i: Input) -> IResult<IntoClause> {
2876    let source_expr = alt((
2877        map(rule! {DEFAULT}, |_| SourceExpr::Default),
2878        map(rule! { #expr }, SourceExpr::Expr),
2879    ));
2880    map(
2881        rule! {
2882            INTO
2883            ~ #dot_separated_idents_1_to_3
2884            ~ ( "(" ~ #comma_separated_list1(ident) ~ ")" )?
2885            ~ (VALUES ~ "(" ~ #comma_separated_list1(source_expr) ~ ")" )?
2886        },
2887        |(_, (catalog, database, table), opt_target_columns, opt_source_columns)| IntoClause {
2888            catalog,
2889            database,
2890            table,
2891            target_columns: opt_target_columns
2892                .map(|(_, columns, _)| columns)
2893                .unwrap_or_default(),
2894            source_columns: opt_source_columns
2895                .map(|(_, _, columns, _)| columns)
2896                .unwrap_or_default(),
2897        },
2898    )(i)
2899}
2900
2901fn else_clause(i: Input) -> IResult<ElseClause> {
2902    map(
2903        rule! {
2904            ELSE ~ (#into_clause)+
2905        },
2906        |(_, into_clauses)| ElseClause { into_clauses },
2907    )(i)
2908}
2909
2910pub fn replace_stmt(allow_raw: bool) -> impl FnMut(Input) -> IResult<Statement> {
2911    move |i| {
2912        let insert_source_parser = if allow_raw {
2913            insert_source_fast_values
2914        } else {
2915            insert_source
2916        };
2917        map(
2918            rule! {
2919                REPLACE ~ #hint? ~ INTO?
2920                ~ #dot_separated_idents_1_to_3
2921                ~ ( "(" ~ #comma_separated_list1(ident) ~ ")" )?
2922                ~ ON ~ CONFLICT? ~ "(" ~ #comma_separated_list1(ident) ~ ")"
2923                ~ ( DELETE ~ WHEN ~ ^#expr )?
2924                ~ #insert_source_parser
2925            },
2926            |(
2927                _,
2928                opt_hints,
2929                _,
2930                (catalog, database, table),
2931                opt_columns,
2932                _,
2933                opt_conflict,
2934                _,
2935                on_conflict_columns,
2936                _,
2937                opt_delete_when,
2938                source,
2939            )| {
2940                Statement::Replace(ReplaceStmt {
2941                    hints: opt_hints,
2942                    catalog,
2943                    database,
2944                    table,
2945                    is_conflict: opt_conflict.is_some(),
2946                    on_conflict_columns,
2947                    columns: opt_columns
2948                        .map(|(_, columns, _)| columns)
2949                        .unwrap_or_default(),
2950                    source,
2951                    delete_when: opt_delete_when.map(|(_, _, expr)| expr),
2952                })
2953            },
2954        )(i)
2955    }
2956}
2957
2958// `VALUES (expr, expr), (expr, expr)`
2959pub fn insert_source(i: Input) -> IResult<InsertSource> {
2960    let row = map(
2961        rule! {
2962            "(" ~ #comma_separated_list1(expr) ~ ")"
2963        },
2964        |(_, values, _)| values,
2965    );
2966    let values = map(
2967        rule! {
2968            VALUES ~ #comma_separated_list0(row)
2969        },
2970        |(_, rows)| InsertSource::Values { rows },
2971    );
2972
2973    let query = map(query, |query| InsertSource::Select {
2974        query: Box::new(query),
2975    });
2976
2977    rule!(
2978        #values
2979        | #query
2980    )(i)
2981}
2982
2983pub fn insert_source_file(i: Input) -> IResult<InsertSource> {
2984    let value = map(
2985        rule! {
2986            "(" ~ #comma_separated_list1(expr) ~ ")"
2987        },
2988        |(_, values, _)| values,
2989    );
2990    map(
2991        rule! {
2992           (VALUES ~ #value?)? ~ FROM ~ #at_string ~  #file_format_clause ~ ";"? ~ &EOI
2993        },
2994        |(values, _, location, format_options, _, _)| InsertSource::LoadFile {
2995            value: values.map(|(_, value)| value).unwrap_or_default(),
2996            location,
2997            format_options,
2998        },
2999    )(i)
3000}
3001
3002// `INSERT INTO ... VALUES` statement will
3003// stop the parser immediately and return the rest tokens in `InsertSource`.
3004//
3005// This is a hack to parse large insert statements.
3006pub fn insert_source_fast_values(i: Input) -> IResult<InsertSource> {
3007    let values = map(
3008        rule! {
3009            VALUES ~ #rest_str
3010        },
3011        |(_, (rest_str, start))| InsertSource::RawValues { rest_str, start },
3012    );
3013    let query = map(
3014        rule! {
3015            #query ~ ";"? ~ &EOI
3016        },
3017        |(query, _, _)| InsertSource::Select {
3018            query: Box::new(query),
3019        },
3020    );
3021
3022    rule!(
3023        #insert_source_file |
3024        #values
3025        | #query
3026    )(i)
3027}
3028
3029pub fn mutation_source(i: Input) -> IResult<MutationSource> {
3030    let query = map(rule! {#query ~ #table_alias}, |(query, source_alias)| {
3031        MutationSource::Select {
3032            query: Box::new(query),
3033            source_alias,
3034        }
3035    });
3036
3037    let source_table = map(
3038        rule!(#dot_separated_idents_1_to_3 ~ #with_options? ~ #table_alias?),
3039        |((catalog, database, table), with_options, alias)| MutationSource::Table {
3040            catalog,
3041            database,
3042            table,
3043            with_options,
3044            alias,
3045        },
3046    );
3047
3048    rule!(
3049        #query
3050        | #source_table
3051    )(i)
3052}
3053
3054pub fn unset_source(i: Input) -> IResult<Vec<Identifier>> {
3055    //#ident ~ ( "(" ~ ^#comma_separated_list1(ident) ~ ")")?
3056    let var = map(
3057        rule! {
3058            #ident
3059        },
3060        |variable| vec![variable],
3061    );
3062    let vars = map(
3063        rule! {
3064            "(" ~ ^#comma_separated_list1(ident) ~ ")"
3065        },
3066        |(_, variables, _)| variables,
3067    );
3068
3069    rule!(
3070        #var
3071        | #vars
3072    )(i)
3073}
3074
3075pub fn set_stmt_args(i: Input) -> IResult<(Identifier, Box<Expr>)> {
3076    map(
3077        rule! {
3078            #ident ~ "=" ~ #subexpr(0)
3079        },
3080        |(id, _, expr)| (id, Box::new(expr)),
3081    )(i)
3082}
3083
3084pub fn set_var_hints(i: Input) -> IResult<HintItem> {
3085    map(
3086        rule! {
3087            SET_VAR ~ ^"(" ~ ^#ident ~ ^"=" ~ #subexpr(0) ~ ^")"
3088        },
3089        |(_, _, name, _, expr, _)| HintItem { name, expr },
3090    )(i)
3091}
3092
3093pub fn hint(i: Input) -> IResult<Hint> {
3094    let hint = map(
3095        rule! {
3096            "/*+" ~ #set_var_hints+ ~ "*/"
3097        },
3098        |(_, hints_list, _)| Hint { hints_list },
3099    );
3100    let invalid_hint = map(
3101        rule! {
3102            "/*+" ~ (!"*/" ~ #any_token)* ~ "*/"
3103        },
3104        |_| Hint { hints_list: vec![] },
3105    );
3106    rule!(#hint|#invalid_hint)(i)
3107}
3108
3109pub fn query_setting(i: Input) -> IResult<(Identifier, Expr)> {
3110    map(
3111        rule! {
3112            #ident ~ "=" ~ #subexpr(0)
3113        },
3114        |(id, _, value)| (id, value),
3115    )(i)
3116}
3117
3118pub fn query_statement_setting(i: Input) -> IResult<Settings> {
3119    let query_set = map(
3120        rule! {
3121            "(" ~ #comma_separated_list0(query_setting) ~ ")"
3122        },
3123        |(_, query_setting, _)| {
3124            let mut ids = Vec::with_capacity(query_setting.len());
3125            let mut values = Vec::with_capacity(query_setting.len());
3126            for (id, value) in query_setting {
3127                ids.push(id);
3128                values.push(value);
3129            }
3130            Settings {
3131                set_type: SetType::SettingsQuery,
3132                identifiers: ids,
3133                values: SetValues::Expr(values.into_iter().map(|x| x.into()).collect()),
3134            }
3135        },
3136    );
3137    rule!(#query_set: "(SETTING_NAME = VALUE, ...)")(i)
3138}
3139pub fn top_n(i: Input) -> IResult<u64> {
3140    map(
3141        rule! {
3142            TOP
3143            ~ ^#error_hint(
3144                not(literal_u64),
3145                "expecting a literal number after keyword `TOP`, if you were referring to a column with name `top`, \
3146                        please quote it like `\"top\"`"
3147            )
3148            ~ ^#literal_u64
3149            : "TOP <limit>"
3150        },
3151        |(_, _, n)| n,
3152    )(i)
3153}
3154
3155pub fn rest_str(i: Input) -> IResult<(String, usize)> {
3156    // It's safe to unwrap because input must contain EOI.
3157    let first_token = i.tokens.first().unwrap();
3158    let last_token = i.tokens.last().unwrap();
3159    Ok((
3160        i.slice((i.len() - 1)..),
3161        (
3162            first_token.source[first_token.span.start()..last_token.span.end()].to_string(),
3163            first_token.span.start(),
3164        ),
3165    ))
3166}
3167
3168pub fn column_def(i: Input) -> IResult<ColumnDefinition> {
3169    #[derive(Clone)]
3170    enum ColumnConstraint {
3171        Nullable(bool),
3172        DefaultExpr(Box<Expr>),
3173        VirtualExpr(Box<Expr>),
3174        StoredExpr(Box<Expr>),
3175    }
3176
3177    let nullable = alt((
3178        value(ColumnConstraint::Nullable(true), rule! { NULL }),
3179        value(ColumnConstraint::Nullable(false), rule! { NOT ~ ^NULL }),
3180    ));
3181    let expr = alt((
3182        map(
3183            rule! {
3184                DEFAULT ~ ^#subexpr(NOT_PREC)
3185            },
3186            |(_, default_expr)| ColumnConstraint::DefaultExpr(Box::new(default_expr)),
3187        ),
3188        map(
3189            rule! {
3190                (GENERATED ~ ^ALWAYS)? ~ AS ~ ^"(" ~ ^#subexpr(NOT_PREC) ~ ^")" ~ VIRTUAL
3191            },
3192            |(_, _, _, virtual_expr, _, _)| ColumnConstraint::VirtualExpr(Box::new(virtual_expr)),
3193        ),
3194        map(
3195            rule! {
3196                (GENERATED ~ ^ALWAYS)? ~ AS ~ ^"(" ~ ^#subexpr(NOT_PREC) ~ ^")" ~ STORED
3197            },
3198            |(_, _, _, stored_expr, _, _)| ColumnConstraint::StoredExpr(Box::new(stored_expr)),
3199        ),
3200    ));
3201
3202    let comment = map(
3203        rule! {
3204            COMMENT ~ #literal_string
3205        },
3206        |(_, comment)| comment,
3207    );
3208
3209    let (i, (mut def, constraints)) = map(
3210        rule! {
3211            #ident
3212            ~ #type_name
3213            ~ ( #nullable | #expr )*
3214            ~ ( #comment )?
3215            : "`<column name> <type> [DEFAULT <expr>] [AS (<expr>) VIRTUAL] [AS (<expr>) STORED] [COMMENT '<comment>']`"
3216        },
3217        |(name, data_type, constraints, comment)| {
3218            let def = ColumnDefinition {
3219                name,
3220                data_type,
3221                expr: None,
3222                comment,
3223            };
3224            (def, constraints)
3225        },
3226    )(i)?;
3227
3228    for constraint in constraints {
3229        match constraint {
3230            ColumnConstraint::Nullable(nullable) => {
3231                if (nullable && matches!(def.data_type, TypeName::NotNull(_)))
3232                    || (!nullable && matches!(def.data_type, TypeName::Nullable(_)))
3233                {
3234                    return Err(nom::Err::Error(Error::from_error_kind(
3235                        i,
3236                        ErrorKind::Other("ambiguous NOT NULL constraint"),
3237                    )));
3238                }
3239                if nullable {
3240                    def.data_type = def.data_type.wrap_nullable();
3241                } else {
3242                    def.data_type = def.data_type.wrap_not_null();
3243                }
3244            }
3245            ColumnConstraint::DefaultExpr(default_expr) => {
3246                def.expr = Some(ColumnExpr::Default(default_expr))
3247            }
3248            ColumnConstraint::VirtualExpr(virtual_expr) => {
3249                def.expr = Some(ColumnExpr::Virtual(virtual_expr))
3250            }
3251            ColumnConstraint::StoredExpr(stored_expr) => {
3252                def.expr = Some(ColumnExpr::Stored(stored_expr))
3253            }
3254        }
3255    }
3256
3257    Ok((i, def))
3258}
3259
3260pub fn table_index_def(i: Input) -> IResult<TableIndexDefinition> {
3261    map_res(
3262        rule! {
3263            ASYNC?
3264            ~ #index_type ~ ^INDEX
3265            ~ #ident
3266            ~ ^"(" ~ ^#comma_separated_list1(ident) ~ ^")"
3267            ~ ( #table_option )?
3268        },
3269        |(opt_async, index_type, _, index_name, _, columns, _, opt_index_options)| {
3270            Ok(TableIndexDefinition {
3271                index_name,
3272                index_type,
3273                columns,
3274                sync_creation: opt_async.is_none(),
3275                index_options: opt_index_options.unwrap_or_default(),
3276            })
3277        },
3278    )(i)
3279}
3280
3281pub fn create_def(i: Input) -> IResult<CreateDefinition> {
3282    alt((
3283        map(rule! { #column_def }, CreateDefinition::Column),
3284        map(rule! { #table_index_def }, CreateDefinition::TableIndex),
3285    ))(i)
3286}
3287
3288pub fn role_name(i: Input) -> IResult<String> {
3289    let role_ident = map_res(
3290        rule! {
3291            #ident
3292        },
3293        |role_name| {
3294            let name = role_name.name;
3295            let mut chars = name.chars();
3296            while let Some(c) = chars.next() {
3297                match c {
3298                    '\\' => match chars.next() {
3299                        Some('f') | Some('b') => {
3300                            return Err(nom::Err::Failure(ErrorKind::Other(
3301                                "' or \" or \\f or \\b are not allowed in role name",
3302                            )));
3303                        }
3304                        _ => {}
3305                    },
3306                    '\'' | '"' => {
3307                        return Err(nom::Err::Failure(ErrorKind::Other(
3308                            "' or \" or \\f or \\b are not allowed in role name",
3309                        )));
3310                    }
3311                    _ => {}
3312                }
3313            }
3314            Ok(name)
3315        },
3316    );
3317    let role_lit = map(
3318        rule! {
3319            #literal_string
3320        },
3321        |role_name| role_name,
3322    );
3323
3324    rule!(
3325        #role_ident : "<role_name>"
3326        | #role_lit : "'<role_name>'"
3327    )(i)
3328}
3329
3330pub fn grant_source(i: Input) -> IResult<AccountMgrSource> {
3331    let role = map(
3332        rule! {
3333            ROLE ~ #role_name
3334        },
3335        |(_, role_name)| AccountMgrSource::Role { role: role_name },
3336    );
3337    let privs = map(
3338        rule! {
3339            #comma_separated_list1(priv_type) ~ ON ~ #grant_level
3340        },
3341        |(privs, _, level)| AccountMgrSource::Privs {
3342            privileges: privs,
3343            level,
3344        },
3345    );
3346    let all = map(
3347        rule! { ALL ~ PRIVILEGES? ~ ON ~ #grant_all_level },
3348        |(_, _, _, level)| AccountMgrSource::ALL { level },
3349    );
3350
3351    let udf_privs = map(
3352        rule! {
3353            USAGE ~ ON ~ UDF ~ #ident
3354        },
3355        |(_, _, _, udf)| AccountMgrSource::Privs {
3356            privileges: vec![UserPrivilegeType::Usage],
3357            level: AccountMgrLevel::UDF(udf.to_string()),
3358        },
3359    );
3360
3361    let udf_all_privs = map(
3362        rule! {
3363            ALL ~ PRIVILEGES? ~ ON ~ UDF ~ #ident
3364        },
3365        |(_, _, _, _, udf)| AccountMgrSource::Privs {
3366            privileges: vec![UserPrivilegeType::Usage],
3367            level: AccountMgrLevel::UDF(udf.to_string()),
3368        },
3369    );
3370
3371    let stage_privs = map(
3372        rule! {
3373            #comma_separated_list1(stage_priv_type) ~ ON ~ STAGE ~ #ident
3374        },
3375        |(privileges, _, _, stage_name)| AccountMgrSource::Privs {
3376            privileges,
3377            level: AccountMgrLevel::Stage(stage_name.to_string()),
3378        },
3379    );
3380
3381    let warehouse_privs = map(
3382        rule! {
3383            USAGE ~ ON ~ WAREHOUSE ~ #ident
3384        },
3385        |(_, _, _, w)| AccountMgrSource::Privs {
3386            privileges: vec![UserPrivilegeType::Usage],
3387            level: AccountMgrLevel::Warehouse(w.to_string()),
3388        },
3389    );
3390
3391    let warehouse_all_privs = map(
3392        rule! {
3393            ALL ~ PRIVILEGES? ~ ON ~ WAREHOUSE ~ #ident
3394        },
3395        |(_, _, _, _, w)| AccountMgrSource::Privs {
3396            privileges: vec![UserPrivilegeType::Usage],
3397            level: AccountMgrLevel::Warehouse(w.to_string()),
3398        },
3399    );
3400
3401    let connection_privs = map(
3402        rule! {
3403            ACCESS ~ CONNECTION ~ ON ~ CONNECTION ~ #ident
3404        },
3405        |(_, _, _, _, c)| AccountMgrSource::Privs {
3406            privileges: vec![UserPrivilegeType::AccessConnection],
3407            level: AccountMgrLevel::Connection(c.to_string()),
3408        },
3409    );
3410
3411    let connection_all_privs = map(
3412        rule! {
3413            ALL ~ PRIVILEGES? ~ ON ~ CONNECTION ~ #ident
3414        },
3415        |(_, _, _, _, w)| AccountMgrSource::Privs {
3416            privileges: vec![UserPrivilegeType::AccessConnection],
3417            level: AccountMgrLevel::Connection(w.to_string()),
3418        },
3419    );
3420
3421    let seq_privs = map(
3422        rule! {
3423            ACCESS ~ SEQUENCE ~ ON ~ SEQUENCE ~ #ident
3424        },
3425        |(_, _, _, _, c)| AccountMgrSource::Privs {
3426            privileges: vec![UserPrivilegeType::AccessSequence],
3427            level: AccountMgrLevel::Sequence(c.to_string()),
3428        },
3429    );
3430
3431    let seq_all_privs = map(
3432        rule! {
3433            ALL ~ PRIVILEGES? ~ ON ~ SEQUENCE ~ #ident
3434        },
3435        |(_, _, _, _, w)| AccountMgrSource::Privs {
3436            privileges: vec![UserPrivilegeType::AccessSequence],
3437            level: AccountMgrLevel::Sequence(w.to_string()),
3438        },
3439    );
3440
3441    rule!(
3442        #role : "ROLE <role_name>"
3443        | #warehouse_all_privs: "ALL [ PRIVILEGES ] ON WAREHOUSE <warehouse_name>"
3444        | #connection_all_privs: "ALL [ PRIVILEGES ] ON CONNECTION <connection_name>"
3445        | #seq_all_privs: "ALL [ PRIVILEGES ] ON SEQUENCE <seq_name>"
3446        | #udf_privs: "USAGE ON UDF <udf_name>"
3447        | #warehouse_privs: "USAGE ON WAREHOUSE <warehouse_name>"
3448        | #connection_privs: "ACCESS CONNECTION ON CONNECTION <connection_name>"
3449        | #seq_privs: "ACCESS SEQUENCE ON CONNECTION <seq_name>"
3450        | #privs : "<privileges> ON <privileges_level>"
3451        | #stage_privs : "<stage_privileges> ON STAGE <stage_name>"
3452        | #udf_all_privs: "ALL [ PRIVILEGES ] ON UDF <udf_name>"
3453        | #all : "ALL [ PRIVILEGES ] ON <privileges_level>"
3454    )(i)
3455}
3456
3457pub fn priv_type(i: Input) -> IResult<UserPrivilegeType> {
3458    let usage = value(UserPrivilegeType::Usage, rule! { USAGE });
3459    let select = value(UserPrivilegeType::Select, rule! { SELECT });
3460    let insert = value(UserPrivilegeType::Insert, rule! { INSERT });
3461    let update = value(UserPrivilegeType::Update, rule! { UPDATE });
3462    let delete = value(UserPrivilegeType::Delete, rule! { DELETE });
3463    let alter = value(UserPrivilegeType::Alter, rule! { ALTER });
3464    let super_priv = value(UserPrivilegeType::Super, rule! { SUPER });
3465    let create_user = value(UserPrivilegeType::CreateUser, rule! { CREATE ~ USER });
3466    let create_database = value(
3467        UserPrivilegeType::CreateDatabase,
3468        rule! { CREATE ~ DATABASE },
3469    );
3470    let create_warehouse = value(
3471        UserPrivilegeType::CreateWarehouse,
3472        rule! { CREATE ~ WAREHOUSE },
3473    );
3474    let create_connection = value(
3475        UserPrivilegeType::CreateConnection,
3476        rule! { CREATE ~ CONNECTION },
3477    );
3478    let access_sequence = value(
3479        UserPrivilegeType::AccessConnection,
3480        rule! { ACCESS ~ CONNECTION },
3481    );
3482    let create_sequence = value(
3483        UserPrivilegeType::CreateSequence,
3484        rule! { CREATE ~ SEQUENCE },
3485    );
3486    let access_connection = value(
3487        UserPrivilegeType::AccessSequence,
3488        rule! { ACCESS ~ SEQUENCE },
3489    );
3490    let drop_user = value(UserPrivilegeType::DropUser, rule! { DROP ~ USER });
3491    let create_role = value(UserPrivilegeType::CreateRole, rule! { CREATE ~ ROLE });
3492    let drop_role = value(UserPrivilegeType::DropRole, rule! { DROP ~ ROLE });
3493    let grant = value(UserPrivilegeType::Grant, rule! { GRANT });
3494    let create_stage = value(UserPrivilegeType::CreateStage, rule! { CREATE ~ STAGE });
3495    let set = value(UserPrivilegeType::Set, rule! { SET });
3496    let drop = value(UserPrivilegeType::Drop, rule! { DROP });
3497    let create = value(UserPrivilegeType::Create, rule! { CREATE });
3498
3499    alt((
3500        rule!(
3501            #usage
3502            | #select
3503            | #insert
3504            | #update
3505            | #delete
3506            | #alter
3507            | #super_priv
3508            | #create_user
3509            | #create_database
3510            | #create_warehouse
3511        ),
3512        rule!(
3513            #create_connection
3514            | #access_connection
3515            | #access_sequence
3516            | #create_sequence
3517            | #drop_user
3518            | #create_role
3519            | #drop_role
3520            | #grant
3521            | #create_stage
3522            | #set
3523            | #drop
3524            | #create
3525        ),
3526    ))(i)
3527}
3528
3529pub fn stage_priv_type(i: Input) -> IResult<UserPrivilegeType> {
3530    alt((
3531        value(UserPrivilegeType::Read, rule! { READ }),
3532        value(UserPrivilegeType::Write, rule! { WRITE }),
3533    ))(i)
3534}
3535
3536pub fn priv_share_type(i: Input) -> IResult<ShareGrantObjectPrivilege> {
3537    alt((
3538        value(ShareGrantObjectPrivilege::Usage, rule! { USAGE }),
3539        value(ShareGrantObjectPrivilege::Select, rule! { SELECT }),
3540        value(
3541            ShareGrantObjectPrivilege::ReferenceUsage,
3542            rule! { REFERENCE_USAGE },
3543        ),
3544    ))(i)
3545}
3546
3547pub fn alter_add_share_accounts(i: Input) -> IResult<bool> {
3548    alt((value(true, rule! { ADD }), value(false, rule! { REMOVE })))(i)
3549}
3550
3551pub fn on_object_name(i: Input) -> IResult<GrantObjectName> {
3552    let database = map(
3553        rule! {
3554            DATABASE ~ #ident
3555        },
3556        |(_, database)| GrantObjectName::Database(database.to_string()),
3557    );
3558
3559    // `db01`.'tb1' or `db01`.`tb1` or `db01`.tb1
3560    let table = map(
3561        rule! {
3562            TABLE ~  #dot_separated_idents_1_to_2
3563        },
3564        |(_, (database, table))| {
3565            GrantObjectName::Table(database.map(|db| db.to_string()), table.to_string())
3566        },
3567    );
3568
3569    let stage = map(rule! { STAGE ~ #ident}, |(_, stage_name)| {
3570        GrantObjectName::Stage(stage_name.to_string())
3571    });
3572
3573    let udf = map(rule! { UDF ~ #ident}, |(_, udf_name)| {
3574        GrantObjectName::UDF(udf_name.to_string())
3575    });
3576
3577    let warehouse = map(rule! { WAREHOUSE ~ #ident}, |(_, w)| {
3578        GrantObjectName::Warehouse(w.to_string())
3579    });
3580
3581    let connection = map(rule! { CONNECTION ~ #ident}, |(_, w)| {
3582        GrantObjectName::Connection(w.to_string())
3583    });
3584
3585    let seq = map(rule! { SEQUENCE ~ #ident}, |(_, w)| {
3586        GrantObjectName::Sequence(w.to_string())
3587    });
3588
3589    rule!(
3590        #database : "DATABASE <database>"
3591        | #table : "TABLE <database>.<table>"
3592        | #stage : "STAGE <stage_name>"
3593        | #udf : "UDF <udf_name>"
3594        | #warehouse : "WAREHOUSE <warehouse_name>"
3595        | #connection : "CONNECTION <connection_name>"
3596        | #seq : "SEQUENCE <seq_name>"
3597    )(i)
3598}
3599
3600pub fn grant_level(i: Input) -> IResult<AccountMgrLevel> {
3601    // *.*
3602    let global = map(rule! { "*" ~ "." ~ "*" }, |_| AccountMgrLevel::Global);
3603    // db.*
3604    // "*": as current db or "table" with current db
3605    let db = map(
3606        rule! {
3607            ( #ident ~ "." )? ~ "*"
3608        },
3609        |(database, _)| AccountMgrLevel::Database(database.map(|(database, _)| database.name)),
3610    );
3611
3612    // `db01`.'tb1' or `db01`.`tb1` or `db01`.tb1
3613    let table = map(
3614        rule! {
3615            ( #ident ~ "." )? ~ #parameter_to_string
3616        },
3617        |(database, table)| {
3618            AccountMgrLevel::Table(database.map(|(database, _)| database.name), table)
3619        },
3620    );
3621
3622    rule!(
3623        #global : "*.*"
3624        | #db : "<database>.*"
3625        | #table : "<database>.<table>"
3626    )(i)
3627}
3628
3629pub fn grant_all_level(i: Input) -> IResult<AccountMgrLevel> {
3630    // *.*
3631    let global = map(rule! { "*" ~ "." ~ "*" }, |_| AccountMgrLevel::Global);
3632    // db.*
3633    // "*": as current db or "table" with current db
3634    let db = map(
3635        rule! {
3636            ( #ident ~ "." )? ~ "*"
3637        },
3638        |(database, _)| AccountMgrLevel::Database(database.map(|(database, _)| database.name)),
3639    );
3640
3641    // `db01`.'tb1' or `db01`.`tb1` or `db01`.tb1
3642    let table = map(
3643        rule! {
3644            ( #ident ~ "." )? ~ #parameter_to_string
3645        },
3646        |(database, table)| {
3647            AccountMgrLevel::Table(database.map(|(database, _)| database.name), table)
3648        },
3649    );
3650
3651    let stage = map(rule! { STAGE ~ #ident}, |(_, stage_name)| {
3652        AccountMgrLevel::Stage(stage_name.to_string())
3653    });
3654
3655    let warehouse = map(rule! { WAREHOUSE ~ #ident}, |(_, w)| {
3656        AccountMgrLevel::Warehouse(w.to_string())
3657    });
3658    rule!(
3659        #global : "*.*"
3660        | #db : "<database>.*"
3661        | #table : "<database>.<table>"
3662        | #stage : "STAGE <stage_name>"
3663        | #warehouse : "WAREHOUSE <warehouse_name>"
3664    )(i)
3665}
3666
3667pub fn grant_ownership_level(i: Input) -> IResult<AccountMgrLevel> {
3668    // db.*
3669    // "*": as current db or "table" with current db
3670    let db = map(
3671        rule! {
3672            ( #grant_ident ~ "." )? ~ "*"
3673        },
3674        |(database, _)| AccountMgrLevel::Database(database.map(|(database, _)| database.name)),
3675    );
3676
3677    // `db01`.'tb1' or `db01`.`tb1` or `db01`.tb1
3678    let table = map(
3679        rule! {
3680            ( #grant_ident ~ "." )? ~ #parameter_to_grant_string
3681        },
3682        |(database, table)| {
3683            AccountMgrLevel::Table(database.map(|(database, _)| database.name), table)
3684        },
3685    );
3686
3687    #[derive(Clone)]
3688    enum Object {
3689        Stage,
3690        Udf,
3691        Warehouse,
3692        Connection,
3693        Sequence,
3694    }
3695    let object = alt((
3696        value(Object::Udf, rule! { UDF }),
3697        value(Object::Stage, rule! { STAGE }),
3698        value(Object::Warehouse, rule! { WAREHOUSE }),
3699        value(Object::Connection, rule! { CONNECTION }),
3700        value(Object::Sequence, rule! { SEQUENCE }),
3701    ));
3702
3703    // Object object_name
3704    let object = map(
3705        rule! { #object ~ #grant_ident },
3706        |(object, object_name)| match object {
3707            Object::Stage => AccountMgrLevel::Stage(object_name.to_string()),
3708            Object::Udf => AccountMgrLevel::UDF(object_name.to_string()),
3709            Object::Warehouse => AccountMgrLevel::Warehouse(object_name.to_string()),
3710            Object::Connection => AccountMgrLevel::Connection(object_name.to_string()),
3711            Object::Sequence => AccountMgrLevel::Sequence(object_name.to_string()),
3712        },
3713    );
3714
3715    rule!(
3716        #db : "<database>.*"
3717        | #table : "<database>.<table>"
3718        | #object : "STAGE | UDF | WAREHOUSE | CONNECTION | SEQUENCE <object_name>"
3719    )(i)
3720}
3721
3722pub fn show_grant_option(i: Input) -> IResult<ShowGrantOption> {
3723    let grant_role = map(
3724        rule! {
3725            FOR ~ #grant_option
3726        },
3727        |(_, opt_principal)| ShowGrantOption::PrincipalIdentity(opt_principal),
3728    );
3729
3730    let share_object_name = map(
3731        rule! {
3732            ON ~ #on_object_name
3733        },
3734        |(_, object_name)| ShowGrantOption::GrantObjectName(object_name),
3735    );
3736
3737    let role_granted = map(
3738        rule! {
3739            OF ~ ROLE ~ #role_name
3740        },
3741        |(_, _, role_name)| ShowGrantOption::OfRole(role_name),
3742    );
3743
3744    rule!(
3745        #grant_role: "FOR  { ROLE <role_name> | [USER] <user> }"
3746        | #share_object_name: "ON {DATABASE <db_name> | TABLE <db_name>.<table_name> | UDF <udf_name> | STAGE <stage_name> | CONNECTION <connection_name> | SEQUENCE <seq_name> }"
3747        | #role_granted: "OF ROLE <role_name>"
3748    )(i)
3749}
3750
3751pub fn grant_option(i: Input) -> IResult<PrincipalIdentity> {
3752    let role = map(
3753        rule! {
3754            ROLE ~ #role_name
3755        },
3756        |(_, role_name)| PrincipalIdentity::Role(role_name),
3757    );
3758
3759    let user = map(
3760        rule! {
3761            USER? ~ #user_identity
3762        },
3763        |(_, user)| PrincipalIdentity::User(user),
3764    );
3765
3766    rule!(
3767        #role
3768        | #user
3769    )(i)
3770}
3771
3772pub fn create_table_source(i: Input) -> IResult<CreateTableSource> {
3773    let columns = map(
3774        rule! {
3775            "(" ~ ^#comma_separated_list1(create_def) ~ ^")"
3776        },
3777        |(_, create_defs, _)| {
3778            let mut columns = Vec::with_capacity(create_defs.len());
3779            let mut table_indexes = Vec::new();
3780            for create_def in create_defs {
3781                match create_def {
3782                    CreateDefinition::Column(column) => {
3783                        columns.push(column);
3784                    }
3785                    CreateDefinition::TableIndex(table_index) => {
3786                        table_indexes.push(table_index);
3787                    }
3788                }
3789            }
3790            let opt_table_indexes = if !table_indexes.is_empty() {
3791                Some(table_indexes)
3792            } else {
3793                None
3794            };
3795            CreateTableSource::Columns(columns, opt_table_indexes)
3796        },
3797    );
3798    let like = map(
3799        rule! {
3800            LIKE ~ #dot_separated_idents_1_to_3
3801        },
3802        |(_, (catalog, database, table))| CreateTableSource::Like {
3803            catalog,
3804            database,
3805            table,
3806        },
3807    );
3808
3809    rule!(
3810        #columns
3811        | #like
3812    )(i)
3813}
3814
3815pub fn alter_database_action(i: Input) -> IResult<AlterDatabaseAction> {
3816    let rename_database = map(
3817        rule! {
3818            RENAME ~ TO ~ #ident
3819        },
3820        |(_, _, new_db)| AlterDatabaseAction::RenameDatabase { new_db },
3821    );
3822
3823    let refresh_cache = map(
3824        rule! {
3825            REFRESH ~ CACHE
3826        },
3827        |(_, _)| AlterDatabaseAction::RefreshDatabaseCache,
3828    );
3829
3830    rule!(
3831        #rename_database
3832        | #refresh_cache
3833    )(i)
3834}
3835
3836pub fn modify_column_type(i: Input) -> IResult<ColumnDefinition> {
3837    #[derive(Educe)]
3838    #[educe(Clone(bound = false, attrs = "#[recursive::recursive]"))]
3839    enum ColumnConstraint {
3840        Nullable(bool),
3841        DefaultExpr(Box<Expr>),
3842    }
3843
3844    let nullable = alt((
3845        value(ColumnConstraint::Nullable(true), rule! { NULL }),
3846        value(ColumnConstraint::Nullable(false), rule! { NOT ~ ^NULL }),
3847    ));
3848    let expr = alt((map(
3849        rule! {
3850            DEFAULT ~ ^#subexpr(NOT_PREC)
3851        },
3852        |(_, default_expr)| ColumnConstraint::DefaultExpr(Box::new(default_expr)),
3853    ),));
3854
3855    let comment = map(
3856        rule! {
3857            COMMENT ~ #literal_string
3858        },
3859        |(_, comment)| comment,
3860    );
3861
3862    map_res(
3863        rule! {
3864            #ident
3865            ~ #type_name
3866            ~ ( #nullable | #expr )*
3867            ~ ( #comment )?
3868            : "`<column name> <type> [DEFAULT <expr>] [COMMENT '<comment>']`"
3869        },
3870        |(name, data_type, constraints, comment)| {
3871            let mut def = ColumnDefinition {
3872                name,
3873                data_type,
3874                expr: None,
3875                comment,
3876            };
3877            for constraint in constraints {
3878                match constraint {
3879                    ColumnConstraint::Nullable(nullable) => {
3880                        if (nullable && matches!(def.data_type, TypeName::NotNull(_)))
3881                            || (!nullable && matches!(def.data_type, TypeName::Nullable(_)))
3882                        {
3883                            return Err(nom::Err::Failure(ErrorKind::Other(
3884                                "ambiguous NOT NULL constraint",
3885                            )));
3886                        }
3887                        if nullable {
3888                            def.data_type = def.data_type.wrap_nullable();
3889                        } else {
3890                            def.data_type = def.data_type.wrap_not_null();
3891                        }
3892                    }
3893                    ColumnConstraint::DefaultExpr(default_expr) => {
3894                        def.expr = Some(ColumnExpr::Default(default_expr))
3895                    }
3896                }
3897            }
3898            Ok(def)
3899        },
3900    )(i)
3901}
3902
3903pub fn modify_column_comment(i: Input) -> IResult<ColumnComment> {
3904    let comment = map(
3905        rule! {
3906            COMMENT ~ #literal_string
3907        },
3908        |(_, comment)| comment,
3909    );
3910    map_res(
3911        rule! {
3912            #ident
3913            ~ #comment
3914            : "`<column name> COMMENT '<comment>'`"
3915        },
3916        |(name, comment)| Ok(ColumnComment { name, comment }),
3917    )(i)
3918}
3919
3920pub fn modify_column_action(i: Input) -> IResult<ModifyColumnAction> {
3921    let set_mask_policy = map(
3922        rule! {
3923            #ident ~ SET ~ MASKING ~ POLICY ~ #ident
3924        },
3925        |(column, _, _, _, mask_name)| {
3926            ModifyColumnAction::SetMaskingPolicy(column, mask_name.to_string())
3927        },
3928    );
3929
3930    let unset_mask_policy = map(
3931        rule! {
3932            #ident ~ UNSET ~ MASKING ~ POLICY
3933        },
3934        |(column, _, _, _)| ModifyColumnAction::UnsetMaskingPolicy(column),
3935    );
3936
3937    let convert_stored_computed_column = map(
3938        rule! {
3939            #ident ~ DROP ~ STORED
3940        },
3941        |(column, _, _)| ModifyColumnAction::ConvertStoredComputedColumn(column),
3942    );
3943
3944    let modify_column_type = map(
3945        rule! {
3946            #modify_column_type ~ ("," ~ COLUMN? ~ #modify_column_type)*
3947        },
3948        |(column_def, column_def_vec)| {
3949            let mut column_defs = vec![column_def];
3950            column_def_vec
3951                .iter()
3952                .for_each(|(_, _, column_def)| column_defs.push(column_def.clone()));
3953            ModifyColumnAction::SetDataType(column_defs)
3954        },
3955    );
3956
3957    let modify_column_comment = map(
3958        rule! {
3959            #modify_column_comment ~ ("," ~ COLUMN? ~ #modify_column_comment)*
3960        },
3961        |(column_def, column_def_vec)| {
3962            let mut column_defs = vec![column_def];
3963            column_def_vec
3964                .iter()
3965                .for_each(|(_, _, column_def)| column_defs.push(column_def.clone()));
3966            ModifyColumnAction::Comment(column_defs)
3967        },
3968    );
3969
3970    rule!(
3971        #set_mask_policy
3972        | #unset_mask_policy
3973        | #convert_stored_computed_column
3974        | #modify_column_type
3975        | #modify_column_comment
3976    )(i)
3977}
3978
3979pub fn alter_table_action(i: Input) -> IResult<AlterTableAction> {
3980    let rename_table = map(
3981        rule! {
3982           RENAME ~ TO ~ #ident
3983        },
3984        |(_, _, new_table)| AlterTableAction::RenameTable { new_table },
3985    );
3986    let rename_column = map(
3987        rule! {
3988            RENAME ~ COLUMN? ~ #ident ~ TO ~ #ident
3989        },
3990        |(_, _, old_column, _, new_column)| AlterTableAction::RenameColumn {
3991            old_column,
3992            new_column,
3993        },
3994    );
3995    let modify_table_comment = map(
3996        rule! {
3997            COMMENT ~ ^"=" ~ ^#literal_string
3998        },
3999        |(_, _, new_comment)| AlterTableAction::ModifyTableComment { new_comment },
4000    );
4001    let add_column = map(
4002        rule! {
4003            ADD ~ COLUMN? ~ #column_def ~ ( #add_column_option )?
4004        },
4005        |(_, _, column, option)| AlterTableAction::AddColumn {
4006            column,
4007            option: option.unwrap_or(AddColumnOption::End),
4008        },
4009    );
4010
4011    let modify_column = map(
4012        rule! {
4013            MODIFY ~ COLUMN? ~ #modify_column_action
4014        },
4015        |(_, _, action)| AlterTableAction::ModifyColumn { action },
4016    );
4017
4018    let drop_column = map(
4019        rule! {
4020            DROP ~ COLUMN? ~ #ident
4021        },
4022        |(_, _, column)| AlterTableAction::DropColumn { column },
4023    );
4024    let alter_table_cluster_key = map(
4025        rule! {
4026            CLUSTER ~ ^BY ~ ( #cluster_type )? ~ ^"(" ~ ^#comma_separated_list1(expr) ~ ^")"
4027        },
4028        |(_, _, typ, _, cluster_exprs, _)| AlterTableAction::AlterTableClusterKey {
4029            cluster_by: ClusterOption {
4030                cluster_type: typ.unwrap_or(ClusterType::Linear),
4031                cluster_exprs,
4032            },
4033        },
4034    );
4035
4036    let drop_table_cluster_key = map(
4037        rule! {
4038            DROP ~ CLUSTER ~ KEY
4039        },
4040        |(_, _, _)| AlterTableAction::DropTableClusterKey,
4041    );
4042
4043    let recluster_table = map(
4044        rule! {
4045            RECLUSTER ~ FINAL? ~ ( WHERE ~ ^#expr )? ~ ( LIMIT ~ #literal_u64 )?
4046        },
4047        |(_, opt_is_final, opt_selection, opt_limit)| AlterTableAction::ReclusterTable {
4048            is_final: opt_is_final.is_some(),
4049            selection: opt_selection.map(|(_, selection)| selection),
4050            limit: opt_limit.map(|(_, limit)| limit),
4051        },
4052    );
4053
4054    let revert_table = map(
4055        rule! {
4056            FLASHBACK ~ TO ~ #travel_point
4057        },
4058        |(_, _, point)| AlterTableAction::FlashbackTo { point },
4059    );
4060
4061    let set_table_options = map(
4062        rule! {
4063            SET ~ OPTIONS ~ "(" ~ #set_table_option ~ ")"
4064        },
4065        |(_, _, _, set_options, _)| AlterTableAction::SetOptions { set_options },
4066    );
4067
4068    let unset_table_options = map(
4069        rule! {
4070            UNSET ~ OPTIONS ~ #unset_source
4071        },
4072        |(_, _, targets)| AlterTableAction::UnsetOptions { targets },
4073    );
4074
4075    let refresh_cache = map(
4076        rule! {
4077            REFRESH ~ CACHE
4078        },
4079        |(_, _)| AlterTableAction::RefreshTableCache,
4080    );
4081
4082    let modify_table_connection = map(
4083        rule! {
4084            CONNECTION ~ ^"=" ~ #connection_options
4085        },
4086        |(_, _, connection_options)| AlterTableAction::ModifyConnection {
4087            new_connection: connection_options,
4088        },
4089    );
4090
4091    rule!(
4092        #alter_table_cluster_key
4093        | #drop_table_cluster_key
4094        | #rename_table
4095        | #rename_column
4096        | #modify_table_comment
4097        | #add_column
4098        | #drop_column
4099        | #modify_column
4100        | #recluster_table
4101        | #revert_table
4102        | #set_table_options
4103        | #unset_table_options
4104        | #refresh_cache
4105        | #modify_table_connection
4106    )(i)
4107}
4108
4109pub fn match_clause(i: Input) -> IResult<MergeOption> {
4110    map(
4111        rule! {
4112            WHEN ~ MATCHED ~ (AND ~ ^#expr)? ~ THEN ~ #match_operation
4113        },
4114        |(_, _, expr_op, _, match_operation)| match expr_op {
4115            Some(expr) => MergeOption::Match(MatchedClause {
4116                selection: Some(expr.1),
4117                operation: match_operation,
4118            }),
4119            None => MergeOption::Match(MatchedClause {
4120                selection: None,
4121                operation: match_operation,
4122            }),
4123        },
4124    )(i)
4125}
4126
4127fn match_operation(i: Input) -> IResult<MatchOperation> {
4128    alt((
4129        value(MatchOperation::Delete, rule! { DELETE }),
4130        map(
4131            rule! {
4132                UPDATE ~ SET ~ ^#comma_separated_list1(mutation_update_expr)
4133            },
4134            |(_, _, update_list)| MatchOperation::Update {
4135                update_list,
4136                is_star: false,
4137            },
4138        ),
4139        map(
4140            rule! {
4141                UPDATE ~ "*"
4142            },
4143            |(_, _)| MatchOperation::Update {
4144                update_list: Vec::new(),
4145                is_star: true,
4146            },
4147        ),
4148    ))(i)
4149}
4150
4151pub fn unmatch_clause(i: Input) -> IResult<MergeOption> {
4152    alt((
4153        map(
4154            rule! {
4155                WHEN ~ NOT ~ MATCHED ~ (AND ~ ^#expr)?  ~ THEN ~ INSERT ~ ( "(" ~ ^#comma_separated_list1(ident) ~ ^")" )?
4156                ~ VALUES ~ ^#row_values
4157            },
4158            |(_, _, _, expr_op, _, _, columns_op, _, values)| {
4159                let selection = match expr_op {
4160                    Some(e) => Some(e.1),
4161                    None => None,
4162                };
4163                match columns_op {
4164                    Some(columns) => MergeOption::Unmatch(UnmatchedClause {
4165                        insert_operation: InsertOperation {
4166                            columns: Some(columns.1),
4167                            values,
4168                            is_star: false,
4169                        },
4170                        selection,
4171                    }),
4172                    None => MergeOption::Unmatch(UnmatchedClause {
4173                        insert_operation: InsertOperation {
4174                            columns: None,
4175                            values,
4176                            is_star: false,
4177                        },
4178                        selection,
4179                    }),
4180                }
4181            },
4182        ),
4183        map(
4184            rule! {
4185                WHEN ~ NOT ~ MATCHED ~ (AND ~ ^#expr)?  ~ THEN ~ INSERT ~ "*"
4186            },
4187            |(_, _, _, expr_op, _, _, _)| {
4188                let selection = match expr_op {
4189                    Some(e) => Some(e.1),
4190                    None => None,
4191                };
4192                MergeOption::Unmatch(UnmatchedClause {
4193                    insert_operation: InsertOperation {
4194                        columns: None,
4195                        values: Vec::new(),
4196                        is_star: true,
4197                    },
4198                    selection,
4199                })
4200            },
4201        ),
4202    ))(i)
4203}
4204
4205pub fn add_column_option(i: Input) -> IResult<AddColumnOption> {
4206    alt((
4207        value(AddColumnOption::First, rule! { FIRST }),
4208        map(rule! { AFTER ~ #ident }, |(_, ident)| {
4209            AddColumnOption::After(ident)
4210        }),
4211    ))(i)
4212}
4213
4214pub fn optimize_table_action(i: Input) -> IResult<OptimizeTableAction> {
4215    alt((
4216        value(OptimizeTableAction::All, rule! { ALL }),
4217        map(
4218            rule! { PURGE ~ (BEFORE ~ ^#travel_point)? },
4219            |(_, opt_travel_point)| OptimizeTableAction::Purge {
4220                before: opt_travel_point.map(|(_, p)| p),
4221            },
4222        ),
4223        map(rule! { COMPACT ~ SEGMENT? }, |(_, opt_segment)| {
4224            OptimizeTableAction::Compact {
4225                target: opt_segment.map_or(CompactTarget::Block, |_| CompactTarget::Segment),
4226            }
4227        }),
4228    ))(i)
4229}
4230
4231pub fn literal_duration(i: Input) -> IResult<Duration> {
4232    let seconds = map(
4233        rule! {
4234            #literal_u64 ~ SECONDS
4235        },
4236        |(v, _)| Duration::from_secs(v),
4237    );
4238
4239    let days = map(
4240        rule! {
4241            #literal_u64 ~ DAYS
4242        },
4243        |(v, _)| Duration::from_secs(v * 60 * 60 * 24),
4244    );
4245
4246    rule!(
4247        #days
4248        | #seconds
4249    )(i)
4250}
4251
4252pub fn vacuum_drop_table_option(i: Input) -> IResult<VacuumDropTableOption> {
4253    alt((map(
4254        rule! {
4255            (DRY ~ ^RUN ~ SUMMARY?)? ~ (LIMIT ~ #literal_u64)?
4256        },
4257        |(opt_dry_run, opt_limit)| VacuumDropTableOption {
4258            dry_run: opt_dry_run.map(|dry_run| dry_run.2.is_some()),
4259            limit: opt_limit.map(|(_, limit)| limit as usize),
4260        },
4261    ),))(i)
4262}
4263
4264pub fn vacuum_table_option(i: Input) -> IResult<VacuumTableOption> {
4265    alt((map(
4266        rule! {
4267            (DRY ~ ^RUN ~ SUMMARY?)?
4268        },
4269        |opt_dry_run| VacuumTableOption {
4270            dry_run: opt_dry_run.map(|dry_run| dry_run.2.is_some()),
4271        },
4272    ),))(i)
4273}
4274
4275pub fn task_sql_block(i: Input) -> IResult<TaskSql> {
4276    let single_statement = map(
4277        rule! {
4278            #statement
4279        },
4280        |stmt| {
4281            let sql = format!("{}", stmt.stmt);
4282            TaskSql::SingleStatement(sql)
4283        },
4284    );
4285    let task_block = map(
4286        rule! {
4287            BEGIN
4288            ~ #semicolon_terminated_list1(statement_body)
4289            ~ END
4290        },
4291        |(_, stmts, _)| {
4292            let sql = stmts
4293                .iter()
4294                .map(|stmt| format!("{}", stmt))
4295                .collect::<Vec<String>>();
4296            TaskSql::ScriptBlock(sql)
4297        },
4298    );
4299    alt((single_statement, task_block))(i)
4300}
4301
4302pub fn alter_task_option(i: Input) -> IResult<AlterTaskOptions> {
4303    let suspend = map(
4304        rule! {
4305             SUSPEND
4306        },
4307        |_| AlterTaskOptions::Suspend,
4308    );
4309    let resume = map(
4310        rule! {
4311             RESUME
4312        },
4313        |_| AlterTaskOptions::Resume,
4314    );
4315    let modify_as = map(
4316        rule! {
4317             MODIFY ~ AS ~ #task_sql_block
4318        },
4319        |(_, _, sql)| AlterTaskOptions::ModifyAs(sql),
4320    );
4321    let modify_when = map(
4322        rule! {
4323             MODIFY ~ WHEN ~ #expr
4324        },
4325        |(_, _, expr)| AlterTaskOptions::ModifyWhen(expr),
4326    );
4327    let add_after = map(
4328        rule! {
4329             ADD ~ AFTER ~ #comma_separated_list0(literal_string)
4330        },
4331        |(_, _, after)| AlterTaskOptions::AddAfter(after),
4332    );
4333    let remove_after = map(
4334        rule! {
4335             REMOVE ~ AFTER ~ #comma_separated_list0(literal_string)
4336        },
4337        |(_, _, after)| AlterTaskOptions::RemoveAfter(after),
4338    );
4339
4340    let set = map(
4341        rule! {
4342             SET
4343             ~ #alter_task_set_option*
4344             ~ #set_table_option?
4345        },
4346        |(_, task_set_options, session_opts)| {
4347            let mut set = AlterTaskOptions::Set {
4348                session_parameters: session_opts,
4349                warehouse: None,
4350                schedule: None,
4351                suspend_task_after_num_failures: None,
4352                comments: None,
4353                error_integration: None,
4354            };
4355            for opt in task_set_options {
4356                set.apply_opt(opt);
4357            }
4358            set
4359        },
4360    );
4361    let unset = map(
4362        rule! {
4363             UNSET ~ WAREHOUSE
4364        },
4365        |_| AlterTaskOptions::Unset { warehouse: true },
4366    );
4367    rule!(
4368        #suspend
4369        | #resume
4370        | #modify_as
4371        | #set
4372        | #unset
4373        | #modify_when
4374        | #add_after
4375        | #remove_after
4376    )(i)
4377}
4378
4379pub fn alter_pipe_option(i: Input) -> IResult<AlterPipeOptions> {
4380    let set = map(
4381        rule! {
4382             SET
4383             ~ ( PIPE_EXECUTION_PAUSED ~ "=" ~ #literal_bool )?
4384             ~ ( COMMENT ~ "=" ~ #literal_string )?
4385        },
4386        |(_, execution_parsed, comment)| AlterPipeOptions::Set {
4387            execution_paused: execution_parsed.map(|(_, _, paused)| paused),
4388            comments: comment.map(|(_, _, comment)| comment),
4389        },
4390    );
4391    let refresh = map(
4392        rule! {
4393             REFRESH
4394             ~ ( PREFIX ~ "=" ~ #literal_string )?
4395             ~ ( MODIFIED_AFTER ~ "=" ~ #literal_string )?
4396        },
4397        |(_, prefix, modified_after)| AlterPipeOptions::Refresh {
4398            prefix: prefix.map(|(_, _, prefix)| prefix),
4399            modified_after: modified_after.map(|(_, _, modified_after)| modified_after),
4400        },
4401    );
4402    rule!(
4403        #set
4404        | #refresh
4405    )(i)
4406}
4407
4408pub fn task_warehouse_option(i: Input) -> IResult<WarehouseOptions> {
4409    alt((map(
4410        rule! {
4411            (WAREHOUSE  ~ "=" ~ #literal_string)?
4412        },
4413        |warehouse_opt| {
4414            let warehouse = match warehouse_opt {
4415                Some(warehouse) => Some(warehouse.2),
4416                None => None,
4417            };
4418            WarehouseOptions { warehouse }
4419        },
4420    ),))(i)
4421}
4422
4423pub fn assign_nodes_list(i: Input) -> IResult<Vec<(Option<String>, u64)>> {
4424    let nodes_list = map(
4425        rule! {
4426            ASSIGN ~ #literal_u64 ~ NODES ~ (FROM ~ #option_to_string)?
4427        },
4428        |(_, node_size, _, node_group)| (node_group.map(|(_, x)| x), node_size),
4429    );
4430
4431    map(comma_separated_list1(nodes_list), |opts| {
4432        opts.into_iter().collect()
4433    })(i)
4434}
4435
4436pub fn assign_warehouse_nodes_list(i: Input) -> IResult<Vec<(Identifier, Option<String>, u64)>> {
4437    let nodes_list = map(
4438        rule! {
4439            ASSIGN ~ #literal_u64 ~ NODES ~ (FROM ~ #option_to_string)? ~ FOR ~ #ident
4440        },
4441        |(_, node_size, _, node_group, _, cluster)| {
4442            (cluster, node_group.map(|(_, x)| x), node_size)
4443        },
4444    );
4445
4446    map(comma_separated_list1(nodes_list), |opts| {
4447        opts.into_iter().collect()
4448    })(i)
4449}
4450
4451pub fn unassign_warehouse_nodes_list(i: Input) -> IResult<Vec<(Identifier, Option<String>, u64)>> {
4452    let nodes_list = map(
4453        rule! {
4454            UNASSIGN ~ #literal_u64 ~ NODES ~ (FROM ~ #option_to_string)? ~ FOR ~ #ident
4455        },
4456        |(_, node_size, _, node_group, _, cluster)| {
4457            (cluster, node_group.map(|(_, x)| x), node_size)
4458        },
4459    );
4460
4461    map(comma_separated_list1(nodes_list), |opts| {
4462        opts.into_iter().collect()
4463    })(i)
4464}
4465
4466pub fn warehouse_cluster_option(i: Input) -> IResult<BTreeMap<String, String>> {
4467    let option = map(
4468        rule! {
4469           #ident ~ "=" ~ #option_to_string
4470        },
4471        |(k, _, v)| (k, v),
4472    );
4473    map(comma_separated_list1(option), |opts| {
4474        opts.into_iter()
4475            .map(|(k, v)| (k.name.to_lowercase(), v.clone()))
4476            .collect()
4477    })(i)
4478}
4479
4480pub fn workload_quotas(i: Input) -> IResult<BTreeMap<String, QuotaValueStmt>> {
4481    let option = map(
4482        rule! {
4483           #ident ~ "=" ~ #option_to_string
4484        },
4485        |(k, _, v)| (k, v),
4486    );
4487
4488    map_res(comma_separated_list1(option), |opts| {
4489        let mut quotas = BTreeMap::new();
4490        for (name, value) in opts {
4491            let name = name.name.to_lowercase();
4492            match QuotaValueStmt::new(&name, value) {
4493                Ok(value) => {
4494                    quotas.insert(name, value);
4495                }
4496                Err(error_desc) => {
4497                    return Err(nom::Err::Failure(ErrorKind::Other(error_desc)));
4498                }
4499            }
4500        }
4501
4502        Ok(quotas)
4503    })(i)
4504}
4505
4506pub fn task_schedule_option(i: Input) -> IResult<ScheduleOptions> {
4507    let interval = map(
4508        rule! {
4509             #literal_u64 ~ MINUTE
4510        },
4511        |(mins, _)| ScheduleOptions::IntervalSecs(mins * 60, 0),
4512    );
4513    let cron_expr = map(
4514        rule! {
4515            USING ~ CRON ~ #literal_string ~ #literal_string?
4516        },
4517        |(_, _, expr, timezone)| ScheduleOptions::CronExpression(expr, timezone),
4518    );
4519    let interval_sec = map(
4520        rule! {
4521             #literal_u64 ~ SECOND
4522        },
4523        |(secs, _)| ScheduleOptions::IntervalSecs(secs, 0),
4524    );
4525    let interval_millis = map(
4526        rule! {
4527             #literal_u64 ~ MILLISECOND
4528        },
4529        |(millis, _)| ScheduleOptions::IntervalSecs(0, millis),
4530    );
4531    rule!(
4532        #interval
4533        | #cron_expr
4534        | #interval_sec
4535        | #interval_millis
4536    )(i)
4537}
4538
4539pub fn kill_target(i: Input) -> IResult<KillTarget> {
4540    alt((
4541        value(KillTarget::Query, rule! { QUERY }),
4542        value(KillTarget::Connection, rule! { CONNECTION }),
4543    ))(i)
4544}
4545
4546pub fn priority(i: Input) -> IResult<Priority> {
4547    alt((
4548        value(Priority::LOW, rule! { LOW }),
4549        value(Priority::MEDIUM, rule! { MEDIUM }),
4550        value(Priority::HIGH, rule! { HIGH }),
4551    ))(i)
4552}
4553
4554pub fn action(i: Input) -> IResult<SystemAction> {
4555    let mut backtrace = map(
4556        rule! {
4557             #switch ~ EXCEPTION_BACKTRACE
4558        },
4559        |(switch, _)| SystemAction::Backtrace(switch),
4560    );
4561    // add other system action type here
4562    rule!(
4563        #backtrace
4564    )(i)
4565}
4566
4567pub fn switch(i: Input) -> IResult<bool> {
4568    alt((
4569        value(true, rule! { ENABLE }),
4570        value(false, rule! { DISABLE }),
4571    ))(i)
4572}
4573
4574pub fn cluster_type(i: Input) -> IResult<ClusterType> {
4575    alt((
4576        value(ClusterType::Linear, rule! { LINEAR }),
4577        value(ClusterType::Hilbert, rule! { HILBERT }),
4578    ))(i)
4579}
4580
4581pub fn limit_where(i: Input) -> IResult<ShowLimit> {
4582    map(
4583        rule! {
4584            WHERE ~ #expr
4585        },
4586        |(_, selection)| ShowLimit::Where {
4587            selection: Box::new(selection),
4588        },
4589    )(i)
4590}
4591
4592pub fn limit_like(i: Input) -> IResult<ShowLimit> {
4593    map(
4594        rule! {
4595            LIKE ~ #literal_string
4596        },
4597        |(_, pattern)| ShowLimit::Like { pattern },
4598    )(i)
4599}
4600
4601pub fn show_limit(i: Input) -> IResult<ShowLimit> {
4602    rule!(
4603        #limit_like
4604        | #limit_where
4605    )(i)
4606}
4607
4608pub fn show_options(i: Input) -> IResult<ShowOptions> {
4609    map(
4610        rule! {
4611            #show_limit? ~ ( LIMIT ~ ^#literal_u64 )?
4612        },
4613        |(show_limit, opt_limit)| ShowOptions {
4614            show_limit,
4615            limit: opt_limit.map(|(_, limit)| limit),
4616        },
4617    )(i)
4618}
4619
4620pub fn table_option(i: Input) -> IResult<BTreeMap<String, String>> {
4621    map(
4622        rule! {
4623           ( #ident ~ "=" ~ #option_to_string )*
4624        },
4625        |opts| {
4626            BTreeMap::from_iter(
4627                opts.iter()
4628                    .map(|(k, _, v)| (k.name.to_lowercase(), v.clone())),
4629            )
4630        },
4631    )(i)
4632}
4633
4634pub fn set_table_option(i: Input) -> IResult<BTreeMap<String, String>> {
4635    let option = map(
4636        rule! {
4637           #ident ~ "=" ~ #option_to_string
4638        },
4639        |(k, _, v)| (k, v),
4640    );
4641
4642    map(comma_separated_list1(option), |opts| {
4643        opts.into_iter()
4644            .map(|(k, v)| (k.name.to_lowercase(), v.clone()))
4645            .collect()
4646    })(i)
4647}
4648
4649pub fn option_to_string(i: Input) -> IResult<String> {
4650    let bool_to_string = |i| map(literal_bool, |v| v.to_string())(i);
4651
4652    rule!(
4653        #bool_to_string
4654        | #parameter_to_string
4655    )(i)
4656}
4657
4658pub fn engine(i: Input) -> IResult<Engine> {
4659    let engine = alt((
4660        value(Engine::Null, rule! { NULL }),
4661        value(Engine::Memory, rule! { MEMORY }),
4662        value(Engine::Fuse, rule! { FUSE }),
4663        value(Engine::View, rule! { VIEW }),
4664        value(Engine::Random, rule! { RANDOM }),
4665        value(Engine::Iceberg, rule! { ICEBERG }),
4666        value(Engine::Delta, rule! { DELTA }),
4667    ));
4668
4669    map(
4670        rule! {
4671            ENGINE ~ ^"=" ~ ^#engine
4672        },
4673        |(_, _, engine)| engine,
4674    )(i)
4675}
4676
4677pub fn database_engine(i: Input) -> IResult<DatabaseEngine> {
4678    value(DatabaseEngine::Default, rule! { DEFAULT })(i)
4679}
4680
4681pub fn create_database_option(i: Input) -> IResult<CreateDatabaseOption> {
4682    let mut create_db_engine = map(
4683        rule! {
4684            ENGINE ~  ^"=" ~ ^#database_engine
4685        },
4686        |(_, _, option)| CreateDatabaseOption::DatabaseEngine(option),
4687    );
4688
4689    rule!(
4690        #create_db_engine
4691    )(i)
4692}
4693
4694pub fn catalog_type(i: Input) -> IResult<CatalogType> {
4695    alt((
4696        value(CatalogType::Default, rule! { DEFAULT }),
4697        value(CatalogType::Hive, rule! { HIVE }),
4698        value(CatalogType::Iceberg, rule! { ICEBERG }),
4699    ))(i)
4700}
4701
4702pub fn user_option(i: Input) -> IResult<UserOptionItem> {
4703    let tenant_setting = value(UserOptionItem::TenantSetting(true), rule! { TENANTSETTING });
4704    let no_tenant_setting = value(
4705        UserOptionItem::TenantSetting(false),
4706        rule! { NOTENANTSETTING },
4707    );
4708    let default_role_option = map(
4709        rule! {
4710            DEFAULT_ROLE ~ ^"=" ~ ^#role_name
4711        },
4712        |(_, _, role)| UserOptionItem::DefaultRole(role),
4713    );
4714    let set_network_policy = map(
4715        rule! {
4716            SET ~ NETWORK ~ ^POLICY ~ ^"=" ~ ^#literal_string
4717        },
4718        |(_, _, _, _, policy)| UserOptionItem::SetNetworkPolicy(policy),
4719    );
4720    let unset_network_policy = map(
4721        rule! {
4722            UNSET ~ NETWORK ~ ^POLICY
4723        },
4724        |(_, _, _)| UserOptionItem::UnsetNetworkPolicy,
4725    );
4726    let set_disabled_option = map(
4727        rule! {
4728            DISABLED ~ ^"=" ~ #literal_bool
4729        },
4730        |(_, _, disabled)| UserOptionItem::Disabled(disabled),
4731    );
4732    let set_password_policy = map(
4733        rule! {
4734            SET ~ PASSWORD ~ ^POLICY ~ ^"=" ~ ^#literal_string
4735        },
4736        |(_, _, _, _, policy)| UserOptionItem::SetPasswordPolicy(policy),
4737    );
4738    let unset_password_policy = map(
4739        rule! {
4740            UNSET ~ PASSWORD ~ ^POLICY
4741        },
4742        |(_, _, _)| UserOptionItem::UnsetPasswordPolicy,
4743    );
4744    let must_change_password = map(
4745        rule! {
4746            MUST_CHANGE_PASSWORD ~ ^"=" ~ ^#literal_bool
4747        },
4748        |(_, _, val)| UserOptionItem::MustChangePassword(val),
4749    );
4750    let set_workload_group = map(
4751        rule! {
4752            SET ~ WORKLOAD ~ ^GROUP ~ ^"=" ~ ^#literal_string
4753        },
4754        |(_, _, _, _, wg)| UserOptionItem::SetWorkloadGroup(wg),
4755    );
4756    let unset_workload_group = map(
4757        rule! {
4758            UNSET ~ WORKLOAD ~ ^GROUP
4759        },
4760        |(_, _, _)| UserOptionItem::UnsetWorkloadGroup,
4761    );
4762
4763    rule!(
4764        #tenant_setting
4765        | #no_tenant_setting
4766        | #default_role_option
4767        | #set_network_policy
4768        | #unset_network_policy
4769        | #set_password_policy
4770        | #unset_password_policy
4771        | #set_disabled_option
4772        | #must_change_password
4773        | #set_workload_group
4774        | #unset_workload_group
4775    )(i)
4776}
4777
4778pub fn user_identity(i: Input) -> IResult<UserIdentity> {
4779    map(
4780        rule! {
4781            #parameter_to_string ~ ( "@" ~ "'%'" )?
4782        },
4783        |(username, _)| {
4784            let hostname = "%".to_string();
4785            UserIdentity { username, hostname }
4786        },
4787    )(i)
4788}
4789
4790pub fn auth_type(i: Input) -> IResult<AuthType> {
4791    alt((
4792        value(AuthType::NoPassword, rule! { NO_PASSWORD }),
4793        value(AuthType::Sha256Password, rule! { SHA256_PASSWORD }),
4794        value(AuthType::DoubleSha1Password, rule! { DOUBLE_SHA1_PASSWORD }),
4795        value(AuthType::JWT, rule! { JWT }),
4796    ))(i)
4797}
4798
4799pub fn presign_action(i: Input) -> IResult<PresignAction> {
4800    alt((
4801        value(PresignAction::Download, rule! { DOWNLOAD }),
4802        value(PresignAction::Upload, rule! { UPLOAD }),
4803    ))(i)
4804}
4805
4806pub fn presign_location(i: Input) -> IResult<PresignLocation> {
4807    map_res(
4808        rule! {
4809            #stage_location
4810        },
4811        |v| Ok(PresignLocation::StageLocation(v)),
4812    )(i)
4813}
4814
4815pub fn presign_option(i: Input) -> IResult<PresignOption> {
4816    alt((
4817        map(rule! { EXPIRE ~ ^"=" ~ ^#literal_u64 }, |(_, _, v)| {
4818            PresignOption::Expire(v)
4819        }),
4820        map(
4821            rule! { CONTENT_TYPE ~ ^"=" ~ ^#literal_string },
4822            |(_, _, v)| PresignOption::ContentType(v),
4823        ),
4824    ))(i)
4825}
4826
4827pub fn table_reference_with_alias(i: Input) -> IResult<TableReference> {
4828    map(
4829        consumed(rule! {
4830            #dot_separated_idents_1_to_3 ~ #alias_name?
4831        }),
4832        |(span, ((catalog, database, table), alias))| TableReference::Table {
4833            span: transform_span(span.tokens),
4834            catalog,
4835            database,
4836            table,
4837            alias: alias.map(|v| TableAlias {
4838                name: v,
4839                columns: vec![],
4840            }),
4841            temporal: None,
4842            with_options: None,
4843            pivot: None,
4844            unpivot: None,
4845            sample: None,
4846        },
4847    )(i)
4848}
4849
4850pub fn update_expr(i: Input) -> IResult<UpdateExpr> {
4851    map(rule! { ( #ident ~ "=" ~ ^#expr ) }, |(name, _, expr)| {
4852        UpdateExpr { name, expr }
4853    })(i)
4854}
4855
4856pub fn udaf_state_field(i: Input) -> IResult<UDAFStateField> {
4857    map(
4858        rule! {
4859            #ident
4860            ~ #type_name
4861            : "`<state name> <type>`"
4862        },
4863        |(name, type_name)| UDAFStateField { name, type_name },
4864    )(i)
4865}
4866
4867pub fn udf_header(i: Input) -> IResult<(String, String)> {
4868    map(
4869        rule! {
4870            #literal_string ~ #match_text("=") ~ ^#literal_string
4871        },
4872        |(k, _, v)| (k, v),
4873    )(i)
4874}
4875
4876pub fn udf_script_or_address(i: Input) -> IResult<(String, bool)> {
4877    let script = map(
4878        rule! {
4879            AS ~ ^(#code_string | #literal_string)
4880        },
4881        |(_, code)| (code, true),
4882    );
4883
4884    let address = map(
4885        rule! {
4886            ADDRESS ~ ^"=" ~ ^#literal_string
4887        },
4888        |(_, _, address)| (address, false),
4889    );
4890
4891    rule!(
4892        #script: "AS <language_codes>"
4893        | #address: "ADDRESS=<udf_server_address>"
4894    )(i)
4895}
4896
4897pub fn udf_definition(i: Input) -> IResult<UDFDefinition> {
4898    let lambda_udf = map(
4899        rule! {
4900            AS ~ "(" ~ #comma_separated_list0(ident) ~ ")"
4901            ~ "->" ~ #expr
4902        },
4903        |(_, _, parameters, _, _, definition)| UDFDefinition::LambdaUDF {
4904            parameters,
4905            definition: Box::new(definition),
4906        },
4907    );
4908
4909    let udf = map(
4910        rule! {
4911            "(" ~ #comma_separated_list0(type_name) ~ ")"
4912            ~ RETURNS ~ #type_name
4913            ~ LANGUAGE ~ #ident
4914            ~ (#udf_immutable)?
4915            ~ ( IMPORTS ~ ^"=" ~ "(" ~ #comma_separated_list0(literal_string) ~ ")" )?
4916            ~ ( PACKAGES ~ ^"=" ~ "(" ~ #comma_separated_list0(literal_string) ~ ")" )?
4917            ~ HANDLER ~ ^"=" ~ ^#literal_string
4918            ~ ( HEADERS ~ ^"=" ~ "(" ~ #comma_separated_list0(udf_header) ~ ")" )?
4919            ~ #udf_script_or_address
4920        },
4921        |(
4922            _,
4923            arg_types,
4924            _,
4925            _,
4926            return_type,
4927            _,
4928            language,
4929            immutable,
4930            imports,
4931            packages,
4932            _,
4933            _,
4934            handler,
4935            headers,
4936            address_or_code,
4937        )| {
4938            if address_or_code.1 {
4939                UDFDefinition::UDFScript {
4940                    arg_types,
4941                    return_type,
4942                    code: address_or_code.0,
4943                    imports: imports
4944                        .map(|(_, _, _, imports, _)| imports)
4945                        .unwrap_or_default(),
4946                    packages: packages
4947                        .map(|(_, _, _, packages, _)| packages)
4948                        .unwrap_or_default(),
4949                    handler,
4950                    language: language.to_string(),
4951                    // TODO inject runtime_version by user
4952                    // Now we use fixed runtime version
4953                    runtime_version: "".to_string(),
4954                    immutable,
4955                }
4956            } else {
4957                UDFDefinition::UDFServer {
4958                    arg_types,
4959                    return_type,
4960                    address: address_or_code.0,
4961                    handler,
4962                    language: language.to_string(),
4963                    headers: headers
4964                        .map(|(_, _, _, headers, _)| BTreeMap::from_iter(headers))
4965                        .unwrap_or_default(),
4966                    immutable,
4967                }
4968            }
4969        },
4970    );
4971
4972    let udaf = map(
4973        rule! {
4974            "(" ~ #comma_separated_list0(type_name) ~ ")"
4975            ~ STATE ~ "{" ~ #comma_separated_list0(udaf_state_field) ~ "}"
4976            ~ RETURNS ~ #type_name
4977            ~ LANGUAGE ~ #ident
4978            ~ ( IMPORTS ~ ^"=" ~ "(" ~ #comma_separated_list0(literal_string) ~ ")" )?
4979            ~ ( PACKAGES ~ ^"=" ~ "(" ~ #comma_separated_list0(literal_string) ~ ")" )?
4980            ~ ( HEADERS ~ ^"=" ~ "(" ~ #comma_separated_list0(udf_header) ~ ")" )?
4981            ~ #udf_script_or_address
4982        },
4983        |(
4984            _,
4985            arg_types,
4986            _,
4987            _,
4988            _,
4989            state_types,
4990            _,
4991            _,
4992            return_type,
4993            _,
4994            language,
4995            imports,
4996            packages,
4997            headers,
4998            address_or_code,
4999        )| {
5000            if address_or_code.1 {
5001                UDFDefinition::UDAFScript {
5002                    arg_types,
5003                    state_fields: state_types,
5004                    return_type,
5005                    code: address_or_code.0,
5006                    language: language.to_string(),
5007                    imports: imports
5008                        .map(|(_, _, _, imports, _)| imports)
5009                        .unwrap_or_default(),
5010                    packages: packages
5011                        .map(|(_, _, _, packages, _)| packages)
5012                        .unwrap_or_default(),
5013                    // TODO inject runtime_version by user
5014                    // Now we use fixed runtime version
5015                    runtime_version: "".to_string(),
5016                }
5017            } else {
5018                UDFDefinition::UDAFServer {
5019                    arg_types,
5020                    state_fields: state_types,
5021                    return_type,
5022                    address: address_or_code.0,
5023                    headers: headers
5024                        .map(|(_, _, _, headers, _)| BTreeMap::from_iter(headers))
5025                        .unwrap_or_default(),
5026                    language: language.to_string(),
5027                }
5028            }
5029        },
5030    );
5031
5032    rule!(
5033        #lambda_udf: "AS (<parameter>, ...) -> <definition expr>"
5034        | #udaf: "(<arg_type>, ...) STATE {<state_field>, ...} RETURNS <return_type> LANGUAGE <language> { ADDRESS=<udf_server_address> | AS <language_codes> } "
5035        | #udf: "(<arg_type>, ...) RETURNS <return_type> LANGUAGE <language> HANDLER=<handler> { ADDRESS=<udf_server_address> | AS <language_codes> } "
5036
5037    )(i)
5038}
5039
5040fn udf_immutable(i: Input) -> IResult<bool> {
5041    alt((
5042        value(false, rule! { VOLATILE }),
5043        value(true, rule! { IMMUTABLE }),
5044    ))(i)
5045}
5046
5047pub fn mutation_update_expr(i: Input) -> IResult<MutationUpdateExpr> {
5048    map(
5049        rule! { #dot_separated_idents_1_to_2 ~ "=" ~ ^#expr },
5050        |((table, name), _, expr)| MutationUpdateExpr { table, name, expr },
5051    )(i)
5052}
5053
5054pub fn password_set_options(i: Input) -> IResult<PasswordSetOptions> {
5055    map(
5056        rule! {
5057             ( PASSWORD_MIN_LENGTH ~ Eq ~ ^#literal_u64 )?
5058             ~ ( PASSWORD_MAX_LENGTH ~ Eq ~ ^#literal_u64 )?
5059             ~ ( PASSWORD_MIN_UPPER_CASE_CHARS ~ Eq ~ ^#literal_u64 )?
5060             ~ ( PASSWORD_MIN_LOWER_CASE_CHARS ~ Eq ~ ^#literal_u64 )?
5061             ~ ( PASSWORD_MIN_NUMERIC_CHARS ~ Eq ~ ^#literal_u64 )?
5062             ~ ( PASSWORD_MIN_SPECIAL_CHARS ~ Eq ~ ^#literal_u64 )?
5063             ~ ( PASSWORD_MIN_AGE_DAYS ~ Eq ~ ^#literal_u64 )?
5064             ~ ( PASSWORD_MAX_AGE_DAYS ~ Eq ~ ^#literal_u64 )?
5065             ~ ( PASSWORD_MAX_RETRIES ~ Eq ~ ^#literal_u64 )?
5066             ~ ( PASSWORD_LOCKOUT_TIME_MINS ~ Eq ~ ^#literal_u64 )?
5067             ~ ( PASSWORD_HISTORY ~ Eq ~ ^#literal_u64 )?
5068             ~ ( COMMENT ~ Eq ~ ^#literal_string)?
5069        },
5070        |(
5071            opt_min_length,
5072            opt_max_length,
5073            opt_min_upper_case_chars,
5074            opt_min_lower_case_chars,
5075            opt_min_numeric_chars,
5076            opt_min_special_chars,
5077            opt_min_age_days,
5078            opt_max_age_days,
5079            opt_max_retries,
5080            opt_lockout_time_mins,
5081            opt_history,
5082            opt_comment,
5083        )| {
5084            PasswordSetOptions {
5085                min_length: opt_min_length.map(|opt| opt.2),
5086                max_length: opt_max_length.map(|opt| opt.2),
5087                min_upper_case_chars: opt_min_upper_case_chars.map(|opt| opt.2),
5088                min_lower_case_chars: opt_min_lower_case_chars.map(|opt| opt.2),
5089                min_numeric_chars: opt_min_numeric_chars.map(|opt| opt.2),
5090                min_special_chars: opt_min_special_chars.map(|opt| opt.2),
5091                min_age_days: opt_min_age_days.map(|opt| opt.2),
5092                max_age_days: opt_max_age_days.map(|opt| opt.2),
5093                max_retries: opt_max_retries.map(|opt| opt.2),
5094                lockout_time_mins: opt_lockout_time_mins.map(|opt| opt.2),
5095                history: opt_history.map(|opt| opt.2),
5096                comment: opt_comment.map(|opt| opt.2),
5097            }
5098        },
5099    )(i)
5100}
5101
5102pub fn password_unset_options(i: Input) -> IResult<PasswordUnSetOptions> {
5103    map(
5104        rule! {
5105             PASSWORD_MIN_LENGTH?
5106             ~ PASSWORD_MAX_LENGTH?
5107             ~ PASSWORD_MIN_UPPER_CASE_CHARS?
5108             ~ PASSWORD_MIN_LOWER_CASE_CHARS?
5109             ~ PASSWORD_MIN_NUMERIC_CHARS?
5110             ~ PASSWORD_MIN_SPECIAL_CHARS?
5111             ~ PASSWORD_MIN_AGE_DAYS?
5112             ~ PASSWORD_MAX_AGE_DAYS?
5113             ~ PASSWORD_MAX_RETRIES?
5114             ~ PASSWORD_LOCKOUT_TIME_MINS?
5115             ~ PASSWORD_HISTORY?
5116             ~ COMMENT?
5117        },
5118        |(
5119            opt_min_length,
5120            opt_max_length,
5121            opt_min_upper_case_chars,
5122            opt_min_lower_case_chars,
5123            opt_min_numeric_chars,
5124            opt_min_special_chars,
5125            opt_min_age_days,
5126            opt_max_age_days,
5127            opt_max_retries,
5128            opt_lockout_time_mins,
5129            opt_history,
5130            opt_comment,
5131        )| {
5132            PasswordUnSetOptions {
5133                min_length: opt_min_length.is_some(),
5134                max_length: opt_max_length.is_some(),
5135                min_upper_case_chars: opt_min_upper_case_chars.is_some(),
5136                min_lower_case_chars: opt_min_lower_case_chars.is_some(),
5137                min_numeric_chars: opt_min_numeric_chars.is_some(),
5138                min_special_chars: opt_min_special_chars.is_some(),
5139                min_age_days: opt_min_age_days.is_some(),
5140                max_age_days: opt_max_age_days.is_some(),
5141                max_retries: opt_max_retries.is_some(),
5142                lockout_time_mins: opt_lockout_time_mins.is_some(),
5143                history: opt_history.is_some(),
5144                comment: opt_comment.is_some(),
5145            }
5146        },
5147    )(i)
5148}
5149
5150pub fn alter_password_action(i: Input) -> IResult<AlterPasswordAction> {
5151    let set_options = map(
5152        rule! {
5153           SET ~ #password_set_options
5154        },
5155        |(_, set_options)| AlterPasswordAction::SetOptions(set_options),
5156    );
5157    let unset_options = map(
5158        rule! {
5159           UNSET ~ #password_unset_options
5160        },
5161        |(_, unset_options)| AlterPasswordAction::UnSetOptions(unset_options),
5162    );
5163
5164    rule!(
5165        #set_options
5166        | #unset_options
5167    )(i)
5168}
5169
5170pub fn explain_option(i: Input) -> IResult<ExplainOption> {
5171    map(
5172        rule! {
5173            VERBOSE | LOGICAL | OPTIMIZED | DECORRELATED
5174        },
5175        |opt| match &opt.kind {
5176            VERBOSE => ExplainOption::Verbose,
5177            LOGICAL => ExplainOption::Logical,
5178            OPTIMIZED => ExplainOption::Optimized,
5179            DECORRELATED => ExplainOption::Decorrelated,
5180            _ => unreachable!(),
5181        },
5182    )(i)
5183}
5184
5185pub fn create_task_option(i: Input) -> IResult<CreateTaskOption> {
5186    let warehouse_opt = map(
5187        rule! {
5188            (WAREHOUSE  ~ "=" ~ #literal_string)
5189        },
5190        |(_, _, warehouse)| CreateTaskOption::Warehouse(warehouse),
5191    );
5192    let schedule_opt = map(
5193        rule! {
5194            SCHEDULE ~ "=" ~ #task_schedule_option
5195        },
5196        |(_, _, schedule)| CreateTaskOption::Schedule(schedule),
5197    );
5198    let after_opt = map(
5199        rule! {
5200            AFTER ~ #comma_separated_list0(literal_string)
5201        },
5202        |(_, after)| CreateTaskOption::After(after),
5203    );
5204    let when_opt = map(
5205        rule! {
5206            WHEN ~ #expr
5207        },
5208        |(_, expr)| CreateTaskOption::When(expr),
5209    );
5210    let suspend_task_after_num_failures_opt = map(
5211        rule! {
5212            SUSPEND_TASK_AFTER_NUM_FAILURES ~ "=" ~ #literal_u64
5213        },
5214        |(_, _, num)| CreateTaskOption::SuspendTaskAfterNumFailures(num),
5215    );
5216    let error_integration_opt = map(
5217        rule! {
5218            ERROR_INTEGRATION ~ "=" ~ #literal_string
5219        },
5220        |(_, _, integration)| CreateTaskOption::ErrorIntegration(integration),
5221    );
5222    let comment_opt = map(
5223        rule! {
5224            (COMMENT | COMMENTS) ~ "=" ~ #literal_string
5225        },
5226        |(_, _, comment)| CreateTaskOption::Comment(comment),
5227    );
5228
5229    map(
5230        rule! {
5231            #warehouse_opt
5232            | #schedule_opt
5233            | #after_opt
5234            | #when_opt
5235            | #suspend_task_after_num_failures_opt
5236            | #error_integration_opt
5237            | #comment_opt
5238        },
5239        |opt| opt,
5240    )(i)
5241}
5242
5243fn alter_task_set_option(i: Input) -> IResult<AlterTaskSetOption> {
5244    let warehouse_opt = map(
5245        rule! {
5246            (WAREHOUSE  ~ "=" ~ #literal_string)
5247        },
5248        |(_, _, warehouse)| AlterTaskSetOption::Warehouse(warehouse),
5249    );
5250    let schedule_opt = map(
5251        rule! {
5252            SCHEDULE ~ "=" ~ #task_schedule_option
5253        },
5254        |(_, _, schedule)| AlterTaskSetOption::Schedule(schedule),
5255    );
5256    let suspend_task_after_num_failures_opt = map(
5257        rule! {
5258            SUSPEND_TASK_AFTER_NUM_FAILURES ~ "=" ~ #literal_u64
5259        },
5260        |(_, _, num)| AlterTaskSetOption::SuspendTaskAfterNumFailures(num),
5261    );
5262    let error_integration_opt = map(
5263        rule! {
5264            ERROR_INTEGRATION ~ "=" ~ #literal_string
5265        },
5266        |(_, _, integration)| AlterTaskSetOption::ErrorIntegration(integration),
5267    );
5268    let comment_opt = map(
5269        rule! {
5270            (COMMENT | COMMENTS) ~ "=" ~ #literal_string
5271        },
5272        |(_, _, comment)| AlterTaskSetOption::Comment(comment),
5273    );
5274
5275    map(
5276        rule! {
5277            #warehouse_opt
5278            | #schedule_opt
5279            | #suspend_task_after_num_failures_opt
5280            | #error_integration_opt
5281            | #comment_opt
5282        },
5283        |opt| opt,
5284    )(i)
5285}
5286
5287pub fn notification_webhook_options(i: Input) -> IResult<NotificationWebhookOptions> {
5288    let url_option = map(
5289        rule! {
5290            URL ~ "=" ~ #literal_string
5291        },
5292        |(_, _, v)| ("url".to_string(), v.to_string()),
5293    );
5294    let method_option = map(
5295        rule! {
5296            METHOD ~ "=" ~ #literal_string
5297        },
5298        |(_, _, v)| ("method".to_string(), v.to_string()),
5299    );
5300    let auth_option = map(
5301        rule! {
5302            AUTHORIZATION_HEADER ~ "=" ~ #literal_string
5303        },
5304        |(_, _, v)| ("authorization_header".to_string(), v.to_string()),
5305    );
5306
5307    map(
5308        rule! { ((
5309        #url_option
5310        | #method_option
5311        | #auth_option) ~ ","?)* },
5312        |opts| {
5313            NotificationWebhookOptions::from_iter(
5314                opts.iter().map(|((k, v), _)| (k.to_uppercase(), v.clone())),
5315            )
5316        },
5317    )(i)
5318}
5319
5320pub fn notification_webhook_clause(i: Input) -> IResult<NotificationWebhookOptions> {
5321    map(
5322        rule! { WEBHOOK ~ ^"=" ~ ^"(" ~ ^#notification_webhook_options ~ ^")" },
5323        |(_, _, _, opts, _)| opts,
5324    )(i)
5325}
5326
5327pub fn alter_notification_options(i: Input) -> IResult<AlterNotificationOptions> {
5328    let enabled = map(
5329        rule! {
5330            SET ~ ENABLED ~ ^"=" ~ #literal_bool
5331        },
5332        |(_, _, _, enabled)| {
5333            AlterNotificationOptions::Set(AlterNotificationSetOptions::enabled(enabled))
5334        },
5335    );
5336    let webhook = map(
5337        rule! {
5338            SET ~ #notification_webhook_clause
5339        },
5340        |(_, webhook)| {
5341            AlterNotificationOptions::Set(AlterNotificationSetOptions::webhook_opts(webhook))
5342        },
5343    );
5344    let comment = map(
5345        rule! {
5346            SET ~ (COMMENT | COMMENTS) ~ ^"=" ~ #literal_string
5347        },
5348        |(_, _, _, comment)| {
5349            AlterNotificationOptions::Set(AlterNotificationSetOptions::comments(comment))
5350        },
5351    );
5352    map(
5353        rule! {
5354            #enabled
5355            | #webhook
5356            | #comment
5357        },
5358        |opts| opts,
5359    )(i)
5360}
5361
5362fn index_type(i: Input) -> IResult<TableIndexType> {
5363    alt((
5364        value(TableIndexType::Inverted, rule! { INVERTED }),
5365        value(TableIndexType::Ngram, rule! { NGRAM }),
5366        value(TableIndexType::Vector, rule! { VECTOR }),
5367    ))(i)
5368}