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 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 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#[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}