Skip to main content

databend_common_ast/parser/
query.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;
16
17use nom::Parser;
18use nom::error::context;
19use nom_rule::rule;
20use pratt::Affix;
21use pratt::Associativity;
22use pratt::PrattParser;
23use pratt::Precedence;
24
25use crate::Range;
26use crate::ast::*;
27use crate::parser::ErrorKind;
28use crate::parser::common::*;
29use crate::parser::expr::*;
30use crate::parser::input::Input;
31use crate::parser::input::WithSpan;
32use crate::parser::stage::file_location;
33use crate::parser::stage::select_stage_option;
34use crate::parser::statement::hint;
35use crate::parser::statement::set_table_option;
36use crate::parser::statement::top_n;
37use crate::parser::token::*;
38
39pub fn query(i: Input) -> IResult<Query> {
40    context(
41        "`SELECT ...`",
42        map(set_operation, |set_expr| set_expr.into_query()),
43    )
44    .parse(i)
45}
46
47pub fn set_operation(i: Input) -> IResult<SetExpr> {
48    let (rest, set_operation_elements) = rule! { #set_operation_element+ }.parse(i)?;
49    run_pratt_parser(SetOperationParser, set_operation_elements, rest, i)
50}
51
52#[derive(Debug, Clone, PartialEq)]
53#[allow(clippy::large_enum_variant)]
54pub enum SetOperationElement {
55    With(With),
56    SelectStmt {
57        hints: Option<Hint>,
58        distinct: bool,
59        top_n: Option<u64>,
60        select_list: Vec<SelectTarget>,
61        from: Vec<TableReference>,
62        selection: Option<Expr>,
63        group_by: Option<GroupBy>,
64        having: Option<Expr>,
65        window_list: Option<Vec<WindowDefinition>>,
66        qualify: Option<Expr>,
67    },
68    SetOperation {
69        op: SetOperator,
70        all: bool,
71    },
72    Values(Vec<Vec<Expr>>),
73    OrderBy {
74        order_by: Vec<OrderByExpr>,
75    },
76    Limit {
77        limit: Vec<Expr>,
78    },
79    Offset {
80        offset: Expr,
81    },
82    IgnoreResult,
83    Group(SetExpr),
84}
85
86pub fn set_operation_element(i: Input) -> IResult<WithSpan<SetOperationElement>> {
87    let with = map(with, SetOperationElement::With);
88    let set_operator = map(
89        rule! {
90            ( UNION | EXCEPT | INTERSECT ) ~ ALL?
91        },
92        |(op, all)| {
93            let op = match op.kind {
94                UNION => SetOperator::Union,
95                INTERSECT => SetOperator::Intersect,
96                EXCEPT => SetOperator::Except,
97                _ => unreachable!(),
98            };
99            SetOperationElement::SetOperation {
100                op,
101                all: all.is_some(),
102            }
103        },
104    );
105    let from_stmt = map_res(
106        rule! {
107            FROM ~ ^#comma_separated_list1(table_reference)
108        },
109        |(_from, from_block)| {
110            if from_block.len() != 1 {
111                return Err(nom::Err::Failure(ErrorKind::Other(
112                    "FROM query only support query one table",
113                )));
114            }
115            Ok(SetOperationElement::SelectStmt {
116                hints: None,
117                distinct: false,
118                top_n: None,
119                select_list: vec![SelectTarget::StarColumns {
120                    qualified: vec![Indirection::Star(Some(Range { start: 0, end: 0 }))],
121                    column_filter: None,
122                }],
123                from: from_block,
124                selection: None,
125                group_by: None,
126                having: None,
127                window_list: None,
128                qualify: None,
129            })
130        },
131    );
132
133    let select_stmt = map_res(
134        rule! {
135            ( FROM ~ ^#comma_separated_list1(table_reference) )?
136            ~ SELECT ~ #hint? ~ DISTINCT? ~ #top_n? ~ ^#comma_separated_list1(select_target)
137            ~ ( FROM ~ ^#comma_separated_list1(table_reference) )?
138            ~ ( WHERE ~ ^#expr )?
139            ~ ( GROUP ~ ^BY ~ ^#group_by_items )?
140            ~ ( HAVING ~ ^#expr )?
141            ~ ( WINDOW ~ ^#comma_separated_list1(window_clause) )?
142            ~ ( QUALIFY ~ ^#expr )?
143        },
144        |(
145            opt_from_block_first,
146            _select,
147            opt_hints,
148            opt_distinct,
149            opt_top_n,
150            select_list,
151            opt_from_block_second,
152            opt_where_block,
153            opt_group_by_block,
154            opt_having_block,
155            opt_window_block,
156            opt_qualify_block,
157        )| {
158            if opt_from_block_first.is_some() && opt_from_block_second.is_some() {
159                return Err(nom::Err::Failure(ErrorKind::Other(
160                    "duplicated FROM clause",
161                )));
162            }
163
164            Ok(SetOperationElement::SelectStmt {
165                hints: opt_hints,
166                distinct: opt_distinct.is_some(),
167                top_n: opt_top_n,
168                select_list,
169                from: opt_from_block_first
170                    .or(opt_from_block_second)
171                    .map(|(_, table_refs)| table_refs)
172                    .unwrap_or_default(),
173                selection: opt_where_block.map(|(_, selection)| selection),
174                group_by: opt_group_by_block.map(|(_, _, group_by)| group_by),
175                having: opt_having_block.map(|(_, having)| having),
176                window_list: opt_window_block.map(|(_, windows)| windows),
177                qualify: opt_qualify_block.map(|(_, qualify)| qualify),
178            })
179        },
180    );
181
182    let values = map(
183        rule! {
184            VALUES ~ ^#comma_separated_list1(row_values)
185        },
186        |(_, values)| SetOperationElement::Values(values),
187    );
188    let order_by = map(
189        rule! {
190            ORDER ~ ^BY ~ ^#comma_separated_list1(order_by_expr)
191        },
192        |(_, _, order_by)| SetOperationElement::OrderBy { order_by },
193    );
194    let limit = map(
195        rule! {
196            LIMIT ~ ^#comma_separated_list1(expr)
197        },
198        |(_, limit)| SetOperationElement::Limit { limit },
199    );
200    let offset = map(
201        rule! {
202            OFFSET ~ ^#expr
203        },
204        |(_, offset)| SetOperationElement::Offset { offset },
205    );
206    let ignore_result = map(
207        rule! {
208            IGNORE_RESULT
209        },
210        |_| SetOperationElement::IgnoreResult,
211    );
212    let group = map(
213        rule! {
214           "(" ~ #set_operation ~ ^")"
215        },
216        |(_, set_expr, _)| SetOperationElement::Group(set_expr),
217    );
218
219    map(
220        consumed(rule! {
221            #group
222            | #with
223            | #set_operator
224            | #select_stmt
225            | #from_stmt
226            | #values
227            | #order_by
228            | #limit
229            | #offset
230            | #ignore_result
231        }),
232        |(span, elem)| WithSpan { span, elem },
233    )
234    .parse(i)
235}
236
237struct SetOperationParser;
238
239impl<'a, I: Iterator<Item = WithSpan<'a, SetOperationElement>>> PrattParser<I>
240    for SetOperationParser
241{
242    type Error = &'static str;
243    type Input = WithSpan<'a, SetOperationElement>;
244    type Output = SetExpr;
245
246    fn query(&mut self, input: &Self::Input) -> Result<Affix, &'static str> {
247        let affix = match &input.elem {
248            // https://learn.microsoft.com/en-us/sql/t-sql/language-elements/set-operators-except-and-intersect-transact-sql?view=sql-server-2017
249            // If EXCEPT or INTERSECT is used together with other operators in an expression, it's evaluated in the context of the following precedence:
250            // 1. Expressions in parentheses
251            // 2. The INTERSECT operator
252            // 3. EXCEPT and UNION evaluated from left to right based on their position in the expression
253            SetOperationElement::SetOperation { op, .. } => match op {
254                SetOperator::Union | SetOperator::Except => {
255                    Affix::Infix(Precedence(10), Associativity::Left)
256                }
257                SetOperator::Intersect => Affix::Infix(Precedence(20), Associativity::Left),
258            },
259            SetOperationElement::With(_) => Affix::Prefix(Precedence(5)),
260            SetOperationElement::OrderBy { .. } => Affix::Postfix(Precedence(5)),
261            SetOperationElement::Limit { .. } => Affix::Postfix(Precedence(5)),
262            SetOperationElement::Offset { .. } => Affix::Postfix(Precedence(5)),
263            SetOperationElement::IgnoreResult => Affix::Postfix(Precedence(5)),
264            _ => Affix::Nilfix,
265        };
266        Ok(affix)
267    }
268
269    fn primary(&mut self, input: Self::Input) -> Result<Self::Output, &'static str> {
270        let set_expr = match input.elem {
271            SetOperationElement::Group(expr) => expr,
272            SetOperationElement::SelectStmt {
273                hints,
274                distinct,
275                top_n,
276                select_list,
277                from,
278                selection,
279                group_by,
280                having,
281                window_list,
282                qualify,
283            } => SetExpr::Select(Box::new(SelectStmt {
284                span: transform_span(input.span.tokens),
285                hints,
286                top_n,
287                distinct,
288                select_list,
289                from,
290                selection,
291                group_by,
292                having,
293                window_list,
294                qualify,
295            })),
296            SetOperationElement::Values(values) => SetExpr::Values {
297                span: transform_span(input.span.tokens),
298                values,
299            },
300            _ => unreachable!(),
301        };
302        Ok(set_expr)
303    }
304
305    fn infix(
306        &mut self,
307        lhs: Self::Output,
308        input: Self::Input,
309        rhs: Self::Output,
310    ) -> Result<Self::Output, &'static str> {
311        let set_expr = match input.elem {
312            SetOperationElement::SetOperation { op, all, .. } => {
313                SetExpr::SetOperation(Box::new(SetOperation {
314                    span: transform_span(input.span.tokens),
315                    op,
316                    all,
317                    left: Box::new(lhs),
318                    right: Box::new(rhs),
319                }))
320            }
321            _ => unreachable!(),
322        };
323        Ok(set_expr)
324    }
325
326    fn prefix(&mut self, op: Self::Input, rhs: Self::Output) -> Result<Self::Output, Self::Error> {
327        let mut query = rhs.into_query();
328        match op.elem {
329            SetOperationElement::With(with) => {
330                if query.with.is_some() {
331                    return Err("duplicated WITH clause");
332                }
333                query.with = Some(with);
334            }
335            _ => unreachable!(),
336        }
337        Ok(SetExpr::Query(Box::new(query)))
338    }
339
340    fn postfix(&mut self, lhs: Self::Output, op: Self::Input) -> Result<Self::Output, Self::Error> {
341        let mut query = lhs.into_query();
342        match op.elem {
343            SetOperationElement::OrderBy { order_by } => {
344                if !query.order_by.is_empty() {
345                    return Err("duplicated ORDER BY clause");
346                }
347                if !query.limit.is_empty() {
348                    return Err("ORDER BY must appear before LIMIT");
349                }
350                if query.offset.is_some() {
351                    return Err("ORDER BY must appear before OFFSET");
352                }
353                query.order_by = order_by;
354            }
355            SetOperationElement::Limit { limit } => {
356                if query.limit.is_empty() && limit.len() > 2 {
357                    return Err("[LIMIT n OFFSET m] or [LIMIT n,m]");
358                }
359                if !query.limit.is_empty() {
360                    return Err("duplicated LIMIT clause");
361                }
362                if query.offset.is_some() {
363                    return Err("LIMIT must appear before OFFSET");
364                }
365                query.limit = limit;
366            }
367            SetOperationElement::Offset { offset } => {
368                if query.limit.len() == 2 {
369                    return Err("LIMIT n,m should not appear OFFSET");
370                }
371                if query.offset.is_some() {
372                    return Err("duplicated OFFSET clause");
373                }
374                query.offset = Some(offset);
375            }
376            SetOperationElement::IgnoreResult => {
377                query.ignore_result = true;
378            }
379            _ => unreachable!(),
380        }
381        Ok(SetExpr::Query(Box::new(query)))
382    }
383}
384
385pub fn row_values(i: Input) -> IResult<Vec<Expr>> {
386    map(
387        rule! {"(" ~ #comma_separated_list1(expr) ~ ")"},
388        |(_, row_values, _)| row_values,
389    )
390    .parse(i)
391}
392
393pub fn with(i: Input) -> IResult<With> {
394    let cte = map(
395        consumed(rule! {
396            #table_alias_without_as ~ AS ~ MATERIALIZED? ~ "(" ~ #query ~ ")"
397        }),
398        |(span, (table_alias, _, materialized, _, query, _))| CTE {
399            span: transform_span(span.tokens),
400            alias: table_alias,
401            user_specified_materialized: materialized.is_some(),
402            materialized: false,
403            query: Box::new(query),
404        },
405    );
406
407    map(
408        consumed(rule! {
409            WITH ~ RECURSIVE? ~ ^#comma_separated_list1(cte)
410        }),
411        |(span, (_, recursive, ctes))| With {
412            span: transform_span(span.tokens),
413            recursive: recursive.is_some(),
414            ctes,
415        },
416    )
417    .parse(i)
418}
419
420pub fn exclude_col(i: Input) -> IResult<Vec<Identifier>> {
421    let var = map(
422        rule! {
423            #ident
424        },
425        |col| vec![col],
426    );
427    let vars = map(
428        rule! {
429             "(" ~ ^#comma_separated_list1(ident) ~ ^")"
430        },
431        |(_, cols, _)| cols,
432    );
433
434    rule!(
435        #var
436        | #vars
437    )
438    .parse(i)
439}
440
441#[allow(clippy::type_complexity)]
442pub fn select_target(i: Input) -> IResult<SelectTarget> {
443    fn qualified_wildcard_transform(
444        res: Option<(Identifier, &Token<'_>, Option<(Identifier, &Token<'_>)>)>,
445        star: &Token<'_>,
446        opt_exclude: Option<(&Token<'_>, Vec<Identifier>)>,
447    ) -> SelectTarget {
448        let column_filter = opt_exclude.map(|(_, exclude)| ColumnFilter::Excludes(exclude));
449        match res {
450            Some((fst, _, Some((snd, _)))) => SelectTarget::StarColumns {
451                qualified: vec![
452                    Indirection::Identifier(fst),
453                    Indirection::Identifier(snd),
454                    Indirection::Star(Some(star.span)),
455                ],
456                column_filter,
457            },
458            Some((fst, _, None)) => SelectTarget::StarColumns {
459                qualified: vec![
460                    Indirection::Identifier(fst),
461                    Indirection::Star(Some(star.span)),
462                ],
463                column_filter,
464            },
465            None => SelectTarget::StarColumns {
466                qualified: vec![Indirection::Star(Some(star.span))],
467                column_filter,
468            },
469        }
470    }
471
472    let qualified_wildcard = alt((
473        // select * exclude ...
474        map(
475            rule! {
476               ( #ident ~ "." ~ ( #ident ~ "." )? )? ~ "*" ~ ( EXCLUDE ~ #exclude_col )?
477            },
478            |(res, star, opt_exclude)| qualified_wildcard_transform(res, star, opt_exclude),
479        ),
480        // select columns(* exclude ...)
481        map(
482            rule! {
483              COLUMNS ~ "(" ~  ( #ident ~ "." ~ ( #ident ~ "." )? )? ~ "*" ~ ( EXCLUDE ~ #exclude_col )? ~ ")"
484            },
485            |(_, _, res, star, opt_exclude, _)| {
486                qualified_wildcard_transform(res, star, opt_exclude)
487            },
488        ),
489    ));
490
491    // columns('.*abc.*')
492    let columns_regexp = map(
493        rule! {
494            COLUMNS ~ "(" ~ #literal_string ~ ")"
495        },
496        |(t, _, s, _)| SelectTarget::StarColumns {
497            qualified: vec![Indirection::Star(Some(t.span))],
498            column_filter: Some(ColumnFilter::Lambda(Lambda {
499                params: vec![Identifier::from_name(Some(t.span), "_t")],
500                expr: Box::new(Expr::BinaryOp {
501                    span: Some(t.span),
502                    op: BinaryOperator::Regexp,
503                    left: Box::new(Expr::ColumnRef {
504                        span: None,
505                        column: ColumnRef {
506                            database: None,
507                            table: None,
508                            column: ColumnID::Name(Identifier::from_name(Some(t.span), "_t")),
509                        },
510                    }),
511                    right: Box::new(Expr::Literal {
512                        span: Some(t.span),
513                        value: Literal::String(s),
514                    }),
515                }),
516            })),
517        },
518    );
519
520    // columns(a -> filter)
521    let columns_lambda = map(
522        rule! {
523            COLUMNS ~ "(" ~ #ident ~ "->" ~ #subexpr(0) ~ ")"
524        },
525        |(t, _, ident, _, expr, _)| SelectTarget::StarColumns {
526            qualified: vec![Indirection::Star(Some(t.span))],
527            column_filter: Some(ColumnFilter::Lambda(Lambda {
528                params: vec![ident],
529                expr: Box::new(expr),
530            })),
531        },
532    );
533
534    let projection = map(
535        rule! {
536            #expr ~ #alias_name?
537        },
538        |(expr, alias)| SelectTarget::AliasedExpr {
539            expr: Box::new(expr),
540            alias,
541        },
542    );
543
544    rule!(
545        #qualified_wildcard
546        | #columns_regexp
547        | #columns_lambda
548        | #projection
549    )
550    .parse(i)
551}
552
553pub fn travel_point(i: Input) -> IResult<TimeTravelPoint> {
554    let at_stream = map(
555        rule! { "(" ~ STREAM ~ "=>" ~  #dot_separated_idents_1_to_3 ~ ")" },
556        |(_, _, _, (catalog, database, name), _)| TimeTravelPoint::Stream {
557            catalog,
558            database,
559            name,
560        },
561    );
562
563    rule!(
564        #at_stream | #at_snapshot_or_ts
565    )
566    .parse(i)
567}
568
569pub fn at_table_ref(i: Input) -> IResult<TimeTravelPoint> {
570    map(
571        rule! { "(" ~ ( BRANCH | TAG ) ~ "=>" ~  #ident ~ ")" },
572        |(_, token, _, name, _)| {
573            let typ = match token.kind {
574                TokenKind::BRANCH => SnapshotRefType::Branch,
575                TokenKind::TAG => SnapshotRefType::Tag,
576                _ => unreachable!(),
577            };
578            TimeTravelPoint::TableRef { typ, name }
579        },
580    )
581    .parse(i)
582}
583
584pub fn at_snapshot_or_ts(i: Input) -> IResult<TimeTravelPoint> {
585    let at_snapshot = map(
586        rule! { "(" ~ SNAPSHOT ~ "=>" ~ #literal_string ~ ")" },
587        |(_, _, _, s, _)| TimeTravelPoint::Snapshot(s),
588    );
589    let at_timestamp = map(
590        rule! { "(" ~ TIMESTAMP ~ "=>" ~ #expr ~ ")" },
591        |(_, _, _, e, _)| TimeTravelPoint::Timestamp(Box::new(e)),
592    );
593    let at_offset = map(
594        rule! { "(" ~ OFFSET ~ "=>" ~ #expr ~ ")" },
595        |(_, _, _, e, _)| TimeTravelPoint::Offset(Box::new(e)),
596    );
597
598    rule!(
599        #at_snapshot | #at_timestamp | #at_offset
600    )
601    .parse(i)
602}
603
604pub fn temporal_clause(i: Input) -> IResult<TemporalClause> {
605    let time_travel = map(
606        rule! {
607            AT ~ ^#travel_point
608        },
609        |(_, travel_point)| TemporalClause::TimeTravel(travel_point),
610    );
611
612    let changes = map(
613        rule! {
614            CHANGES ~ "(" ~ INFORMATION ~ "=>" ~ ( DEFAULT | APPEND_ONLY ) ~ ")" ~ AT ~ ^#travel_point ~ (END ~ ^#at_snapshot_or_ts)?
615        },
616        |(_, _, _, _, changes_type, _, _, at_point, opt_end_point)| {
617            let append_only = matches!(changes_type.kind, APPEND_ONLY);
618            TemporalClause::Changes(ChangesInterval {
619                append_only,
620                at_point,
621                end_point: opt_end_point.map(|p| p.1),
622            })
623        },
624    );
625
626    rule!(
627        #time_travel
628        | #changes
629    )
630    .parse(i)
631}
632
633pub fn alias_name(i: Input) -> IResult<Identifier> {
634    let short_alias = map(
635        rule! {
636            #ident
637            ~ #error_hint(
638                rule! { AS },
639                "an alias without `AS` keyword has already been defined before this one, \
640                    please remove one of them"
641            )
642        },
643        |(ident, _)| ident,
644    );
645    let as_alias = map(
646        rule! {
647            AS ~ #ident_after_as
648        },
649        |(_, name)| name,
650    );
651
652    rule!(
653        #short_alias
654        | #as_alias
655    )
656    .parse(i)
657}
658
659pub fn with_options(i: Input) -> IResult<WithOptions> {
660    alt((
661        map(rule! { WITH ~ CONSUME }, |_| WithOptions {
662            options: BTreeMap::from([("consume".to_string(), "true".to_string())]),
663        }),
664        map(
665            rule! {
666                WITH ~ "(" ~ #set_table_option ~ ")"
667            },
668            |(_, _, options, _)| WithOptions { options },
669        ),
670    ))
671    .parse(i)
672}
673
674pub fn table_alias(i: Input) -> IResult<TableAlias> {
675    map(
676        rule! { #alias_name ~ ( "(" ~ ^#comma_separated_list1(ident) ~ ^")" )? },
677        |(name, opt_columns)| TableAlias {
678            name,
679            columns: opt_columns.map(|(_, cols, _)| cols).unwrap_or_default(),
680            keep_database_name: false,
681        },
682    )
683    .parse(i)
684}
685
686pub fn table_alias_without_as(i: Input) -> IResult<TableAlias> {
687    map(
688        rule! { #ident ~ ( "(" ~ ^#comma_separated_list1(ident) ~ ^")" )? },
689        |(name, opt_columns)| TableAlias {
690            name,
691            columns: opt_columns.map(|(_, cols, _)| cols).unwrap_or_default(),
692            keep_database_name: false,
693        },
694    )
695    .parse(i)
696}
697
698pub fn join_operator(i: Input) -> IResult<JoinOperator> {
699    alt((
700        value(JoinOperator::InnerAny, rule! { INNER ~ ANY }),
701        value(JoinOperator::Inner, rule! { INNER }),
702        value(JoinOperator::LeftSemi, rule! { LEFT? ~ SEMI }),
703        value(JoinOperator::RightSemi, rule! { RIGHT ~ SEMI }),
704        value(JoinOperator::LeftAnti, rule! { LEFT? ~ ANTI }),
705        value(JoinOperator::RightAnti, rule! { RIGHT ~ ANTI }),
706        value(JoinOperator::LeftAny, rule! { LEFT ~ ANY }),
707        value(JoinOperator::RightAny, rule! { RIGHT ~ ANY }),
708        value(JoinOperator::LeftOuter, rule! { LEFT ~ OUTER? }),
709        value(JoinOperator::RightOuter, rule! { RIGHT ~ OUTER? }),
710        value(JoinOperator::FullOuter, rule! { FULL ~ OUTER? }),
711        value(JoinOperator::CrossJoin, rule! { CROSS }),
712        value(JoinOperator::LeftAsof, rule! { ASOF ~ LEFT }),
713        value(JoinOperator::RightAsof, rule! { ASOF ~ RIGHT }),
714        value(JoinOperator::Asof, rule! { ASOF }),
715    ))
716    .parse(i)
717}
718
719pub fn order_by_expr(i: Input) -> IResult<OrderByExpr> {
720    let nulls_first = map(
721        rule! {
722            NULLS ~ ( FIRST | LAST )
723        },
724        |(_, first_last)| first_last.kind == FIRST,
725    );
726
727    map(
728        rule! {
729            #expr ~ ( ASC | DESC )? ~ #nulls_first?
730        },
731        |(expr, opt_asc, opt_nulls_first)| OrderByExpr {
732            expr,
733            asc: opt_asc.map(|asc| asc.kind == ASC),
734            nulls_first: opt_nulls_first,
735        },
736    )
737    .parse(i)
738}
739
740pub fn table_reference(i: Input) -> IResult<TableReference> {
741    let (rest, table_reference_elements) = rule! { #table_reference_element+ }.parse(i)?;
742    run_pratt_parser(TableReferenceParser, table_reference_elements, rest, i)
743}
744
745#[derive(Debug, Clone, PartialEq)]
746pub enum TableFunctionParam {
747    // func(name => arg)
748    Named { name: Identifier, value: Expr },
749    // func(arg)
750    Normal(Expr),
751}
752
753pub fn table_function_param(i: Input) -> IResult<TableFunctionParam> {
754    let named = map(rule! { #ident ~ "=>" ~ #expr  }, |(name, _, value)| {
755        TableFunctionParam::Named { name, value }
756    });
757    let normal = map(rule! { #expr }, TableFunctionParam::Normal);
758
759    rule!(
760        #named | #normal
761    )
762    .parse(i)
763}
764
765#[derive(Debug, Clone, PartialEq)]
766pub enum TableReferenceElement {
767    Table {
768        table: TableRef,
769        alias: Option<TableAlias>,
770        temporal: Option<TemporalClause>,
771        with_options: Option<WithOptions>,
772        pivot: Option<Box<Pivot>>,
773        unpivot: Option<Box<Unpivot>>,
774        sample: Option<SampleConfig>,
775    },
776    // `TABLE(expr)[ AS alias ]`
777    TableFunction {
778        /// If the table function is a lateral table function
779        lateral: bool,
780        name: Identifier,
781        params: Vec<TableFunctionParam>,
782        alias: Option<TableAlias>,
783        sample: Option<SampleConfig>,
784    },
785    // Derived table, which can be a subquery or joined tables or combination of them
786    Subquery {
787        /// If the subquery is a lateral subquery
788        lateral: bool,
789        subquery: Box<Query>,
790        alias: Option<TableAlias>,
791        pivot: Option<Box<Pivot>>,
792        unpivot: Option<Box<Unpivot>>,
793    },
794    // [NATURAL] [INNER|OUTER|CROSS|...] JOIN
795    Join {
796        op: JoinOperator,
797        natural: bool,
798    },
799    // ON expr | USING (ident, ...)
800    JoinCondition(JoinCondition),
801    Group(TableReference),
802    Stage {
803        location: FileLocation,
804        options: Vec<SelectStageOption>,
805        alias: Option<TableAlias>,
806    },
807}
808
809pub fn table_reference_element(i: Input) -> IResult<WithSpan<TableReferenceElement>> {
810    let aliased_table = map(
811        rule! {
812            #table_ref ~ #temporal_clause? ~ #with_options? ~ #table_alias? ~ #pivot? ~ #unpivot? ~ SAMPLE? ~ (BLOCK ~ "(" ~ #expr ~ ")")? ~ (ROW ~ "(" ~ #expr ~ ROWS? ~ ")")?
813        },
814        |(
815            table,
816            temporal,
817            with_options,
818            alias,
819            pivot,
820            unpivot,
821            sample,
822            sample_block_level,
823            sample_row_level,
824        )| {
825            let table_sample = get_table_sample(sample, sample_block_level, sample_row_level);
826            TableReferenceElement::Table {
827                table,
828                alias,
829                temporal,
830                with_options,
831                pivot: pivot.map(Box::new),
832                unpivot: unpivot.map(Box::new),
833                sample: table_sample,
834            }
835        },
836    );
837    let join = map(
838        rule! {
839            NATURAL? ~ #join_operator? ~ JOIN
840        },
841        |(opt_natural, opt_op, _)| TableReferenceElement::Join {
842            op: opt_op.unwrap_or(JoinOperator::Inner),
843            natural: opt_natural.is_some(),
844        },
845    );
846    let join_condition_on = map(
847        rule! {
848            ON ~ #expr
849        },
850        |(_, expr)| TableReferenceElement::JoinCondition(JoinCondition::On(Box::new(expr))),
851    );
852    let join_condition_using = map(
853        rule! {
854            USING ~ "(" ~ #comma_separated_list1(ident) ~ ")"
855        },
856        |(_, _, idents, _)| TableReferenceElement::JoinCondition(JoinCondition::Using(idents)),
857    );
858    let table_function = map(
859        rule! {
860            LATERAL? ~ #function_name ~ "(" ~ #comma_separated_list0(table_function_param) ~ ")" ~ #table_alias? ~ SAMPLE? ~ (BLOCK ~ "(" ~ #expr ~ ")")? ~ (ROW ~ "(" ~ #expr ~ ROWS? ~ ")")?
861        },
862        |(lateral, name, _, params, _, alias, sample, level, sample_conf)| {
863            let table_sample = get_table_sample(sample, level, sample_conf);
864            TableReferenceElement::TableFunction {
865                lateral: lateral.is_some(),
866                name,
867                params,
868                alias,
869                sample: table_sample,
870            }
871        },
872    );
873    let subquery = map(
874        rule! {
875            LATERAL? ~ "(" ~ #query ~ ")" ~ #table_alias? ~ #pivot? ~ #unpivot?
876        },
877        |(lateral, _, subquery, _, alias, pivot, unpivot)| TableReferenceElement::Subquery {
878            lateral: lateral.is_some(),
879            subquery: Box::new(subquery),
880            alias,
881            pivot: pivot.map(Box::new),
882            unpivot: unpivot.map(Box::new),
883        },
884    );
885
886    let group = map(
887        rule! {
888           "(" ~ #table_reference ~ ^")"
889        },
890        |(_, table_ref, _)| TableReferenceElement::Group(table_ref),
891    );
892    let aliased_stage = map(
893        rule! {
894            #file_location ~  ( "(" ~ (#select_stage_option ~ ","?)* ~ ^")" )? ~ #table_alias?
895        },
896        |(location, options, alias)| {
897            let options = options
898                .map(|(_, options, _)| options.into_iter().map(|(option, _)| option).collect())
899                .unwrap_or_default();
900            TableReferenceElement::Stage {
901                location,
902                alias,
903                options,
904            }
905        },
906    );
907
908    let (rest, (span, elem)) = consumed(rule! {
909        #aliased_stage
910        | #table_function
911        | #aliased_table
912        | #subquery
913        | #group
914        | #join
915        | #join_condition_on
916        | #join_condition_using
917    })
918    .parse(i)?;
919    Ok((rest, WithSpan { span, elem }))
920}
921
922// PIVOT(expr FOR col IN (ident, ... | subquery))
923fn pivot(i: Input) -> IResult<Pivot> {
924    map(
925        rule! {
926            PIVOT ~ "(" ~ #expr ~ FOR ~ #ident ~ IN ~ "(" ~ #pivot_values ~ ")" ~ ")"
927        },
928        |(_pivot, _, aggregate, _for, value_column, _in, _, values, _, _)| Pivot {
929            aggregate,
930            value_column,
931            values,
932        },
933    )
934    .parse(i)
935}
936
937fn unpivot_name(i: Input) -> IResult<UnpivotName> {
938    let short_alias = map(
939        rule! {
940            #literal_string
941            ~ #error_hint(
942                rule! { AS },
943                "an alias without `AS` keyword has already been defined before this one, \
944                    please remove one of them"
945            )
946        },
947        |(string, _)| string,
948    );
949    let as_alias = map(
950        rule! {
951            AS ~ #literal_string
952        },
953        |(_, string)| string,
954    );
955    map(
956        rule! {#ident ~ (#short_alias | #as_alias)?},
957        |(ident, alias)| UnpivotName { ident, alias },
958    )
959    .parse(i)
960}
961
962// UNPIVOT(ident for ident IN (ident, ...))
963fn unpivot(i: Input) -> IResult<Unpivot> {
964    map(
965        rule! {
966            UNPIVOT ~ "(" ~ #ident ~ FOR ~ #ident ~ IN ~ "(" ~ #comma_separated_list1(unpivot_name) ~ ")" ~ ")"
967        },
968        |(_unpivot, _, value_column, _for, unpivot_column, _in, _, column_names, _, _)| Unpivot {
969            value_column,
970            unpivot_column,
971            column_names,
972        },
973    ).parse(i)
974}
975
976fn pivot_values(i: Input) -> IResult<PivotValues> {
977    alt((
978        // Parse ANY [ORDER BY ...] - must be first to avoid ANY being parsed as expression
979        map(
980            rule! {
981                ANY ~
982                (ORDER ~ BY ~ #comma_separated_list1(order_by_expr))?
983            },
984            |(_, order_by_opt)| PivotValues::Any {
985                order_by: order_by_opt.map(|(_, _, order_by_list)| order_by_list),
986            },
987        ),
988        // Parse subquery - must be before expr list to avoid parsing subquery as expression
989        map(query, |q| PivotValues::Subquery(Box::new(q))),
990        // Parse expression list - must be last
991        map(comma_separated_list1(expr), PivotValues::ColumnValues),
992    ))
993    .parse(i)
994}
995
996fn get_table_sample(
997    sample: Option<&Token>,
998    block_level_sample: Option<(&Token, &Token, Expr, &Token)>,
999    row_level_sample: Option<(&Token, &Token, Expr, Option<&Token>, &Token)>,
1000) -> Option<SampleConfig> {
1001    let mut default_sample_conf = SampleConfig::default();
1002    if sample.is_some() {
1003        if let Some((_, _, Expr::Literal { value, .. }, _)) = block_level_sample {
1004            default_sample_conf.set_block_level_sample(value.as_double().unwrap_or_default());
1005        }
1006        if let Some((_, _, Expr::Literal { value, .. }, rows, _)) = row_level_sample {
1007            default_sample_conf
1008                .set_row_level_sample(value.as_double().unwrap_or_default(), rows.is_some());
1009        }
1010        return Some(default_sample_conf);
1011    }
1012    None
1013}
1014
1015struct TableReferenceParser;
1016
1017impl<'a, I: Iterator<Item = WithSpan<'a, TableReferenceElement>>> PrattParser<I>
1018    for TableReferenceParser
1019{
1020    type Error = &'static str;
1021    type Input = WithSpan<'a, TableReferenceElement>;
1022    type Output = TableReference;
1023
1024    fn query(&mut self, input: &Self::Input) -> Result<Affix, &'static str> {
1025        let affix = match &input.elem {
1026            TableReferenceElement::Join { .. } => Affix::Infix(Precedence(10), Associativity::Left),
1027            TableReferenceElement::JoinCondition(..) => Affix::Postfix(Precedence(5)),
1028            _ => Affix::Nilfix,
1029        };
1030        Ok(affix)
1031    }
1032
1033    fn primary(&mut self, input: Self::Input) -> Result<Self::Output, &'static str> {
1034        let table_ref = match input.elem {
1035            TableReferenceElement::Group(table_ref) => table_ref,
1036            TableReferenceElement::Table {
1037                table,
1038                alias,
1039                temporal,
1040                with_options,
1041                pivot,
1042                unpivot,
1043                sample,
1044            } => TableReference::Table {
1045                span: transform_span(input.span.tokens),
1046                table,
1047                alias,
1048                temporal,
1049                with_options,
1050                pivot,
1051                unpivot,
1052                sample,
1053            },
1054            TableReferenceElement::TableFunction {
1055                lateral,
1056                name,
1057                params,
1058                alias,
1059                sample,
1060            } => {
1061                let normal_params = params
1062                    .iter()
1063                    .filter_map(|p| match p {
1064                        TableFunctionParam::Normal(p) => Some(p.clone()),
1065                        _ => None,
1066                    })
1067                    .collect();
1068                let named_params = params
1069                    .into_iter()
1070                    .filter_map(|p| match p {
1071                        TableFunctionParam::Named { name, value } => Some((name, value)),
1072                        _ => None,
1073                    })
1074                    .collect();
1075                TableReference::TableFunction {
1076                    span: transform_span(input.span.tokens),
1077                    lateral,
1078                    name,
1079                    params: normal_params,
1080                    named_params,
1081                    alias,
1082                    sample,
1083                }
1084            }
1085            TableReferenceElement::Subquery {
1086                lateral,
1087                subquery,
1088                alias,
1089                pivot,
1090                unpivot,
1091            } => TableReference::Subquery {
1092                span: transform_span(input.span.tokens),
1093                lateral,
1094                subquery,
1095                alias,
1096                pivot,
1097                unpivot,
1098            },
1099            TableReferenceElement::Stage {
1100                location,
1101                options,
1102                alias,
1103            } => {
1104                let options = SelectStageOptions::from(options);
1105                TableReference::Location {
1106                    span: transform_span(input.span.tokens),
1107                    location,
1108                    options,
1109                    alias,
1110                }
1111            }
1112            _ => unreachable!(),
1113        };
1114        Ok(table_ref)
1115    }
1116
1117    fn infix(
1118        &mut self,
1119        lhs: Self::Output,
1120        input: Self::Input,
1121        rhs: Self::Output,
1122    ) -> Result<Self::Output, &'static str> {
1123        let table_ref = match input.elem {
1124            TableReferenceElement::Join { op, natural } => {
1125                let condition = if natural {
1126                    JoinCondition::Natural
1127                } else {
1128                    JoinCondition::None
1129                };
1130                TableReference::Join {
1131                    span: transform_span(input.span.tokens),
1132                    join: Join {
1133                        op,
1134                        condition,
1135                        left: Box::new(lhs),
1136                        right: Box::new(rhs),
1137                    },
1138                }
1139            }
1140            _ => unreachable!(),
1141        };
1142        Ok(table_ref)
1143    }
1144
1145    fn prefix(
1146        &mut self,
1147        _op: Self::Input,
1148        _rhs: Self::Output,
1149    ) -> Result<Self::Output, Self::Error> {
1150        unreachable!()
1151    }
1152
1153    fn postfix(
1154        &mut self,
1155        mut lhs: Self::Output,
1156        op: Self::Input,
1157    ) -> Result<Self::Output, Self::Error> {
1158        match op.elem {
1159            TableReferenceElement::JoinCondition(new_condition) => match &mut lhs {
1160                TableReference::Join {
1161                    join: Join { condition, .. },
1162                    ..
1163                } => match *condition {
1164                    JoinCondition::None => {
1165                        *condition = new_condition;
1166                        Ok(lhs)
1167                    }
1168                    JoinCondition::Natural => Err("join condition conflicting with NATURAL"),
1169                    _ => Err("join condition already set"),
1170                },
1171                _ => Err("join condition must apply to a join"),
1172            },
1173            _ => unreachable!(),
1174        }
1175    }
1176}
1177
1178pub fn group_by_items(i: Input) -> IResult<GroupBy> {
1179    let all = map(rule! { ALL }, |_| GroupBy::All);
1180
1181    let cube = map(
1182        rule! { CUBE ~ "(" ~ ^#comma_separated_list1(expr) ~ ")" },
1183        |(_, _, groups, _)| GroupBy::Cube(groups),
1184    );
1185    let rollup = map(
1186        rule! { ROLLUP ~ "(" ~ ^#comma_separated_list1(expr) ~ ")" },
1187        |(_, _, groups, _)| GroupBy::Rollup(groups),
1188    );
1189    let group_set = alt((
1190        map(rule! {"(" ~ ")"}, |(_, _)| vec![]), // empty grouping set
1191        map(
1192            rule! {"(" ~ #comma_separated_list1(expr) ~ ")"},
1193            |(_, sets, _)| sets,
1194        ),
1195        map(rule! { #expr }, |e| vec![e]),
1196    ));
1197    let group_sets = map(
1198        rule! { GROUPING ~ ^SETS ~ "(" ~ ^#comma_separated_list1(group_set) ~ ")"  },
1199        |(_, _, _, sets, _)| GroupBy::GroupingSets(sets),
1200    );
1201
1202    // New rule to handle multiple GroupBy items
1203    let single_normal = map(rule! { #expr }, |group| GroupBy::Normal(vec![group]));
1204    let group_by_item = alt((all, group_sets, cube, rollup, single_normal));
1205    map(rule! { ^#comma_separated_list1(group_by_item) }, |items| {
1206        if items.len() > 1 {
1207            if items.iter().all(|item| matches!(item, GroupBy::Normal(_))) {
1208                let items = items
1209                    .into_iter()
1210                    .flat_map(|item| match item {
1211                        GroupBy::Normal(exprs) => exprs,
1212                        _ => unreachable!(),
1213                    })
1214                    .collect();
1215                GroupBy::Normal(items)
1216            } else {
1217                GroupBy::Combined(items)
1218            }
1219        } else {
1220            items.into_iter().next().unwrap()
1221        }
1222    })
1223    .parse(i)
1224}
1225
1226pub fn window_frame_bound(i: Input) -> IResult<WindowFrameBound> {
1227    alt((
1228        value(WindowFrameBound::CurrentRow, rule! { CURRENT ~ ROW }),
1229        value(
1230            WindowFrameBound::Preceding(None),
1231            rule! { UNBOUNDED ~ PRECEDING },
1232        ),
1233        map(rule! { #subexpr(0) ~ PRECEDING }, |(expr, _)| {
1234            WindowFrameBound::Preceding(Some(Box::new(expr)))
1235        }),
1236        value(
1237            WindowFrameBound::Following(None),
1238            rule! { UNBOUNDED ~ FOLLOWING },
1239        ),
1240        map(rule! { #subexpr(0) ~ FOLLOWING }, |(expr, _)| {
1241            WindowFrameBound::Following(Some(Box::new(expr)))
1242        }),
1243    ))
1244    .parse(i)
1245}
1246
1247pub fn window_frame_between(i: Input) -> IResult<(WindowFrameBound, WindowFrameBound)> {
1248    alt((
1249        map(
1250            rule! { BETWEEN ~ #window_frame_bound ~ AND ~ #window_frame_bound },
1251            |(_, s, _, e)| (s, e),
1252        ),
1253        map(rule! { #window_frame_bound }, |s| {
1254            (s, WindowFrameBound::CurrentRow)
1255        }),
1256    ))
1257    .parse(i)
1258}
1259
1260pub fn window_spec(i: Input) -> IResult<WindowSpec> {
1261    map(
1262        rule! {
1263            #ident?
1264            ~ ( PARTITION ~ ^BY ~ ^#comma_separated_list1(subexpr(0)) )?
1265            ~ ( ORDER ~ ^BY ~ ^#comma_separated_list1(order_by_expr) )?
1266            ~ ( (ROWS | RANGE) ~ ^#window_frame_between )?
1267        },
1268        |(existing_window_name, opt_partition, opt_order, between)| WindowSpec {
1269            existing_window_name,
1270            partition_by: opt_partition.map(|x| x.2).unwrap_or_default(),
1271            order_by: opt_order.map(|x| x.2).unwrap_or_default(),
1272            window_frame: between.map(|x| {
1273                let unit = match x.0.kind {
1274                    ROWS => WindowFrameUnits::Rows,
1275                    RANGE => WindowFrameUnits::Range,
1276                    _ => unreachable!(),
1277                };
1278                let bw = x.1;
1279                WindowFrame {
1280                    units: unit,
1281                    start_bound: bw.0,
1282                    end_bound: bw.1,
1283                }
1284            }),
1285        },
1286    )
1287    .parse(i)
1288}
1289
1290pub fn window_spec_ident(i: Input) -> IResult<Window> {
1291    alt((
1292        map(
1293            rule! {
1294               "(" ~ #window_spec ~ ")"
1295            },
1296            |(_, spec, _)| Window::WindowSpec(spec),
1297        ),
1298        map(
1299            rule! {
1300                #ident
1301            },
1302            |window_name| Window::WindowReference(WindowRef { window_name }),
1303        ),
1304    ))
1305    .parse(i)
1306}
1307
1308pub fn within_group(i: Input) -> IResult<Vec<OrderByExpr>> {
1309    map(
1310        rule! {
1311        WITHIN ~ GROUP ~ "(" ~ ORDER ~ ^BY ~ ^#comma_separated_list1(order_by_expr) ~ ")"
1312        },
1313        |(_, _, _, _, _, order_by, _)| order_by,
1314    )
1315    .parse(i)
1316}
1317
1318pub fn window_function(i: Input) -> IResult<WindowDesc> {
1319    map(
1320        rule! {
1321        (( IGNORE | RESPECT ) ~ NULLS)? ~ (OVER ~ #window_spec_ident)
1322        },
1323        |(opt_ignore_nulls, window)| WindowDesc {
1324            ignore_nulls: opt_ignore_nulls.map(|key| key.0.kind == IGNORE),
1325            window: window.1,
1326        },
1327    )
1328    .parse(i)
1329}
1330
1331pub fn window_clause(i: Input) -> IResult<WindowDefinition> {
1332    map(
1333        rule! {
1334            #ident ~ AS ~ "(" ~ #window_spec ~ ")"
1335        },
1336        |(ident, _, _, window, _)| WindowDefinition {
1337            name: ident,
1338            spec: window,
1339        },
1340    )
1341    .parse(i)
1342}