sqlparser_mysql/dms/
select.rs

1use std::fmt;
2use std::str;
3
4use nom::bytes::complete::{tag_no_case, take_till, take_until};
5use nom::character::complete::{multispace0, multispace1};
6use nom::combinator::{map, opt};
7use nom::multi::many0;
8use nom::sequence::{delimited, terminated, tuple};
9use nom::IResult;
10
11use base::column::Column;
12use base::condition::ConditionExpression;
13use base::error::ParseSQLError;
14use base::table::Table;
15use base::{
16    CommonParser, FieldDefinitionExpression, JoinClause, JoinConstraint, JoinOperator,
17    JoinRightSide, OrderClause,
18};
19
20#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
21pub struct SelectStatement {
22    pub tables: Vec<Table>,
23    pub distinct: bool,
24    pub fields: Vec<FieldDefinitionExpression>,
25    pub join: Vec<JoinClause>,
26    pub where_clause: Option<ConditionExpression>,
27    pub group_by: Option<GroupByClause>,
28    pub order: Option<OrderClause>,
29    pub limit: Option<LimitClause>,
30}
31
32impl SelectStatement {
33    // Parse rule for a SQL selection query.
34    pub fn parse(i: &str) -> IResult<&str, SelectStatement, ParseSQLError<&str>> {
35        terminated(Self::nested_selection, CommonParser::statement_terminator)(i)
36    }
37
38    pub fn nested_selection(i: &str) -> IResult<&str, SelectStatement, ParseSQLError<&str>> {
39        let (
40            remaining_input,
41            (_, _, distinct, _, fields, _, tables, join, where_clause, group_by, order, limit),
42        ) = tuple((
43            tag_no_case("SELECT"),
44            multispace1,
45            opt(tag_no_case("DISTINCT")),
46            multispace0,
47            FieldDefinitionExpression::parse,
48            delimited(multispace0, tag_no_case("FROM"), multispace0),
49            Table::table_list,
50            many0(JoinClause::parse),
51            opt(ConditionExpression::parse),
52            opt(GroupByClause::parse),
53            opt(OrderClause::parse),
54            opt(LimitClause::parse),
55        ))(i)?;
56        Ok((
57            remaining_input,
58            SelectStatement {
59                tables,
60                distinct: distinct.is_some(),
61                fields,
62                join,
63                where_clause,
64                group_by,
65                order,
66                limit,
67            },
68        ))
69    }
70}
71
72impl fmt::Display for SelectStatement {
73    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74        write!(f, "SELECT ")?;
75        if self.distinct {
76            write!(f, "DISTINCT ")?;
77        }
78        write!(
79            f,
80            "{}",
81            self.fields
82                .iter()
83                .map(|field| format!("{}", field))
84                .collect::<Vec<_>>()
85                .join(", ")
86        )?;
87
88        if !self.tables.is_empty() {
89            write!(f, " FROM ")?;
90            write!(
91                f,
92                "{}",
93                self.tables
94                    .iter()
95                    .map(|table| format!("{}", table))
96                    .collect::<Vec<_>>()
97                    .join(", ")
98            )?;
99        }
100        for jc in &self.join {
101            write!(f, " {}", jc)?;
102        }
103        if let Some(ref where_clause) = self.where_clause {
104            write!(f, " WHERE ")?;
105            write!(f, "{}", where_clause)?;
106        }
107        if let Some(ref group_by) = self.group_by {
108            write!(f, " {}", group_by)?;
109        }
110        if let Some(ref order) = self.order {
111            write!(f, " {}", order)?;
112        }
113        if let Some(ref limit) = self.limit {
114            write!(f, " {}", limit)?;
115        }
116        Ok(())
117    }
118}
119
120#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
121pub struct GroupByClause {
122    pub columns: Vec<Column>,
123    pub having: Option<ConditionExpression>,
124}
125
126impl GroupByClause {
127    // Parse GROUP BY clause
128    pub fn parse(i: &str) -> IResult<&str, GroupByClause, ParseSQLError<&str>> {
129        let (remaining_input, (_, _, _, columns, having)) = tuple((
130            multispace0,
131            tag_no_case("GROUP BY"),
132            multispace1,
133            Column::field_list,
134            opt(ConditionExpression::having_clause),
135        ))(i)?;
136
137        Ok((remaining_input, GroupByClause { columns, having }))
138    }
139}
140
141impl fmt::Display for GroupByClause {
142    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143        write!(f, "GROUP BY ")?;
144        write!(
145            f,
146            "{}",
147            self.columns
148                .iter()
149                .map(|c| format!("{}", c))
150                .collect::<Vec<_>>()
151                .join(", ")
152        )?;
153        if let Some(ref having) = self.having {
154            write!(f, " HAVING {}", having)?;
155        }
156        Ok(())
157    }
158}
159
160// TODO need parse as detailed data type
161#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
162pub struct BetweenAndClause {
163    pub left: String,
164    pub right: String,
165}
166
167impl BetweenAndClause {
168    pub fn parse(i: &str) -> IResult<&str, BetweenAndClause, ParseSQLError<&str>> {
169        map(
170            tuple((
171                CommonParser::sql_identifier,
172                multispace1,
173                tag_no_case("BETWEEN"),
174                multispace1,
175                take_until(" "),
176                multispace1,
177                tag_no_case("AND"),
178                multispace1,
179                take_till(|c| c == ' '),
180            )),
181            |x| BetweenAndClause {
182                left: String::from(x.4),
183                right: String::from(x.8),
184            },
185        )(i)
186    }
187}
188
189impl fmt::Display for BetweenAndClause {
190    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191        write!(f, " BETWEEN {}", self.left)?;
192        write!(f, " AND {}", self.right)?;
193        Ok(())
194    }
195}
196
197#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
198pub struct LimitClause {
199    pub limit: u64,
200    pub offset: u64,
201}
202
203impl LimitClause {
204    pub fn parse(i: &str) -> IResult<&str, LimitClause, ParseSQLError<&str>> {
205        let (remaining_input, (_, _, _, limit, opt_offset)) = tuple((
206            multispace0,
207            tag_no_case("LIMIT"),
208            multispace1,
209            CommonParser::unsigned_number,
210            opt(Self::offset),
211        ))(i)?;
212        let offset = opt_offset.unwrap_or(0);
213
214        Ok((remaining_input, LimitClause { limit, offset }))
215    }
216
217    fn offset(i: &str) -> IResult<&str, u64, ParseSQLError<&str>> {
218        let (remaining_input, (_, _, _, val)) = tuple((
219            multispace0,
220            tag_no_case("OFFSET"),
221            multispace1,
222            CommonParser::unsigned_number,
223        ))(i)?;
224
225        Ok((remaining_input, val))
226    }
227}
228
229impl fmt::Display for LimitClause {
230    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
231        write!(f, "LIMIT {}", self.limit)?;
232        if self.offset > 0 {
233            write!(f, " OFFSET {}", self.offset)?;
234        }
235        Ok(())
236    }
237}
238
239#[cfg(test)]
240mod tests {
241    use base::arithmetic::{ArithmeticBase, ArithmeticExpression, ArithmeticOperator};
242    use base::column::{Column, FunctionArgument, FunctionArguments, FunctionExpression};
243    use base::condition::ConditionBase::LiteralList;
244    use base::condition::ConditionExpression::{Base, ComparisonOp, LogicalOp};
245    use base::condition::{ConditionBase, ConditionExpression, ConditionTree};
246    use base::table::Table;
247    use base::{
248        CaseWhenExpression, ColumnOrLiteral, FieldValueExpression, ItemPlaceholder, JoinClause,
249        JoinConstraint, JoinOperator, JoinRightSide, Operator, OrderClause,
250    };
251    use base::{Literal, OrderType};
252
253    use super::*;
254}