databend_common_ast/ast/
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;
16use std::fmt::Display;
17use std::fmt::Formatter;
18
19use derive_visitor::Drive;
20use derive_visitor::DriveMut;
21use educe::Educe;
22
23use crate::ast::quote::QuotedString;
24use crate::ast::write_comma_separated_list;
25use crate::ast::write_comma_separated_string_map;
26use crate::ast::write_dot_separated_list;
27use crate::ast::Expr;
28use crate::ast::FileLocation;
29use crate::ast::Hint;
30use crate::ast::Identifier;
31use crate::ast::Lambda;
32use crate::ast::SelectStageOptions;
33use crate::ast::WindowDefinition;
34use crate::ParseError;
35use crate::Result;
36use crate::Span;
37
38/// Root node of a query tree
39#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
40pub struct Query {
41    pub span: Span,
42    // With clause, common table expression
43    pub with: Option<With>,
44    // Set operator: SELECT or UNION / EXCEPT / INTERSECT
45    pub body: SetExpr,
46
47    // The following clauses can only appear in top level of a subquery/query
48    // `ORDER BY` clause
49    pub order_by: Vec<OrderByExpr>,
50    // `LIMIT` clause
51    pub limit: Vec<Expr>,
52    // `OFFSET` expr
53    pub offset: Option<Expr>,
54
55    // If ignore the result (not output).
56    pub ignore_result: bool,
57}
58
59impl Display for Query {
60    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
61        // CTE, with clause
62        if let Some(with) = &self.with {
63            write!(f, "WITH {with} ")?;
64        }
65
66        // Query body
67        write!(f, "{}", self.body)?;
68
69        // ORDER BY clause
70        if !self.order_by.is_empty() {
71            write!(f, " ORDER BY ")?;
72            write_comma_separated_list(f, &self.order_by)?;
73        }
74
75        // LIMIT clause
76        if !self.limit.is_empty() {
77            write!(f, " LIMIT ")?;
78            write_comma_separated_list(f, &self.limit)?;
79        }
80
81        // TODO: We should validate if offset exists, limit should be empty or just one element
82        if let Some(offset) = &self.offset {
83            write!(f, " OFFSET {offset}")?;
84        }
85
86        if self.ignore_result {
87            write!(f, " IGNORE_RESULT")?;
88        }
89
90        Ok(())
91    }
92}
93
94#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
95pub struct With {
96    pub span: Span,
97    pub recursive: bool,
98    pub ctes: Vec<CTE>,
99}
100
101impl Display for With {
102    #[recursive::recursive]
103    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
104        if self.recursive {
105            write!(f, "RECURSIVE ")?;
106        }
107
108        write_comma_separated_list(f, &self.ctes)?;
109        Ok(())
110    }
111}
112
113#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
114pub struct CTE {
115    pub span: Span,
116    pub alias: TableAlias,
117    pub materialized: bool,
118    pub query: Box<Query>,
119}
120
121impl Display for CTE {
122    #[recursive::recursive]
123    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
124        write!(f, "{} AS ", self.alias)?;
125        if self.materialized {
126            write!(f, "MATERIALIZED ")?;
127        }
128        write!(f, "({})", self.query)?;
129        Ok(())
130    }
131}
132
133#[derive(Educe, Drive, DriveMut)]
134#[educe(
135    PartialEq(bound = false, attrs = "#[recursive::recursive]"),
136    Clone(bound = false, attrs = "#[recursive::recursive]"),
137    Debug(bound = false, attrs = "#[recursive::recursive]")
138)]
139pub struct SetOperation {
140    pub span: Span,
141    pub op: SetOperator,
142    pub all: bool,
143    pub left: Box<SetExpr>,
144    pub right: Box<SetExpr>,
145}
146
147/// A subquery represented with `SELECT` statement
148#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
149pub struct SelectStmt {
150    pub span: Span,
151    pub hints: Option<Hint>,
152    pub distinct: bool,
153    pub top_n: Option<u64>,
154    // Result set of current subquery
155    pub select_list: Vec<SelectTarget>,
156    // `FROM` clause, a list of table references.
157    // The table references split by `,` will be joined with cross join,
158    // and the result set is union of the joined tables by default.
159    pub from: Vec<TableReference>,
160    // `WHERE` clause
161    pub selection: Option<Expr>,
162    // `GROUP BY` clause
163    pub group_by: Option<GroupBy>,
164    // `HAVING` clause
165    pub having: Option<Expr>,
166    // `WINDOW` clause
167    pub window_list: Option<Vec<WindowDefinition>>,
168    // `QUALIFY` clause
169    pub qualify: Option<Expr>,
170}
171
172impl Display for SelectStmt {
173    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
174        // SELECT clause
175        write!(f, "SELECT ")?;
176        if let Some(hints) = &self.hints {
177            write!(f, "{} ", hints)?;
178        }
179        if self.distinct {
180            write!(f, "DISTINCT ")?;
181        }
182        if let Some(topn) = &self.top_n {
183            write!(f, "TOP {} ", topn)?;
184        }
185        write_comma_separated_list(f, &self.select_list)?;
186
187        // FROM clause
188        if !self.from.is_empty() {
189            write!(f, " FROM ")?;
190            write_comma_separated_list(f, &self.from)?;
191        }
192
193        // WHERE clause
194        if let Some(expr) = &self.selection {
195            write!(f, " WHERE {expr}")?;
196        }
197
198        // GROUP BY clause
199        if self.group_by.is_some() {
200            write!(f, " GROUP BY ")?;
201            write!(f, "{}", self.group_by.as_ref().unwrap())?;
202        }
203        // HAVING clause
204        if let Some(having) = &self.having {
205            write!(f, " HAVING {having}")?;
206        }
207
208        // WINDOW clause
209        if let Some(windows) = &self.window_list {
210            write!(f, " WINDOW ")?;
211            write_comma_separated_list(f, windows)?;
212        }
213
214        if let Some(qualify) = &self.qualify {
215            write!(f, " QUALIFY {qualify}")?;
216        }
217        Ok(())
218    }
219}
220
221/// Group by Clause.
222#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
223pub enum GroupBy {
224    /// GROUP BY expr [, expr]*
225    Normal(Vec<Expr>),
226    /// GROUP By ALL
227    All,
228    /// GROUP BY GROUPING SETS ( GroupSet [, GroupSet]* )
229    ///
230    /// GroupSet := (expr [, expr]*) | expr
231    GroupingSets(Vec<Vec<Expr>>),
232    /// GROUP BY CUBE ( expr [, expr]* )
233    Cube(Vec<Expr>),
234    /// GROUP BY ROLLUP ( expr [, expr]* )
235    Rollup(Vec<Expr>),
236    Combined(Vec<GroupBy>),
237}
238
239impl GroupBy {
240    pub fn normal_items(&self) -> Vec<Expr> {
241        match self {
242            GroupBy::Normal(exprs) => exprs.clone(),
243            _ => Vec::new(),
244        }
245    }
246}
247
248impl Display for GroupBy {
249    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
250        match self {
251            GroupBy::Normal(exprs) => {
252                write_comma_separated_list(f, exprs)?;
253            }
254            GroupBy::All => {
255                write!(f, "ALL")?;
256            }
257            GroupBy::GroupingSets(sets) => {
258                write!(f, "GROUPING SETS (")?;
259                for (i, set) in sets.iter().enumerate() {
260                    if i > 0 {
261                        write!(f, ", ")?;
262                    }
263                    write!(f, "(")?;
264                    write_comma_separated_list(f, set)?;
265                    write!(f, ")")?;
266                }
267                write!(f, ")")?;
268            }
269            GroupBy::Cube(exprs) => {
270                write!(f, "CUBE (")?;
271                write_comma_separated_list(f, exprs)?;
272                write!(f, ")")?;
273            }
274            GroupBy::Rollup(exprs) => {
275                write!(f, "ROLLUP (")?;
276                write_comma_separated_list(f, exprs)?;
277                write!(f, ")")?;
278            }
279            GroupBy::Combined(group_bys) => {
280                for (i, group_by) in group_bys.iter().enumerate() {
281                    if i > 0 {
282                        write!(f, ", ")?;
283                    }
284                    write!(f, "{}", group_by)?;
285                }
286            }
287        }
288        Ok(())
289    }
290}
291
292/// A relational set expression, like `SELECT ... FROM ... {UNION|EXCEPT|INTERSECT} SELECT ... FROM ...`
293#[derive(Educe, Drive, DriveMut)]
294#[educe(
295    PartialEq(bound = false, attrs = "#[recursive::recursive]"),
296    Clone(bound = false, attrs = "#[recursive::recursive]"),
297    Debug(bound = false, attrs = "#[recursive::recursive]")
298)]
299pub enum SetExpr {
300    Select(Box<SelectStmt>),
301    Query(Box<Query>),
302    // UNION/EXCEPT/INTERSECT operator
303    SetOperation(Box<SetOperation>),
304    // Values clause
305    Values { span: Span, values: Vec<Vec<Expr>> },
306}
307
308impl Display for SetExpr {
309    #[recursive::recursive]
310    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
311        match self {
312            SetExpr::Select(select_stmt) => {
313                write!(f, "{select_stmt}")?;
314            }
315            SetExpr::Query(query) => {
316                write!(f, "({query})")?;
317            }
318            SetExpr::SetOperation(set_operation) => {
319                // Check if the left or right expressions are also SetOperations
320                let left_needs_parentheses = matches!(set_operation.left.as_ref(), SetExpr::SetOperation(left_op) if left_op.op < set_operation.op);
321                let right_needs_parentheses = matches!(set_operation.right.as_ref(), SetExpr::SetOperation(right_op) if right_op.op < set_operation.op);
322
323                if left_needs_parentheses {
324                    write!(f, "(")?;
325                }
326                write!(f, "{}", set_operation.left)?;
327                if left_needs_parentheses {
328                    write!(f, ")")?;
329                }
330
331                match set_operation.op {
332                    SetOperator::Union => {
333                        write!(f, " UNION ")?;
334                    }
335                    SetOperator::Except => {
336                        write!(f, " EXCEPT ")?;
337                    }
338                    SetOperator::Intersect => {
339                        write!(f, " INTERSECT ")?;
340                    }
341                }
342                if set_operation.all {
343                    write!(f, "ALL ")?;
344                }
345                // Add parentheses if necessary
346                if right_needs_parentheses {
347                    write!(f, "(")?;
348                }
349                write!(f, "{}", set_operation.right)?;
350                if right_needs_parentheses {
351                    write!(f, ")")?;
352                }
353            }
354            SetExpr::Values { values, .. } => {
355                write!(f, "VALUES")?;
356                for (i, value) in values.iter().enumerate() {
357                    if i > 0 {
358                        write!(f, ", ")?;
359                    }
360                    write!(f, "(")?;
361                    write_comma_separated_list(f, value)?;
362                    write!(f, ")")?;
363                }
364            }
365        }
366        Ok(())
367    }
368}
369
370#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
371pub enum SetOperator {
372    Union,
373    Except,
374    Intersect,
375}
376
377impl PartialOrd for SetOperator {
378    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
379        if self == other {
380            Some(std::cmp::Ordering::Equal)
381        } else if self == &SetOperator::Intersect {
382            Some(std::cmp::Ordering::Greater)
383        } else {
384            Some(std::cmp::Ordering::Less)
385        }
386    }
387}
388
389/// `ORDER BY` clause
390#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
391pub struct OrderByExpr {
392    pub expr: Expr,
393    /// `ASC` or `DESC`
394    pub asc: Option<bool>,
395    /// `NULLS FIRST` or `NULLS LAST`
396    pub nulls_first: Option<bool>,
397}
398
399impl Display for OrderByExpr {
400    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
401        write!(f, "{}", self.expr)?;
402        if let Some(asc) = self.asc {
403            if asc {
404                write!(f, " ASC")?;
405            } else {
406                write!(f, " DESC")?;
407            }
408        }
409        if let Some(nulls_first) = self.nulls_first {
410            if nulls_first {
411                write!(f, " NULLS FIRST")?;
412            } else {
413                write!(f, " NULLS LAST")?;
414            }
415        }
416        Ok(())
417    }
418}
419
420/// One item of the comma-separated list following `SELECT`
421#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
422pub enum SelectTarget {
423    /// Expression with alias, e.g. `SELECT t.a, b AS a, a+1 AS b FROM t`
424    AliasedExpr {
425        expr: Box<Expr>,
426        alias: Option<Identifier>,
427    },
428
429    /// Qualified star name, e.g. `SELECT t.*  exclude a, columns(expr) FROM t`.
430    /// Columns("pattern_str")
431    /// Columns(lambda expression)
432    /// For simplicity, star wildcard is involved.
433    StarColumns {
434        qualified: QualifiedName,
435        column_filter: Option<ColumnFilter>,
436    },
437}
438
439impl SelectTarget {
440    pub fn is_star(&self) -> bool {
441        match self {
442            SelectTarget::AliasedExpr { .. } => false,
443            SelectTarget::StarColumns { qualified, .. } => {
444                matches!(qualified.last(), Some(Indirection::Star(_)))
445            }
446        }
447    }
448
449    pub fn exclude(&mut self, exclude: Vec<Identifier>) {
450        match self {
451            SelectTarget::AliasedExpr { .. } => unreachable!(),
452            SelectTarget::StarColumns { column_filter, .. } => {
453                *column_filter = Some(ColumnFilter::Excludes(exclude));
454            }
455        }
456    }
457
458    pub fn has_window(&self) -> bool {
459        match self {
460            SelectTarget::AliasedExpr { expr, .. } => match &**expr {
461                Expr::FunctionCall { func, .. } => func.window.is_some(),
462                _ => false,
463            },
464            SelectTarget::StarColumns { .. } => false,
465        }
466    }
467
468    pub fn function_call_name(&self) -> Option<String> {
469        match self {
470            SelectTarget::AliasedExpr { expr, .. } => match &**expr {
471                Expr::FunctionCall { func, .. } if func.window.is_none() => {
472                    Some(func.name.name.to_lowercase())
473                }
474                _ => None,
475            },
476            SelectTarget::StarColumns { .. } => None,
477        }
478    }
479}
480
481impl Display for SelectTarget {
482    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
483        match self {
484            SelectTarget::AliasedExpr { expr, alias } => {
485                write!(f, "{expr}")?;
486                if let Some(ident) = alias {
487                    write!(f, " AS {ident}")?;
488                }
489            }
490            SelectTarget::StarColumns {
491                qualified,
492                column_filter,
493            } => match column_filter {
494                Some(ColumnFilter::Excludes(excludes)) => {
495                    write_dot_separated_list(f, qualified)?;
496                    write!(f, " EXCLUDE (")?;
497                    write_comma_separated_list(f, excludes)?;
498                    write!(f, ")")?;
499                }
500                Some(ColumnFilter::Lambda(lambda)) => {
501                    write!(f, "COLUMNS({lambda})")?;
502                }
503                None => {
504                    write_dot_separated_list(f, qualified)?;
505                }
506            },
507        }
508        Ok(())
509    }
510}
511
512#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
513pub enum ColumnFilter {
514    Excludes(Vec<Identifier>),
515    Lambda(Lambda),
516}
517
518impl ColumnFilter {
519    pub fn get_excludes(&self) -> Option<&[Identifier]> {
520        if let ColumnFilter::Excludes(ex) = self {
521            Some(ex)
522        } else {
523            None
524        }
525    }
526
527    pub fn get_lambda(&self) -> Option<&Lambda> {
528        if let ColumnFilter::Lambda(l) = self {
529            Some(l)
530        } else {
531            None
532        }
533    }
534}
535
536pub type QualifiedName = Vec<Indirection>;
537
538/// Indirection of a select result, like a part of `db.table.column`.
539/// Can be a database name, table name, field name or wildcard star(`*`).
540#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
541pub enum Indirection {
542    // Field name
543    Identifier(Identifier),
544    // Wildcard star
545    Star(Span),
546}
547
548impl Display for Indirection {
549    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
550        match self {
551            Indirection::Identifier(ident) => {
552                write!(f, "{ident}")?;
553            }
554            Indirection::Star(_) => {
555                write!(f, "*")?;
556            }
557        }
558        Ok(())
559    }
560}
561
562/// Time Travel specification
563#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
564pub enum TimeTravelPoint {
565    Snapshot(String),
566    Timestamp(Box<Expr>),
567    Offset(Box<Expr>),
568    Stream {
569        catalog: Option<Identifier>,
570        database: Option<Identifier>,
571        name: Identifier,
572    },
573}
574
575impl Display for TimeTravelPoint {
576    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
577        match self {
578            TimeTravelPoint::Snapshot(sid) => {
579                write!(f, "(SNAPSHOT => '{sid}')")?;
580            }
581            TimeTravelPoint::Timestamp(ts) => {
582                write!(f, "(TIMESTAMP => {ts})")?;
583            }
584            TimeTravelPoint::Offset(num) => {
585                write!(f, "(OFFSET => {num})")?;
586            }
587            TimeTravelPoint::Stream {
588                catalog,
589                database,
590                name,
591            } => {
592                write!(f, "(STREAM => ")?;
593                write_dot_separated_list(
594                    f,
595                    catalog.iter().chain(database.iter()).chain(Some(name)),
596                )?;
597                write!(f, ")")?;
598            }
599        }
600
601        Ok(())
602    }
603}
604
605#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
606pub enum PivotValues {
607    ColumnValues(Vec<Expr>),
608    Subquery(Box<Query>),
609}
610
611#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
612pub struct Pivot {
613    pub aggregate: Expr,
614    pub value_column: Identifier,
615    pub values: PivotValues,
616}
617
618impl Display for Pivot {
619    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
620        write!(f, "PIVOT({} FOR {} IN (", self.aggregate, self.value_column)?;
621        match &self.values {
622            PivotValues::ColumnValues(column_values) => {
623                write_comma_separated_list(f, column_values)?;
624            }
625            PivotValues::Subquery(subquery) => {
626                write!(f, "{}", subquery)?;
627            }
628        }
629        write!(f, "))")?;
630        Ok(())
631    }
632}
633
634#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
635pub struct UnpivotName {
636    pub ident: Identifier,
637    pub alias: Option<String>,
638}
639
640impl Display for UnpivotName {
641    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
642        match &self.alias {
643            Some(alias) => {
644                write!(f, "{} AS {}", self.ident, QuotedString(alias, '\''))
645            }
646            None => write!(f, "{}", self.ident),
647        }
648    }
649}
650
651#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
652pub struct Unpivot {
653    pub value_column: Identifier,
654    pub unpivot_column: Identifier,
655    pub column_names: Vec<UnpivotName>,
656}
657
658impl Display for Unpivot {
659    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
660        write!(
661            f,
662            "UNPIVOT({} FOR {} IN (",
663            self.value_column, self.unpivot_column
664        )?;
665        write_comma_separated_list(f, &self.column_names)?;
666        write!(f, "))")
667    }
668}
669
670#[derive(Debug, Clone, PartialEq, Eq, Default, Drive, DriveMut)]
671pub struct WithOptions {
672    pub options: BTreeMap<String, String>,
673}
674
675impl Display for WithOptions {
676    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
677        write!(f, "WITH (")?;
678        write_comma_separated_string_map(f, &self.options)?;
679        write!(f, ")")
680    }
681}
682
683impl WithOptions {
684    /// Used for build change query.
685    pub fn to_change_query_with_clause(&self) -> String {
686        let mut result = String::from(" WITH (");
687        for (i, (k, v)) in self.options.iter().enumerate() {
688            if i > 0 {
689                result.push_str(", ");
690            }
691
692            if k == "consume" {
693                // The consume stream will be recorded in QueryContext.
694                // Skip 'consume' to avoid unnecessary operations.
695                result.push_str("consume = false");
696            } else {
697                result.push_str(&format!("{k} = '{v}'"));
698            }
699        }
700        result.push(')');
701        result
702    }
703}
704
705#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
706pub struct ChangesInterval {
707    pub append_only: bool,
708    pub at_point: TimeTravelPoint,
709    pub end_point: Option<TimeTravelPoint>,
710}
711
712impl Display for ChangesInterval {
713    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
714        write!(f, "CHANGES (INFORMATION => ")?;
715        if self.append_only {
716            write!(f, "APPEND_ONLY")?;
717        } else {
718            write!(f, "DEFAULT")?;
719        }
720        write!(f, ") AT {}", self.at_point)?;
721        if let Some(end_point) = &self.end_point {
722            write!(f, " END {}", end_point)?;
723        }
724        Ok(())
725    }
726}
727
728#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
729pub enum TemporalClause {
730    TimeTravel(TimeTravelPoint),
731    Changes(ChangesInterval),
732}
733
734impl Display for TemporalClause {
735    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
736        match self {
737            TemporalClause::TimeTravel(point) => {
738                write!(f, "AT {}", point)?;
739            }
740            TemporalClause::Changes(changes) => {
741                write!(f, "{}", changes)?;
742            }
743        }
744        Ok(())
745    }
746}
747
748#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Drive, DriveMut)]
749pub enum SampleRowLevel {
750    RowsNum(f64),
751    Probability(f64),
752}
753
754impl SampleRowLevel {
755    pub fn sample_probability(&self, stats_rows: Option<u64>) -> Result<Option<f64>> {
756        let rand = match &self {
757            SampleRowLevel::Probability(probability) => probability / 100.0,
758            SampleRowLevel::RowsNum(rows) => {
759                if let Some(row_num) = stats_rows {
760                    if row_num > 0 {
761                        rows / row_num as f64
762                    } else {
763                        return Ok(None);
764                    }
765                } else {
766                    return Ok(None);
767                }
768            }
769        };
770        if rand > 1.0 {
771            return Err(ParseError(
772                None,
773                format!(
774                    "Sample value should be less than or equal to 100, but got {}",
775                    rand * 100.0
776                ),
777            ));
778        }
779        Ok(Some(rand))
780    }
781}
782
783impl Eq for SampleRowLevel {}
784
785#[derive(
786    serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Drive, DriveMut, Default,
787)]
788pub struct SampleConfig {
789    pub row_level: Option<SampleRowLevel>,
790    pub block_level: Option<f64>,
791}
792
793impl SampleConfig {
794    pub fn set_row_level_sample(&mut self, value: f64, rows: bool) {
795        if rows {
796            self.row_level = Some(SampleRowLevel::RowsNum(value));
797        } else {
798            self.row_level = Some(SampleRowLevel::Probability(value));
799        }
800    }
801
802    pub fn set_block_level_sample(&mut self, probability: f64) {
803        self.block_level = Some(probability);
804    }
805}
806
807impl Eq for SampleConfig {}
808
809impl Display for SampleConfig {
810    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
811        write!(f, "SAMPLE ")?;
812        if let Some(block_level) = self.block_level {
813            write!(f, "BLOCK ({}) ", block_level)?;
814        }
815        if let Some(row_level) = &self.row_level {
816            match row_level {
817                SampleRowLevel::RowsNum(rows) => {
818                    write!(f, "ROW ({} ROWS)", rows)?;
819                }
820                SampleRowLevel::Probability(probability) => {
821                    write!(f, "ROW ({})", probability)?;
822                }
823            }
824        }
825        Ok(())
826    }
827}
828
829/// A table name or a parenthesized subquery with an optional alias
830#[allow(clippy::large_enum_variant)]
831#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
832pub enum TableReference {
833    // Table name
834    Table {
835        span: Span,
836        catalog: Option<Identifier>,
837        database: Option<Identifier>,
838        table: Identifier,
839        alias: Option<TableAlias>,
840        temporal: Option<TemporalClause>,
841        with_options: Option<WithOptions>,
842        pivot: Option<Box<Pivot>>,
843        unpivot: Option<Box<Unpivot>>,
844        sample: Option<SampleConfig>,
845    },
846    // `TABLE(expr)[ AS alias ]`
847    TableFunction {
848        span: Span,
849        /// Whether the table function is a lateral table function
850        lateral: bool,
851        name: Identifier,
852        params: Vec<Expr>,
853        named_params: Vec<(Identifier, Expr)>,
854        alias: Option<TableAlias>,
855        sample: Option<SampleConfig>,
856    },
857    // Derived table, which can be a subquery or joined tables or combination of them
858    Subquery {
859        span: Span,
860        /// Whether the subquery is a lateral subquery
861        lateral: bool,
862        subquery: Box<Query>,
863        alias: Option<TableAlias>,
864        pivot: Option<Box<Pivot>>,
865        unpivot: Option<Box<Unpivot>>,
866    },
867    Join {
868        span: Span,
869        join: Join,
870    },
871    Location {
872        span: Span,
873        location: FileLocation,
874        options: SelectStageOptions,
875        alias: Option<TableAlias>,
876    },
877}
878
879impl TableReference {
880    pub fn pivot(&self) -> Option<&Pivot> {
881        match self {
882            TableReference::Table { pivot, .. } => pivot.as_ref().map(|b| b.as_ref()),
883            TableReference::Subquery { pivot, .. } => pivot.as_ref().map(|b| b.as_ref()),
884            _ => None,
885        }
886    }
887
888    pub fn unpivot(&self) -> Option<&Unpivot> {
889        match self {
890            TableReference::Table { unpivot, .. } => unpivot.as_ref().map(|b| b.as_ref()),
891            TableReference::Subquery { unpivot, .. } => unpivot.as_ref().map(|b| b.as_ref()),
892            _ => None,
893        }
894    }
895
896    pub fn is_lateral_table_function(&self) -> bool {
897        match self {
898            TableReference::TableFunction { lateral, .. } => *lateral,
899            _ => false,
900        }
901    }
902
903    pub fn is_lateral_subquery(&self) -> bool {
904        match self {
905            TableReference::Subquery { lateral, .. } => *lateral,
906            _ => false,
907        }
908    }
909}
910
911impl Display for TableReference {
912    #[recursive::recursive]
913    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
914        match self {
915            TableReference::Table {
916                span: _,
917                catalog,
918                database,
919                table,
920                alias,
921                temporal,
922                with_options,
923                pivot,
924                unpivot,
925                sample,
926            } => {
927                write_dot_separated_list(
928                    f,
929                    catalog.iter().chain(database.iter()).chain(Some(table)),
930                )?;
931
932                if let Some(temporal) = temporal {
933                    write!(f, " {temporal}")?;
934                }
935
936                if let Some(with_options) = with_options {
937                    write!(f, " {with_options}")?;
938                }
939
940                if let Some(alias) = alias {
941                    write!(f, " AS {alias}")?;
942                }
943                if let Some(pivot) = pivot {
944                    write!(f, " {pivot}")?;
945                }
946
947                if let Some(unpivot) = unpivot {
948                    write!(f, " {unpivot}")?;
949                }
950
951                if let Some(sample) = sample {
952                    write!(f, " {sample}")?;
953                }
954            }
955            TableReference::TableFunction {
956                span: _,
957                lateral,
958                name,
959                params,
960                named_params,
961                alias,
962                sample,
963            } => {
964                if *lateral {
965                    write!(f, "LATERAL ")?;
966                }
967                write!(f, "{name}(")?;
968                write_comma_separated_list(f, params)?;
969                if !params.is_empty() && !named_params.is_empty() {
970                    write!(f, ",")?;
971                }
972                for (i, (k, v)) in named_params.iter().enumerate() {
973                    if i > 0 {
974                        write!(f, ",")?;
975                    }
976                    write!(f, "{k}=>{v}")?;
977                }
978                write!(f, ")")?;
979                if let Some(alias) = alias {
980                    write!(f, " AS {alias}")?;
981                }
982                if let Some(sample) = sample {
983                    write!(f, " {sample}")?;
984                }
985            }
986            TableReference::Subquery {
987                span: _,
988                lateral,
989                subquery,
990                alias,
991                pivot,
992                unpivot,
993            } => {
994                if *lateral {
995                    write!(f, "LATERAL ")?;
996                }
997                write!(f, "({subquery})")?;
998                if let Some(alias) = alias {
999                    write!(f, " AS {alias}")?;
1000                }
1001
1002                if let Some(pivot) = pivot {
1003                    write!(f, " {pivot}")?;
1004                }
1005
1006                if let Some(unpivot) = unpivot {
1007                    write!(f, " {unpivot}")?;
1008                }
1009            }
1010            TableReference::Join { span: _, join } => {
1011                write!(f, "{}", join.left)?;
1012                if join.condition == JoinCondition::Natural {
1013                    write!(f, " NATURAL")?;
1014                }
1015                match join.op {
1016                    JoinOperator::Inner => {
1017                        write!(f, " INNER JOIN")?;
1018                    }
1019                    JoinOperator::LeftOuter => {
1020                        write!(f, " LEFT OUTER JOIN")?;
1021                    }
1022                    JoinOperator::RightOuter => {
1023                        write!(f, " RIGHT OUTER JOIN")?;
1024                    }
1025                    JoinOperator::FullOuter => {
1026                        write!(f, " FULL OUTER JOIN")?;
1027                    }
1028                    JoinOperator::LeftSemi => {
1029                        write!(f, " LEFT SEMI JOIN")?;
1030                    }
1031                    JoinOperator::RightSemi => {
1032                        write!(f, " RIGHT SEMI JOIN")?;
1033                    }
1034                    JoinOperator::LeftAnti => {
1035                        write!(f, " LEFT ANTI JOIN")?;
1036                    }
1037                    JoinOperator::RightAnti => {
1038                        write!(f, " RIGHT ANTI JOIN")?;
1039                    }
1040                    JoinOperator::CrossJoin => {
1041                        write!(f, " CROSS JOIN")?;
1042                    }
1043                    JoinOperator::Asof => {
1044                        write!(f, " ASOF JOIN")?;
1045                    }
1046                    JoinOperator::LeftAsof => {
1047                        write!(f, " ASOF LEFT JOIN")?;
1048                    }
1049                    JoinOperator::RightAsof => {
1050                        write!(f, " ASOF RIGHT JOIN")?;
1051                    }
1052                }
1053                write!(f, " {}", join.right)?;
1054                match &join.condition {
1055                    JoinCondition::On(expr) => {
1056                        write!(f, " ON {expr}")?;
1057                    }
1058                    JoinCondition::Using(idents) => {
1059                        write!(f, " USING(")?;
1060                        write_comma_separated_list(f, idents)?;
1061                        write!(f, ")")?;
1062                    }
1063                    _ => {}
1064                }
1065            }
1066            TableReference::Location {
1067                span: _,
1068                location,
1069                options,
1070                alias,
1071            } => {
1072                write!(f, "{location}")?;
1073                if !options.is_empty() {
1074                    write!(f, "{options}")?;
1075                }
1076                if let Some(alias) = alias {
1077                    write!(f, " AS {alias}")?;
1078                }
1079            }
1080        }
1081        Ok(())
1082    }
1083}
1084
1085#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
1086pub struct TableAlias {
1087    pub name: Identifier,
1088    pub columns: Vec<Identifier>,
1089}
1090
1091impl Display for TableAlias {
1092    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
1093        write!(f, "{}", &self.name)?;
1094        if !self.columns.is_empty() {
1095            write!(f, "(")?;
1096            write_comma_separated_list(f, &self.columns)?;
1097            write!(f, ")")?;
1098        }
1099        Ok(())
1100    }
1101}
1102
1103#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
1104pub struct Join {
1105    pub op: JoinOperator,
1106    pub condition: JoinCondition,
1107    pub left: Box<TableReference>,
1108    pub right: Box<TableReference>,
1109}
1110
1111#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
1112pub enum JoinOperator {
1113    Inner,
1114    // Outer joins can not work with `JoinCondition::None`
1115    LeftOuter,
1116    RightOuter,
1117    FullOuter,
1118    LeftSemi,
1119    LeftAnti,
1120    RightSemi,
1121    RightAnti,
1122    // CrossJoin can only work with `JoinCondition::None`
1123    CrossJoin,
1124    // Asof
1125    Asof,
1126    LeftAsof,
1127    RightAsof,
1128}
1129
1130#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
1131pub enum JoinCondition {
1132    On(Box<Expr>),
1133    Using(Vec<Identifier>),
1134    Natural,
1135    None,
1136}
1137
1138impl SetExpr {
1139    pub fn span(&self) -> Span {
1140        match self {
1141            SetExpr::Select(stmt) => stmt.span,
1142            SetExpr::Query(query) => query.span,
1143            SetExpr::SetOperation(op) => op.span,
1144            SetExpr::Values { span, .. } => *span,
1145        }
1146    }
1147
1148    pub fn into_query(self) -> Query {
1149        match self {
1150            SetExpr::Query(query) => *query,
1151            _ => Query {
1152                span: self.span(),
1153                with: None,
1154                body: self,
1155                order_by: vec![],
1156                limit: vec![],
1157                offset: None,
1158                ignore_result: false,
1159            },
1160        }
1161    }
1162}