wing_sqlparser/ast/
query.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12
13#[cfg(not(feature = "std"))]
14use alloc::{boxed::Box, vec::Vec};
15
16#[cfg(feature = "serde")]
17use serde::{Deserialize, Serialize};
18
19use crate::ast::*;
20
21/// The most complete variant of a `SELECT` query expression, optionally
22/// including `WITH`, `UNION` / other set operations, and `ORDER BY`.
23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25pub struct Query {
26    /// WITH (common table expressions, or CTEs)
27    pub with: Option<With>,
28    /// SELECT or UNION / EXCEPT / INTERSECT
29    pub body: SetExpr,
30    /// ORDER BY
31    pub order_by: Vec<OrderByExpr>,
32    /// `LIMIT { <N> | ALL }`
33    pub limit: Option<Expr>,
34    /// `OFFSET <N> [ { ROW | ROWS } ]`
35    pub offset: Option<Offset>,
36    /// `FETCH { FIRST | NEXT } <N> [ PERCENT ] { ROW | ROWS } | { ONLY | WITH TIES }`
37    pub fetch: Option<Fetch>,
38    // `FOR { UPDATE | SHARE }`
39    pub lock: Option<LockType>,
40}
41
42impl fmt::Display for Query {
43    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
44        if let Some(ref with) = self.with {
45            write!(f, "{} ", with)?;
46        }
47        write!(f, "{}", self.body)?;
48        if !self.order_by.is_empty() {
49            write!(f, " ORDER BY {}", display_comma_separated(&self.order_by))?;
50        }
51        if let Some(ref limit) = self.limit {
52            write!(f, " LIMIT {}", limit)?;
53        }
54        if let Some(ref offset) = self.offset {
55            write!(f, " {}", offset)?;
56        }
57        if let Some(ref fetch) = self.fetch {
58            write!(f, " {}", fetch)?;
59        }
60        if let Some(ref lock) = self.lock {
61            write!(f, " {}", lock)?;
62        }
63        Ok(())
64    }
65}
66
67/// A node in a tree, representing a "query body" expression, roughly:
68/// `SELECT ... [ {UNION|EXCEPT|INTERSECT} SELECT ...]`
69#[allow(clippy::large_enum_variant)]
70#[derive(Debug, Clone, PartialEq, Eq, Hash)]
71#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
72pub enum SetExpr {
73    /// Restricted SELECT .. FROM .. HAVING (no ORDER BY or set operations)
74    Select(Box<Select>),
75    /// Parenthesized SELECT subquery, which may include more set operations
76    /// in its body and an optional ORDER BY / LIMIT.
77    Query(Box<Query>),
78    /// UNION/EXCEPT/INTERSECT of two queries
79    SetOperation {
80        op: SetOperator,
81        all: bool,
82        left: Box<SetExpr>,
83        right: Box<SetExpr>,
84    },
85    Values(Values),
86    Insert(Statement),
87    // TODO: ANSI SQL supports `TABLE` here.
88}
89
90impl fmt::Display for SetExpr {
91    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92        match self {
93            SetExpr::Select(s) => write!(f, "{}", s),
94            SetExpr::Query(q) => write!(f, "({})", q),
95            SetExpr::Values(v) => write!(f, "{}", v),
96            SetExpr::Insert(v) => write!(f, "{}", v),
97            SetExpr::SetOperation {
98                left,
99                right,
100                op,
101                all,
102            } => {
103                let all_str = if *all { " ALL" } else { "" };
104                write!(f, "{} {}{} {}", left, op, all_str, right)
105            }
106        }
107    }
108}
109
110#[derive(Debug, Clone, PartialEq, Eq, Hash)]
111#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
112pub enum SetOperator {
113    Union,
114    Except,
115    Intersect,
116}
117
118impl fmt::Display for SetOperator {
119    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
120        f.write_str(match self {
121            SetOperator::Union => "UNION",
122            SetOperator::Except => "EXCEPT",
123            SetOperator::Intersect => "INTERSECT",
124        })
125    }
126}
127
128/// A restricted variant of `SELECT` (without CTEs/`ORDER BY`), which may
129/// appear either as the only body item of an `SQLQuery`, or as an operand
130/// to a set operation like `UNION`.
131#[derive(Debug, Clone, PartialEq, Eq, Hash)]
132#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
133pub struct Select {
134    pub distinct: bool,
135    /// MSSQL syntax: `TOP (<N>) [ PERCENT ] [ WITH TIES ]`
136    pub top: Option<Top>,
137    /// projection expressions
138    pub projection: Vec<SelectItem>,
139    /// FROM
140    pub from: Vec<TableWithJoins>,
141    /// LATERAL VIEWs
142    pub lateral_views: Vec<LateralView>,
143    /// WHERE
144    pub selection: Option<Expr>,
145    /// GROUP BY
146    pub group_by: Vec<Expr>,
147    /// CLUSTER BY (Hive)
148    pub cluster_by: Vec<Expr>,
149    /// DISTRIBUTE BY (Hive)
150    pub distribute_by: Vec<Expr>,
151    /// SORT BY (Hive)
152    pub sort_by: Vec<Expr>,
153    /// HAVING
154    pub having: Option<Expr>,
155}
156
157impl fmt::Display for Select {
158    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159        write!(f, "SELECT{}", if self.distinct { " DISTINCT" } else { "" })?;
160        if let Some(ref top) = self.top {
161            write!(f, " {}", top)?;
162        }
163        write!(f, " {}", display_comma_separated(&self.projection))?;
164        if !self.from.is_empty() {
165            write!(f, " FROM {}", display_comma_separated(&self.from))?;
166        }
167        if !self.lateral_views.is_empty() {
168            for lv in &self.lateral_views {
169                write!(f, "{}", lv)?;
170            }
171        }
172        if let Some(ref selection) = self.selection {
173            write!(f, " WHERE {}", selection)?;
174        }
175        if !self.group_by.is_empty() {
176            write!(f, " GROUP BY {}", display_comma_separated(&self.group_by))?;
177        }
178        if !self.cluster_by.is_empty() {
179            write!(
180                f,
181                " CLUSTER BY {}",
182                display_comma_separated(&self.cluster_by)
183            )?;
184        }
185        if !self.distribute_by.is_empty() {
186            write!(
187                f,
188                " DISTRIBUTE BY {}",
189                display_comma_separated(&self.distribute_by)
190            )?;
191        }
192        if !self.sort_by.is_empty() {
193            write!(f, " SORT BY {}", display_comma_separated(&self.sort_by))?;
194        }
195        if let Some(ref having) = self.having {
196            write!(f, " HAVING {}", having)?;
197        }
198        Ok(())
199    }
200}
201
202/// A hive LATERAL VIEW with potential column aliases
203#[derive(Debug, Clone, PartialEq, Eq, Hash)]
204#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
205pub struct LateralView {
206    /// LATERAL VIEW
207    pub lateral_view: Expr,
208    /// LATERAL VIEW table name
209    pub lateral_view_name: ObjectName,
210    /// LATERAL VIEW optional column aliases
211    pub lateral_col_alias: Vec<Ident>,
212    /// LATERAL VIEW OUTER
213    pub outer: bool,
214}
215
216impl fmt::Display for LateralView {
217    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
218        write!(
219            f,
220            " LATERAL VIEW{outer} {} {}",
221            self.lateral_view,
222            self.lateral_view_name,
223            outer = if self.outer { " OUTER" } else { "" }
224        )?;
225        if !self.lateral_col_alias.is_empty() {
226            write!(
227                f,
228                " AS {}",
229                display_comma_separated(&self.lateral_col_alias)
230            )?;
231        }
232        Ok(())
233    }
234}
235
236#[derive(Debug, Clone, PartialEq, Eq, Hash)]
237#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
238pub struct With {
239    pub recursive: bool,
240    pub cte_tables: Vec<Cte>,
241}
242
243impl fmt::Display for With {
244    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
245        write!(
246            f,
247            "WITH {}{}",
248            if self.recursive { "RECURSIVE " } else { "" },
249            display_comma_separated(&self.cte_tables)
250        )
251    }
252}
253
254/// A single CTE (used after `WITH`): `alias [(col1, col2, ...)] AS ( query )`
255/// The names in the column list before `AS`, when specified, replace the names
256/// of the columns returned by the query. The parser does not validate that the
257/// number of columns in the query matches the number of columns in the query.
258#[derive(Debug, Clone, PartialEq, Eq, Hash)]
259#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
260pub struct Cte {
261    pub alias: TableAlias,
262    pub query: Query,
263    pub from: Option<Ident>,
264}
265
266impl fmt::Display for Cte {
267    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
268        write!(f, "{} AS ({})", self.alias, self.query)?;
269        if let Some(ref fr) = self.from {
270            write!(f, " FROM {}", fr)?;
271        }
272        Ok(())
273    }
274}
275
276/// One item of the comma-separated list following `SELECT`
277#[derive(Debug, Clone, PartialEq, Eq, Hash)]
278#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
279pub enum SelectItem {
280    /// Any expression, not followed by `[ AS ] alias`
281    UnnamedExpr(Expr),
282    /// An expression, followed by `[ AS ] alias`
283    ExprWithAlias { expr: Expr, alias: Ident },
284    /// `alias.*` or even `schema.table.*`
285    QualifiedWildcard(ObjectName),
286    /// An unqualified `*`
287    Wildcard,
288}
289
290impl fmt::Display for SelectItem {
291    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
292        match &self {
293            SelectItem::UnnamedExpr(expr) => write!(f, "{}", expr),
294            SelectItem::ExprWithAlias { expr, alias } => write!(f, "{} AS {}", expr, alias),
295            SelectItem::QualifiedWildcard(prefix) => write!(f, "{}.*", prefix),
296            SelectItem::Wildcard => write!(f, "*"),
297        }
298    }
299}
300
301#[derive(Debug, Clone, PartialEq, Eq, Hash)]
302#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
303pub struct TableWithJoins {
304    pub relation: TableFactor,
305    pub joins: Vec<Join>,
306}
307
308impl fmt::Display for TableWithJoins {
309    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
310        write!(f, "{}", self.relation)?;
311        for join in &self.joins {
312            write!(f, "{}", join)?;
313        }
314        Ok(())
315    }
316}
317
318/// A table name or a parenthesized subquery with an optional alias
319#[derive(Debug, Clone, PartialEq, Eq, Hash)]
320#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
321pub enum TableFactor {
322    Table {
323        name: ObjectName,
324        alias: Option<TableAlias>,
325        /// Arguments of a table-valued function, as supported by Postgres
326        /// and MSSQL. Note that deprecated MSSQL `FROM foo (NOLOCK)` syntax
327        /// will also be parsed as `args`.
328        args: Vec<FunctionArg>,
329        /// MSSQL-specific `WITH (...)` hints such as NOLOCK.
330        with_hints: Vec<Expr>,
331    },
332    Derived {
333        lateral: bool,
334        subquery: Box<Query>,
335        alias: Option<TableAlias>,
336    },
337    /// `TABLE(<expr>)[ AS <alias> ]`
338    TableFunction {
339        expr: Expr,
340        alias: Option<TableAlias>,
341    },
342    /// Represents a parenthesized table factor. The SQL spec only allows a
343    /// join expression (`(foo <JOIN> bar [ <JOIN> baz ... ])`) to be nested,
344    /// possibly several times.
345    ///
346    /// The parser may also accept non-standard nesting of bare tables for some
347    /// dialects, but the information about such nesting is stripped from AST.
348    NestedJoin(Box<TableWithJoins>),
349}
350
351impl fmt::Display for TableFactor {
352    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
353        match self {
354            TableFactor::Table {
355                name,
356                alias,
357                args,
358                with_hints,
359            } => {
360                write!(f, "{}", name)?;
361                if !args.is_empty() {
362                    write!(f, "({})", display_comma_separated(args))?;
363                }
364                if let Some(alias) = alias {
365                    write!(f, " AS {}", alias)?;
366                }
367                if !with_hints.is_empty() {
368                    write!(f, " WITH ({})", display_comma_separated(with_hints))?;
369                }
370                Ok(())
371            }
372            TableFactor::Derived {
373                lateral,
374                subquery,
375                alias,
376            } => {
377                if *lateral {
378                    write!(f, "LATERAL ")?;
379                }
380                write!(f, "({})", subquery)?;
381                if let Some(alias) = alias {
382                    write!(f, " AS {}", alias)?;
383                }
384                Ok(())
385            }
386            TableFactor::TableFunction { expr, alias } => {
387                write!(f, "TABLE({})", expr)?;
388                if let Some(alias) = alias {
389                    write!(f, " AS {}", alias)?;
390                }
391                Ok(())
392            }
393            TableFactor::NestedJoin(table_reference) => write!(f, "({})", table_reference),
394        }
395    }
396}
397
398#[derive(Debug, Clone, PartialEq, Eq, Hash)]
399#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
400pub struct TableAlias {
401    pub name: Ident,
402    pub columns: Vec<Ident>,
403}
404
405impl fmt::Display for TableAlias {
406    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
407        write!(f, "{}", self.name)?;
408        if !self.columns.is_empty() {
409            write!(f, " ({})", display_comma_separated(&self.columns))?;
410        }
411        Ok(())
412    }
413}
414
415#[derive(Debug, Clone, PartialEq, Eq, Hash)]
416#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
417pub struct Join {
418    pub relation: TableFactor,
419    pub join_operator: JoinOperator,
420}
421
422impl fmt::Display for Join {
423    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
424        fn prefix(constraint: &JoinConstraint) -> &'static str {
425            match constraint {
426                JoinConstraint::Natural => "NATURAL ",
427                _ => "",
428            }
429        }
430        fn suffix(constraint: &'_ JoinConstraint) -> impl fmt::Display + '_ {
431            struct Suffix<'a>(&'a JoinConstraint);
432            impl<'a> fmt::Display for Suffix<'a> {
433                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
434                    match self.0 {
435                        JoinConstraint::On(expr) => write!(f, " ON {}", expr),
436                        JoinConstraint::Using(attrs) => {
437                            write!(f, " USING({})", display_comma_separated(attrs))
438                        }
439                        _ => Ok(()),
440                    }
441                }
442            }
443            Suffix(constraint)
444        }
445        match &self.join_operator {
446            JoinOperator::Inner(constraint) => write!(
447                f,
448                " {}JOIN {}{}",
449                prefix(constraint),
450                self.relation,
451                suffix(constraint)
452            ),
453            JoinOperator::LeftOuter(constraint) => write!(
454                f,
455                " {}LEFT JOIN {}{}",
456                prefix(constraint),
457                self.relation,
458                suffix(constraint)
459            ),
460            JoinOperator::RightOuter(constraint) => write!(
461                f,
462                " {}RIGHT JOIN {}{}",
463                prefix(constraint),
464                self.relation,
465                suffix(constraint)
466            ),
467            JoinOperator::FullOuter(constraint) => write!(
468                f,
469                " {}FULL JOIN {}{}",
470                prefix(constraint),
471                self.relation,
472                suffix(constraint)
473            ),
474            JoinOperator::CrossJoin => write!(f, " CROSS JOIN {}", self.relation),
475            JoinOperator::CrossApply => write!(f, " CROSS APPLY {}", self.relation),
476            JoinOperator::OuterApply => write!(f, " OUTER APPLY {}", self.relation),
477        }
478    }
479}
480
481#[derive(Debug, Clone, PartialEq, Eq, Hash)]
482#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
483pub enum JoinOperator {
484    Inner(JoinConstraint),
485    LeftOuter(JoinConstraint),
486    RightOuter(JoinConstraint),
487    FullOuter(JoinConstraint),
488    CrossJoin,
489    /// CROSS APPLY (non-standard)
490    CrossApply,
491    /// OUTER APPLY (non-standard)
492    OuterApply,
493}
494
495#[derive(Debug, Clone, PartialEq, Eq, Hash)]
496#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
497pub enum JoinConstraint {
498    On(Expr),
499    Using(Vec<Ident>),
500    Natural,
501    None,
502}
503
504/// An `ORDER BY` expression
505#[derive(Debug, Clone, PartialEq, Eq, Hash)]
506#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
507pub struct OrderByExpr {
508    pub expr: Expr,
509    /// Optional `ASC` or `DESC`
510    pub asc: Option<bool>,
511    /// Optional `NULLS FIRST` or `NULLS LAST`
512    pub nulls_first: Option<bool>,
513}
514
515impl fmt::Display for OrderByExpr {
516    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
517        write!(f, "{}", self.expr)?;
518        match self.asc {
519            Some(true) => write!(f, " ASC")?,
520            Some(false) => write!(f, " DESC")?,
521            None => (),
522        }
523        match self.nulls_first {
524            Some(true) => write!(f, " NULLS FIRST")?,
525            Some(false) => write!(f, " NULLS LAST")?,
526            None => (),
527        }
528        Ok(())
529    }
530}
531
532#[derive(Debug, Clone, PartialEq, Eq, Hash)]
533#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
534pub struct Offset {
535    pub value: Expr,
536    pub rows: OffsetRows,
537}
538
539impl fmt::Display for Offset {
540    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
541        write!(f, "OFFSET {}{}", self.value, self.rows)
542    }
543}
544
545/// Stores the keyword after `OFFSET <number>`
546#[derive(Debug, Clone, PartialEq, Eq, Hash)]
547#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
548pub enum OffsetRows {
549    /// Omitting ROW/ROWS is non-standard MySQL quirk.
550    None,
551    Row,
552    Rows,
553}
554
555impl fmt::Display for OffsetRows {
556    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
557        match self {
558            OffsetRows::None => Ok(()),
559            OffsetRows::Row => write!(f, " ROW"),
560            OffsetRows::Rows => write!(f, " ROWS"),
561        }
562    }
563}
564
565#[derive(Debug, Clone, PartialEq, Eq, Hash)]
566#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
567pub struct Fetch {
568    pub with_ties: bool,
569    pub percent: bool,
570    pub quantity: Option<Expr>,
571}
572
573impl fmt::Display for Fetch {
574    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
575        let extension = if self.with_ties { "WITH TIES" } else { "ONLY" };
576        if let Some(ref quantity) = self.quantity {
577            let percent = if self.percent { " PERCENT" } else { "" };
578            write!(f, "FETCH FIRST {}{} ROWS {}", quantity, percent, extension)
579        } else {
580            write!(f, "FETCH FIRST ROWS {}", extension)
581        }
582    }
583}
584
585#[derive(Debug, Clone, PartialEq, Eq, Hash)]
586#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
587pub enum LockType {
588    Shared,
589    Exclusive,
590}
591
592impl fmt::Display for LockType {
593    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
594        let select_lock = match self {
595            LockType::Shared => "FOR SHARE",
596            LockType::Exclusive => "FOR UPDATE",
597        };
598        write!(f, "{}", select_lock)
599    }
600}
601
602#[derive(Debug, Clone, PartialEq, Eq, Hash)]
603#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
604pub struct Top {
605    /// SQL semantic equivalent of LIMIT but with same structure as FETCH.
606    pub with_ties: bool,
607    pub percent: bool,
608    pub quantity: Option<Expr>,
609}
610
611impl fmt::Display for Top {
612    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
613        let extension = if self.with_ties { " WITH TIES" } else { "" };
614        if let Some(ref quantity) = self.quantity {
615            let percent = if self.percent { " PERCENT" } else { "" };
616            write!(f, "TOP ({}){}{}", quantity, percent, extension)
617        } else {
618            write!(f, "TOP{}", extension)
619        }
620    }
621}
622
623#[derive(Debug, Clone, PartialEq, Eq, Hash)]
624#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
625pub struct Values(pub Vec<Vec<Expr>>);
626
627impl fmt::Display for Values {
628    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
629        write!(f, "VALUES ")?;
630        let mut delim = "";
631        for row in &self.0 {
632            write!(f, "{}", delim)?;
633            delim = ", ";
634            write!(f, "({})", display_comma_separated(row))?;
635        }
636        Ok(())
637    }
638}