sqlparser_mysql/dms/
compound_select.rs

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// TODO 用于 create 语句的 select
17#[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    // Parse compound selection
26    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    // Parse compound operator
95    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                    // DISTINCT is the default in both MySQL and SQLite
110                    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}