databend_common_ast/parser/
dynamic_table.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 nom::branch::alt;
16use nom::branch::permutation;
17use nom::combinator::map;
18use nom::combinator::value;
19use nom_rule::rule;
20
21use crate::ast::ClusterOption;
22use crate::ast::ClusterType;
23use crate::ast::CreateDynamicTableStmt;
24use crate::ast::InitializeMode;
25use crate::ast::RefreshMode;
26use crate::ast::Statement;
27use crate::ast::TargetLag;
28use crate::ast::WarehouseOptions;
29use crate::parser::common::comma_separated_list1;
30use crate::parser::common::dot_separated_idents_1_to_3;
31use crate::parser::common::map_res;
32use crate::parser::common::IResult;
33use crate::parser::common::*;
34use crate::parser::expr::expr;
35use crate::parser::expr::literal_u64;
36use crate::parser::query::query;
37use crate::parser::statement::cluster_type;
38use crate::parser::statement::create_table_source;
39use crate::parser::statement::parse_create_option;
40use crate::parser::statement::table_option;
41use crate::parser::statement::task_warehouse_option;
42use crate::parser::token::TokenKind::*;
43use crate::parser::Input;
44
45pub fn dynamic_table(i: Input) -> IResult<Statement> {
46    rule!(
47        #create_dynamic_table : "`CREATE [OR REPLACE] [TRANSIENT] DYNAMIC TABLE [ IF NOT EXISTS ] [<database>.]<table> [<source>]
48  [ CLUSTER BY <expr> ]
49  TARGET_LAG = { <num> { SECOND | MINUTE | HOUR | DAY } | DOWNSTREAM}
50  [ { WAREHOUSE = <string> } ]
51  [ REFRESH_MODE = { AUTO | FULL | INCREMENTAL } ]
52  [ INITIALIZE = { ON_CREATE | ON_SCHEDULE } ]
53  [ COMMENT = '<string_literal>' ]
54AS
55  <sql>`"
56    )(i)
57}
58
59fn create_dynamic_table(i: Input) -> IResult<Statement> {
60    map_res(
61        rule! {
62            CREATE ~ ( OR ~ ^REPLACE )? ~ TRANSIENT? ~ DYNAMIC ~ TABLE ~ ( IF ~ ^NOT ~ ^EXISTS )?
63            ~ #dot_separated_idents_1_to_3
64            ~ #create_table_source?
65            ~ ( CLUSTER ~ ^BY ~ ( #cluster_type )? ~ ^"(" ~ ^#comma_separated_list1(expr) ~ ^")" )?
66            ~ #dynamic_table_options
67            ~ (#table_option)?
68            ~ (AS ~ ^#query)
69        },
70        |(
71            _,
72            opt_or_replace,
73            opt_transient,
74            _,
75            _,
76            opt_if_not_exists,
77            (catalog, database, table),
78            source,
79            opt_cluster_by,
80            (target_lag, warehouse_opts, refresh_mode_opt, initialize_opt),
81            opt_table_options,
82            (_, query),
83        )| {
84            let create_option =
85                parse_create_option(opt_or_replace.is_some(), opt_if_not_exists.is_some())?;
86            Ok(Statement::CreateDynamicTable(CreateDynamicTableStmt {
87                create_option,
88                transient: opt_transient.is_some(),
89                catalog,
90                database,
91                table,
92                source,
93                cluster_by: opt_cluster_by.map(|(_, _, typ, _, cluster_exprs, _)| ClusterOption {
94                    cluster_type: typ.unwrap_or(ClusterType::Linear),
95                    cluster_exprs,
96                }),
97                target_lag,
98                warehouse_opts,
99                refresh_mode: refresh_mode_opt.unwrap_or(RefreshMode::Auto),
100                initialize: initialize_opt.unwrap_or(InitializeMode::OnCreate),
101                table_options: opt_table_options.unwrap_or_default(),
102                as_query: Box::new(query),
103            }))
104        },
105    )(i)
106}
107
108fn dynamic_table_options(
109    i: Input,
110) -> IResult<(
111    TargetLag,
112    WarehouseOptions,
113    Option<RefreshMode>,
114    Option<InitializeMode>,
115)> {
116    let target_lag = map(
117        rule! {
118            TARGET_LAG ~ "=" ~ #target_lag
119        },
120        |(_, _, target_lag)| target_lag,
121    );
122
123    let refresh_mode = alt((
124        value(RefreshMode::Auto, rule! { AUTO }),
125        value(RefreshMode::Full, rule! { FULL }),
126        value(RefreshMode::Incremental, rule! { INCREMENTAL }),
127    ));
128    let refresh_mode_opt = map(
129        rule! {
130            (REFRESH_MODE ~ "=" ~ #refresh_mode)?
131        },
132        |v| v.map(|v| v.2),
133    );
134
135    let initialize_mode = alt((
136        value(InitializeMode::OnCreate, rule! { ON_CREATE }),
137        value(InitializeMode::OnSchedule, rule! { ON_SCHEDULE }),
138    ));
139    let initialize_opt = map(
140        rule! {
141            (INITIALIZE ~ "=" ~ #initialize_mode)?
142        },
143        |v| v.map(|v| v.2),
144    );
145
146    permutation((
147        target_lag,
148        task_warehouse_option,
149        refresh_mode_opt,
150        initialize_opt,
151    ))(i)
152}
153
154fn target_lag(i: Input) -> IResult<TargetLag> {
155    let interval_sec = map(
156        rule! {
157             #literal_u64 ~ SECOND
158        },
159        |(secs, _)| TargetLag::IntervalSecs(secs),
160    );
161    let interval_min = map(
162        rule! {
163             #literal_u64 ~ MINUTE
164        },
165        |(mins, _)| TargetLag::IntervalSecs(mins * 60),
166    );
167    let interval_hour = map(
168        rule! {
169             #literal_u64 ~ HOUR
170        },
171        |(hours, _)| TargetLag::IntervalSecs(hours * 60 * 60),
172    );
173    let interval_day = map(
174        rule! {
175             #literal_u64 ~ DAY
176        },
177        |(days, _)| TargetLag::IntervalSecs(days * 60 * 60 * 24),
178    );
179    let downstream = map(
180        rule! {
181            DOWNSTREAM
182        },
183        |_| TargetLag::Downstream,
184    );
185    rule!(
186        #interval_sec
187        | #interval_min
188        | #interval_hour
189        | #interval_day
190        | #downstream
191    )(i)
192}