sql_ast/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
13use super::*;
14
15/// The most complete variant of a `SELECT` query expression, optionally
16/// including `WITH`, `UNION` / other set operations, and `ORDER BY`.
17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub struct Query {
19    /// WITH (common table expressions, or CTEs)
20    pub ctes: Vec<Cte>,
21    /// SELECT or UNION / EXCEPT / INTECEPT
22    pub body: SetExpr,
23    /// ORDER BY
24    pub order_by: Vec<OrderByExpr>,
25    /// `LIMIT { <N> | ALL }`
26    pub limit: Option<Expr>,
27    /// `OFFSET <N> { ROW | ROWS }`
28    pub offset: Option<Expr>,
29    /// `FETCH { FIRST | NEXT } <N> [ PERCENT ] { ROW | ROWS } | { ONLY | WITH TIES }`
30    pub fetch: Option<Fetch>,
31}
32
33impl fmt::Display for Query {
34    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35        if !self.ctes.is_empty() {
36            write!(f, "WITH {} ", display_comma_separated(&self.ctes))?;
37        }
38        write!(f, "{}", self.body)?;
39        if !self.order_by.is_empty() {
40            write!(f, " ORDER BY {}", display_comma_separated(&self.order_by))?;
41        }
42        if let Some(ref limit) = self.limit {
43            write!(f, " LIMIT {}", limit)?;
44        }
45        if let Some(ref offset) = self.offset {
46            write!(f, " OFFSET {}", offset)?;
47        }
48        if let Some(ref fetch) = self.fetch {
49            write!(f, " {}", fetch)?;
50        }
51        Ok(())
52    }
53}
54
55/// A node in a tree, representing a "query body" expression, roughly:
56/// `SELECT ... [ {UNION|EXCEPT|INTERSECT} SELECT ...]`
57#[derive(Debug, Clone, PartialEq, Eq, Hash)]
58pub enum SetExpr {
59    /// Restricted SELECT .. FROM .. HAVING (no ORDER BY or set operations)
60    Select(Box<Select>),
61    /// Parenthesized SELECT subquery, which may include more set operations
62    /// in its body and an optional ORDER BY / LIMIT.
63    Query(Box<Query>),
64    /// UNION/EXCEPT/INTERSECT of two queries
65    SetOperation {
66        op: SetOperator,
67        all: bool,
68        left: Box<SetExpr>,
69        right: Box<SetExpr>,
70    },
71    Values(Values),
72    ParameterizedValue(Vec<usize>),
73    // TODO: ANSI SQL supports `TABLE` here.
74}
75
76impl fmt::Display for SetExpr {
77    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78        match self {
79            SetExpr::Select(s) => write!(f, "{}", s),
80            SetExpr::Query(q) => write!(f, "({})", q),
81            SetExpr::Values(v) => write!(f, "{}", v),
82            SetExpr::SetOperation {
83                left,
84                right,
85                op,
86                all,
87            } => {
88                let all_str = if *all { " ALL" } else { "" };
89                write!(f, "{} {}{} {}", left, op, all_str, right)
90            }
91            SetExpr::ParameterizedValue(params) => write!(
92                f,
93                "VALUES({})",
94                params
95                    .iter()
96                    .map(|i| format!("${}", i))
97                    .collect::<Vec<String>>()
98                    .join(", ")
99            ),
100        }
101    }
102}
103
104#[derive(Debug, Clone, PartialEq, Eq, Hash)]
105pub enum SetOperator {
106    Union,
107    Except,
108    Intersect,
109}
110
111impl fmt::Display for SetOperator {
112    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113        f.write_str(match self {
114            SetOperator::Union => "UNION",
115            SetOperator::Except => "EXCEPT",
116            SetOperator::Intersect => "INTERSECT",
117        })
118    }
119}
120
121/// A restricted variant of `SELECT` (without CTEs/`ORDER BY`), which may
122/// appear either as the only body item of an `SQLQuery`, or as an operand
123/// to a set operation like `UNION`.
124#[derive(Debug, Clone, PartialEq, Eq, Hash)]
125pub struct Select {
126    pub distinct: bool,
127    /// projection expressions
128    pub projection: Vec<SelectItem>,
129    /// FROM
130    pub from: Vec<TableWithJoins>,
131    /// WHERE
132    pub selection: Option<Expr>,
133    /// GROUP BY
134    pub group_by: Vec<Expr>,
135    /// HAVING
136    pub having: Option<Expr>,
137}
138
139impl fmt::Display for Select {
140    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
141        write!(
142            f,
143            "SELECT{} {}",
144            if self.distinct { " DISTINCT" } else { "" },
145            display_comma_separated(&self.projection)
146        )?;
147        if !self.from.is_empty() {
148            write!(f, " FROM {}", display_comma_separated(&self.from))?;
149        }
150        if let Some(ref selection) = self.selection {
151            write!(f, " WHERE {}", selection)?;
152        }
153        if !self.group_by.is_empty() {
154            write!(f, " GROUP BY {}", display_comma_separated(&self.group_by))?;
155        }
156        if let Some(ref having) = self.having {
157            write!(f, " HAVING {}", having)?;
158        }
159        Ok(())
160    }
161}
162
163/// A single CTE (used after `WITH`): `alias [(col1, col2, ...)] AS ( query )`
164/// The names in the column list before `AS`, when specified, replace the names
165/// of the columns returned by the query. The parser does not validate that the
166/// number of columns in the query matches the number of columns in the query.
167#[derive(Debug, Clone, PartialEq, Eq, Hash)]
168pub struct Cte {
169    pub alias: TableAlias,
170    pub query: Query,
171}
172
173impl fmt::Display for Cte {
174    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175        write!(f, "{} AS ({})", self.alias, self.query)
176    }
177}
178
179/// One item of the comma-separated list following `SELECT`
180#[derive(Debug, Clone, PartialEq, Eq, Hash)]
181pub enum SelectItem {
182    /// Any expression, not followed by `[ AS ] alias`
183    UnnamedExpr(Expr),
184    /// An expression, followed by `[ AS ] alias`
185    ExprWithAlias { expr: Expr, alias: Ident },
186    /// `alias.*` or even `schema.table.*`
187    QualifiedWildcard(ObjectName),
188    /// An unqualified `*`
189    Wildcard,
190}
191
192impl fmt::Display for SelectItem {
193    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
194        match &self {
195            SelectItem::UnnamedExpr(expr) => write!(f, "{}", expr),
196            SelectItem::ExprWithAlias { expr, alias } => write!(f, "{} AS {}", expr, alias),
197            SelectItem::QualifiedWildcard(prefix) => write!(f, "{}.*", prefix),
198            SelectItem::Wildcard => write!(f, "*"),
199        }
200    }
201}
202
203#[derive(Debug, Clone, PartialEq, Eq, Hash)]
204pub struct TableWithJoins {
205    pub relation: TableFactor,
206    pub joins: Vec<Join>,
207}
208
209impl fmt::Display for TableWithJoins {
210    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
211        write!(f, "{}", self.relation)?;
212        for join in &self.joins {
213            write!(f, "{}", join)?;
214        }
215        Ok(())
216    }
217}
218
219/// A table name or a parenthesized subquery with an optional alias
220#[derive(Debug, Clone, PartialEq, Eq, Hash)]
221pub enum TableFactor {
222    Table {
223        name: ObjectName,
224        alias: Option<TableAlias>,
225        /// Arguments of a table-valued function, as supported by Postgres
226        /// and MSSQL. Note that deprecated MSSQL `FROM foo (NOLOCK)` syntax
227        /// will also be parsed as `args`.
228        args: Vec<Expr>,
229        /// MSSQL-specific `WITH (...)` hints such as NOLOCK.
230        with_hints: Vec<Expr>,
231    },
232    Derived {
233        lateral: bool,
234        subquery: Box<Query>,
235        alias: Option<TableAlias>,
236    },
237    /// Represents a parenthesized join expression, such as
238    /// `(foo <JOIN> bar [ <JOIN> baz ... ])`.
239    /// The inner `TableWithJoins` can have no joins only if its
240    /// `relation` is itself a `TableFactor::NestedJoin`.
241    NestedJoin(Box<TableWithJoins>),
242}
243
244impl fmt::Display for TableFactor {
245    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246        match self {
247            TableFactor::Table {
248                name,
249                alias,
250                args,
251                with_hints,
252            } => {
253                write!(f, "{}", name)?;
254                if !args.is_empty() {
255                    write!(f, "({})", display_comma_separated(args))?;
256                }
257                if let Some(alias) = alias {
258                    write!(f, " AS {}", alias)?;
259                }
260                if !with_hints.is_empty() {
261                    write!(f, " WITH ({})", display_comma_separated(with_hints))?;
262                }
263                Ok(())
264            }
265            TableFactor::Derived {
266                lateral,
267                subquery,
268                alias,
269            } => {
270                if *lateral {
271                    write!(f, "LATERAL ")?;
272                }
273                write!(f, "({})", subquery)?;
274                if let Some(alias) = alias {
275                    write!(f, " AS {}", alias)?;
276                }
277                Ok(())
278            }
279            TableFactor::NestedJoin(table_reference) => write!(f, "({})", table_reference),
280        }
281    }
282}
283
284#[derive(Debug, Clone, PartialEq, Eq, Hash)]
285pub struct TableAlias {
286    pub name: Ident,
287    pub columns: Vec<Ident>,
288}
289
290impl fmt::Display for TableAlias {
291    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
292        write!(f, "{}", self.name)?;
293        if !self.columns.is_empty() {
294            write!(f, " ({})", display_comma_separated(&self.columns))?;
295        }
296        Ok(())
297    }
298}
299
300#[derive(Debug, Clone, PartialEq, Eq, Hash)]
301pub struct Join {
302    pub relation: TableFactor,
303    pub join_operator: JoinOperator,
304}
305
306impl fmt::Display for Join {
307    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
308        fn prefix(constraint: &JoinConstraint) -> &'static str {
309            match constraint {
310                JoinConstraint::Natural => "NATURAL ",
311                _ => "",
312            }
313        }
314        fn suffix(constraint: &JoinConstraint) -> impl fmt::Display + '_ {
315            struct Suffix<'a>(&'a JoinConstraint);
316            impl<'a> fmt::Display for Suffix<'a> {
317                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
318                    match self.0 {
319                        JoinConstraint::On(expr) => write!(f, " ON {}", expr),
320                        JoinConstraint::Using(attrs) => {
321                            write!(f, " USING({})", display_comma_separated(attrs))
322                        }
323                        _ => Ok(()),
324                    }
325                }
326            }
327            Suffix(constraint)
328        }
329        match &self.join_operator {
330            JoinOperator::Inner(constraint) => write!(
331                f,
332                " {}JOIN {}{}",
333                prefix(constraint),
334                self.relation,
335                suffix(constraint)
336            ),
337            JoinOperator::LeftOuter(constraint) => write!(
338                f,
339                " {}LEFT JOIN {}{}",
340                prefix(constraint),
341                self.relation,
342                suffix(constraint)
343            ),
344            JoinOperator::RightOuter(constraint) => write!(
345                f,
346                " {}RIGHT JOIN {}{}",
347                prefix(constraint),
348                self.relation,
349                suffix(constraint)
350            ),
351            JoinOperator::FullOuter(constraint) => write!(
352                f,
353                " {}FULL JOIN {}{}",
354                prefix(constraint),
355                self.relation,
356                suffix(constraint)
357            ),
358            JoinOperator::CrossJoin => write!(f, " CROSS JOIN {}", self.relation),
359            JoinOperator::CrossApply => write!(f, " CROSS APPLY {}", self.relation),
360            JoinOperator::OuterApply => write!(f, " OUTER APPLY {}", self.relation),
361        }
362    }
363}
364
365#[derive(Debug, Clone, PartialEq, Eq, Hash)]
366pub enum JoinOperator {
367    Inner(JoinConstraint),
368    LeftOuter(JoinConstraint),
369    RightOuter(JoinConstraint),
370    FullOuter(JoinConstraint),
371    CrossJoin,
372    /// CROSS APPLY (non-standard)
373    CrossApply,
374    /// OUTER APPLY (non-standard)
375    OuterApply,
376}
377
378#[derive(Debug, Clone, PartialEq, Eq, Hash)]
379pub enum JoinConstraint {
380    On(Expr),
381    Using(Vec<Ident>),
382    Natural,
383}
384
385/// SQL ORDER BY expression
386#[derive(Debug, Clone, PartialEq, Eq, Hash)]
387pub struct OrderByExpr {
388    pub expr: Expr,
389    pub asc: Option<bool>,
390}
391
392impl fmt::Display for OrderByExpr {
393    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
394        match self.asc {
395            Some(true) => write!(f, "{} ASC", self.expr),
396            Some(false) => write!(f, "{} DESC", self.expr),
397            None => write!(f, "{}", self.expr),
398        }
399    }
400}
401
402#[derive(Debug, Clone, PartialEq, Eq, Hash)]
403pub struct Fetch {
404    pub with_ties: bool,
405    pub percent: bool,
406    pub quantity: Option<Expr>,
407}
408
409impl fmt::Display for Fetch {
410    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
411        let extension = if self.with_ties { "WITH TIES" } else { "ONLY" };
412        if let Some(ref quantity) = self.quantity {
413            let percent = if self.percent { " PERCENT" } else { "" };
414            write!(f, "FETCH FIRST {}{} ROWS {}", quantity, percent, extension)
415        } else {
416            write!(f, "FETCH FIRST ROWS {}", extension)
417        }
418    }
419}
420
421#[derive(Debug, Clone, PartialEq, Eq, Hash)]
422pub struct Values(pub Vec<Vec<Expr>>);
423
424impl fmt::Display for Values {
425    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
426        write!(f, "VALUES ")?;
427        let mut delim = "";
428        for row in &self.0 {
429            write!(f, "{}", delim)?;
430            delim = ", ";
431            write!(f, "({})", display_comma_separated(row))?;
432        }
433        Ok(())
434    }
435}