1use std::fmt;
2use std::str;
3
4use nom::branch::alt;
5use nom::bytes::complete::{tag, tag_no_case};
6use nom::character::complete::{multispace0, multispace1};
7use nom::combinator::{map, opt};
8use nom::multi::many1;
9use nom::sequence::{delimited, preceded, tuple};
10use nom::IResult;
11
12use base::error::ParseSQLError;
13use base::{CommonParser, OrderClause};
14use dms::select::{LimitClause, SelectStatement};
15
16#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
18pub struct CompoundSelectStatement {
19 pub selects: Vec<(Option<CompoundSelectOperator>, SelectStatement)>,
20 pub order: Option<OrderClause>,
21 pub limit: Option<LimitClause>,
22}
23
24impl CompoundSelectStatement {
25 pub fn parse(i: &str) -> IResult<&str, CompoundSelectStatement, ParseSQLError<&str>> {
27 let (remaining_input, (first_select, other_selects, _, order, limit, _)) = tuple((
28 CommonParser::opt_delimited(tag("("), SelectStatement::nested_selection, tag(")")),
29 many1(Self::other_selects),
30 multispace0,
31 opt(OrderClause::parse),
32 opt(LimitClause::parse),
33 CommonParser::statement_terminator,
34 ))(i)?;
35
36 let mut selects = vec![(None, first_select)];
37 selects.extend(other_selects);
38
39 Ok((
40 remaining_input,
41 CompoundSelectStatement {
42 selects,
43 order,
44 limit,
45 },
46 ))
47 }
48
49 fn other_selects(
50 i: &str,
51 ) -> IResult<&str, (Option<CompoundSelectOperator>, SelectStatement), ParseSQLError<&str>> {
52 let (remaining_input, (_, op, _, select)) = tuple((
53 multispace0,
54 CompoundSelectOperator::parse,
55 multispace1,
56 CommonParser::opt_delimited(
57 tag("("),
58 delimited(multispace0, SelectStatement::nested_selection, multispace0),
59 tag(")"),
60 ),
61 ))(i)?;
62
63 Ok((remaining_input, (Some(op), select)))
64 }
65}
66
67impl fmt::Display for CompoundSelectStatement {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 for (ref op, ref sel) in &self.selects {
70 if op.is_some() {
71 write!(f, " {}", op.as_ref().unwrap())?;
72 }
73 write!(f, " {}", sel)?;
74 }
75 if self.order.is_some() {
76 write!(f, " {}", self.order.as_ref().unwrap())?;
77 }
78 if self.limit.is_some() {
79 write!(f, " {}", self.order.as_ref().unwrap())?;
80 }
81 Ok(())
82 }
83}
84
85#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
86pub enum CompoundSelectOperator {
87 Union,
88 DistinctUnion,
89 Intersect,
90 Except,
91}
92
93impl CompoundSelectOperator {
94 fn parse(i: &str) -> IResult<&str, CompoundSelectOperator, ParseSQLError<&str>> {
96 alt((
97 map(
98 preceded(
99 tag_no_case("UNION"),
100 opt(preceded(
101 multispace1,
102 alt((
103 map(tag_no_case("ALL"), |_| false),
104 map(tag_no_case("DISTINCT"), |_| true),
105 )),
106 )),
107 ),
108 |distinct| match distinct {
109 None => CompoundSelectOperator::DistinctUnion,
111 Some(d) => {
112 if d {
113 CompoundSelectOperator::DistinctUnion
114 } else {
115 CompoundSelectOperator::Union
116 }
117 }
118 },
119 ),
120 map(tag_no_case("INTERSECT"), |_| {
121 CompoundSelectOperator::Intersect
122 }),
123 map(tag_no_case("EXCEPT"), |_| CompoundSelectOperator::Except),
124 ))(i)
125 }
126}
127
128impl fmt::Display for CompoundSelectOperator {
129 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
130 match *self {
131 CompoundSelectOperator::Union => write!(f, "UNION"),
132 CompoundSelectOperator::DistinctUnion => write!(f, "UNION DISTINCT"),
133 CompoundSelectOperator::Intersect => write!(f, "INTERSECT"),
134 CompoundSelectOperator::Except => write!(f, "EXCEPT"),
135 }
136 }
137}