Skip to main content

mysqldump_mutator/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 {} ROWS", 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    Values(Values),
61    // TODO: ANSI SQL supports `TABLE` here.
62}
63
64impl fmt::Display for SetExpr {
65    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66        match self {
67            SetExpr::Values(v) => write!(f, "{}", v),
68        }
69    }
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Hash)]
73pub enum SetOperator {}
74
75/// A single CTE (used after `WITH`): `alias [(col1, col2, ...)] AS ( query )`
76/// The names in the column list before `AS`, when specified, replace the names
77/// of the columns returned by the query. The parser does not validate that the
78/// number of columns in the query matches the number of columns in the query.
79#[derive(Debug, Clone, PartialEq, Eq, Hash)]
80pub struct Cte {
81    pub alias: TableAlias,
82    pub query: Query,
83}
84
85impl fmt::Display for Cte {
86    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87        write!(f, "{} AS ({})", self.alias, self.query)
88    }
89}
90
91#[derive(Debug, Clone, PartialEq, Eq, Hash)]
92pub struct TableAlias {
93    pub name: Ident,
94    pub columns: Vec<Ident>,
95}
96
97impl fmt::Display for TableAlias {
98    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99        write!(f, "{}", self.name)?;
100        if !self.columns.is_empty() {
101            write!(f, " ({})", display_comma_separated(&self.columns))?;
102        }
103        Ok(())
104    }
105}
106
107/// SQL ORDER BY expression
108#[derive(Debug, Clone, PartialEq, Eq, Hash)]
109pub struct OrderByExpr {
110    pub expr: Expr,
111    pub asc: Option<bool>,
112}
113
114impl fmt::Display for OrderByExpr {
115    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116        match self.asc {
117            Some(true) => write!(f, "{} ASC", self.expr),
118            Some(false) => write!(f, "{} DESC", self.expr),
119            None => write!(f, "{}", self.expr),
120        }
121    }
122}
123
124#[derive(Debug, Clone, PartialEq, Eq, Hash)]
125pub struct Fetch {
126    pub with_ties: bool,
127    pub percent: bool,
128    pub quantity: Option<Expr>,
129}
130
131impl fmt::Display for Fetch {
132    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133        let extension = if self.with_ties { "WITH TIES" } else { "ONLY" };
134        if let Some(ref quantity) = self.quantity {
135            let percent = if self.percent { " PERCENT" } else { "" };
136            write!(f, "FETCH FIRST {}{} ROWS {}", quantity, percent, extension)
137        } else {
138            write!(f, "FETCH FIRST ROWS {}", extension)
139        }
140    }
141}
142
143#[derive(Debug, Clone, PartialEq, Eq, Hash)]
144pub struct Top {
145    /// SQL semantic equivalent of LIMIT but with same structure as FETCH.
146    pub with_ties: bool,
147    pub percent: bool,
148    pub quantity: Option<Expr>,
149}
150
151impl fmt::Display for Top {
152    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
153        let extension = if self.with_ties { " WITH TIES" } else { "" };
154        if let Some(ref quantity) = self.quantity {
155            let percent = if self.percent { " PERCENT" } else { "" };
156            write!(f, "TOP ({}){}{}", quantity, percent, extension)
157        } else {
158            write!(f, "TOP{}", extension)
159        }
160    }
161}
162
163#[derive(Debug, Clone, PartialEq, Eq, Hash)]
164pub struct Values(pub Vec<Vec<Expr>>);
165
166impl fmt::Display for Values {
167    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
168        write!(f, "VALUES ")?;
169        let mut delim = "";
170        for row in &self.0 {
171            write!(f, "{}", delim)?;
172            delim = ", ";
173            write!(f, "({})", display_comma_separated(row))?;
174        }
175        Ok(())
176    }
177}