sqlparser_mysql/base/
literal.rs

1use std::fmt;
2use std::fmt::{Display, Formatter};
3use std::str::FromStr;
4
5use nom::branch::alt;
6use nom::bytes::complete::{is_not, tag, tag_no_case, take};
7use nom::character::complete::{digit1, multispace0};
8use nom::combinator::{map, opt};
9use nom::multi::{fold_many0, many0};
10use nom::sequence::{delimited, pair, preceded, tuple};
11use nom::IResult;
12
13use base::error::ParseSQLError;
14use base::{CommonParser, ItemPlaceholder};
15
16#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
17pub enum Literal {
18    Bool(bool),
19    Null,
20    Integer(i64),
21    UnsignedInteger(u64),
22    FixedPoint(Real),
23    String(String),
24    Blob(Vec<u8>),
25    CurrentTime,
26    CurrentDate,
27    CurrentTimestamp,
28    Placeholder(ItemPlaceholder),
29}
30
31impl Literal {
32    // Integer literal value
33    pub fn integer_literal(i: &str) -> IResult<&str, Literal, ParseSQLError<&str>> {
34        map(pair(opt(tag("-")), digit1), |tup| {
35            let mut intval = i64::from_str(tup.1).unwrap();
36            if (tup.0).is_some() {
37                intval *= -1;
38            }
39            Literal::Integer(intval)
40        })(i)
41    }
42
43    fn unpack(v: &str) -> i32 {
44        i32::from_str(v).unwrap()
45    }
46
47    // Floating point literal value
48    pub fn float_literal(i: &str) -> IResult<&str, Literal, ParseSQLError<&str>> {
49        map(tuple((opt(tag("-")), digit1, tag("."), digit1)), |tup| {
50            Literal::FixedPoint(Real {
51                integral: if (tup.0).is_some() {
52                    -Self::unpack(tup.1)
53                } else {
54                    Self::unpack(tup.1)
55                },
56                fractional: Self::unpack(tup.3),
57            })
58        })(i)
59    }
60
61    /// String literal value
62    fn raw_string_quoted(
63        input: &str,
64        is_single_quote: bool,
65    ) -> IResult<&str, String, ParseSQLError<&str>> {
66        // Adjusted to work with &str
67        let quote_char = if is_single_quote { '\'' } else { '"' };
68        let quote_str = if is_single_quote { "\'" } else { "\"" };
69        let double_quote_str = if is_single_quote { "\'\'" } else { "\"\"" };
70        let backslash_quote = if is_single_quote { "\\\'" } else { "\\\"" };
71
72        delimited(
73            tag(quote_str),
74            fold_many0(
75                alt((
76                    is_not(backslash_quote),
77                    map(tag(double_quote_str), |_| {
78                        if is_single_quote {
79                            "\'"
80                        } else {
81                            "\""
82                        }
83                    }),
84                    map(tag("\\\\"), |_| "\\"),
85                    map(tag("\\b"), |_| "\x7F"), // 注意:\x7f 是 DEL,\x08 是退格
86                    map(tag("\\r"), |_| "\r"),
87                    map(tag("\\n"), |_| "\n"),
88                    map(tag("\\t"), |_| "\t"),
89                    map(tag("\\0"), |_| "\0"),
90                    map(tag("\\Z"), |_| "\x1A"),
91                    preceded(tag("\\"), take(1usize)),
92                )),
93                String::new,
94                |mut acc: String, bytes: &str| {
95                    acc.push_str(bytes);
96                    acc
97                },
98            ),
99            tag(quote_str),
100        )(input)
101    }
102
103    fn raw_string_single_quoted(i: &str) -> IResult<&str, String, ParseSQLError<&str>> {
104        Self::raw_string_quoted(i, true)
105    }
106
107    fn raw_string_double_quoted(i: &str) -> IResult<&str, String, ParseSQLError<&str>> {
108        Self::raw_string_quoted(i, false)
109    }
110
111    pub fn string_literal(i: &str) -> IResult<&str, Literal, ParseSQLError<&str>> {
112        map(
113            alt((
114                Self::raw_string_single_quoted,
115                Self::raw_string_double_quoted,
116            )),
117            Literal::String,
118        )(i)
119    }
120
121    // Any literal value.
122    pub fn parse(i: &str) -> IResult<&str, Literal, ParseSQLError<&str>> {
123        alt((
124            Self::float_literal,
125            Self::integer_literal,
126            Self::string_literal,
127            map(tag_no_case("NULL"), |_| Literal::Null),
128            map(tag_no_case("CURRENT_TIMESTAMP"), |_| {
129                Literal::CurrentTimestamp
130            }),
131            map(tag_no_case("CURRENT_DATE"), |_| Literal::CurrentDate),
132            map(tag_no_case("CURRENT_TIME"), |_| Literal::CurrentTime),
133            map(tag("?"), |_| {
134                Literal::Placeholder(ItemPlaceholder::QuestionMark)
135            }),
136            map(preceded(tag(":"), digit1), |num| {
137                let value = i32::from_str(num).unwrap();
138                Literal::Placeholder(ItemPlaceholder::ColonNumber(value))
139            }),
140            map(preceded(tag("$"), digit1), |num| {
141                let value = i32::from_str(num).unwrap();
142                Literal::Placeholder(ItemPlaceholder::DollarNumber(value))
143            }),
144        ))(i)
145    }
146
147    // Parse a list of values (e.g., for INSERT syntax).
148    pub fn value_list(i: &str) -> IResult<&str, Vec<Literal>, ParseSQLError<&str>> {
149        many0(delimited(
150            multispace0,
151            Literal::parse,
152            opt(CommonParser::ws_sep_comma),
153        ))(i)
154    }
155}
156
157impl From<i64> for Literal {
158    fn from(i: i64) -> Self {
159        Literal::Integer(i)
160    }
161}
162
163impl From<u64> for Literal {
164    fn from(i: u64) -> Self {
165        Literal::UnsignedInteger(i)
166    }
167}
168
169impl From<i32> for Literal {
170    fn from(i: i32) -> Self {
171        Literal::Integer(i.into())
172    }
173}
174
175impl From<u32> for Literal {
176    fn from(i: u32) -> Self {
177        Literal::UnsignedInteger(i.into())
178    }
179}
180
181impl From<String> for Literal {
182    fn from(s: String) -> Self {
183        Literal::String(s)
184    }
185}
186
187impl<'a> From<&'a str> for Literal {
188    fn from(s: &'a str) -> Self {
189        Literal::String(String::from(s))
190    }
191}
192
193impl Display for Literal {
194    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
195        match *self {
196            Literal::Null => write!(f, "NULL"),
197            Literal::Bool(ref value) => {
198                if *value {
199                    write!(f, "TRUE")
200                } else {
201                    write!(f, "FALSE")
202                }
203            }
204            Literal::Integer(ref i) => write!(f, "{}", i),
205            Literal::UnsignedInteger(ref i) => write!(f, "{}", i),
206            Literal::FixedPoint(ref fp) => write!(f, "{}.{}", fp.integral, fp.fractional),
207            Literal::String(ref s) => write!(f, "'{}'", s.replace('\'', "''")),
208            Literal::Blob(ref bv) => {
209                let val = bv
210                    .iter()
211                    .map(|v| format!("{:x}", v))
212                    .collect::<Vec<String>>()
213                    .join(" ")
214                    .to_string();
215                write!(f, "{}", val)
216            }
217            Literal::CurrentTime => write!(f, "CURRENT_TIME"),
218            Literal::CurrentDate => write!(f, "CURRENT_DATE"),
219            Literal::CurrentTimestamp => write!(f, "CURRENT_TIMESTAMP"),
220            Literal::Placeholder(ref item) => write!(f, "{}", item),
221        }
222    }
223}
224
225#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
226pub struct LiteralExpression {
227    pub value: Literal,
228    pub alias: Option<String>,
229}
230
231impl LiteralExpression {
232    pub fn parse(i: &str) -> IResult<&str, LiteralExpression, ParseSQLError<&str>> {
233        map(
234            pair(
235                CommonParser::opt_delimited(tag("("), Literal::parse, tag(")")),
236                opt(CommonParser::as_alias),
237            ),
238            |p| LiteralExpression {
239                value: p.0,
240                alias: (p.1).map(|a| a.to_string()),
241            },
242        )(i)
243    }
244}
245
246impl From<Literal> for LiteralExpression {
247    fn from(l: Literal) -> Self {
248        LiteralExpression {
249            value: l,
250            alias: None,
251        }
252    }
253}
254
255impl fmt::Display for LiteralExpression {
256    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
257        match self.alias {
258            Some(ref alias) => write!(f, "{} AS {}", self.value, alias),
259            None => write!(f, "{}", self.value),
260        }
261    }
262}
263
264#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
265pub struct Real {
266    pub integral: i32,
267    pub fractional: i32,
268}
269
270impl Display for Real {
271    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
272        write!(f, "{}.{}", self.integral, self.fractional)
273    }
274}
275
276#[cfg(test)]
277mod tests {
278    use base::Literal;
279
280    #[test]
281    #[allow(clippy::redundant_slicing)]
282    fn literal_string_single_backslash_escape() {
283        let all_escaped = r#"\0\'\"\b\n\r\t\Z\\\%\_"#;
284        for quote in ["'", "\""].iter() {
285            let quoted = &[quote, &all_escaped[..], quote].concat();
286            let res = Literal::string_literal(quoted);
287            let expected = Literal::String("\0\'\"\x7F\n\r\t\x1a\\%_".to_string());
288
289            assert!(res.is_ok());
290            assert_eq!(res.unwrap().1, expected);
291        }
292    }
293
294    #[test]
295    fn literal_string_single_quote() {
296        let res = Literal::string_literal("'a''b'");
297        let expected = Literal::String("a'b".to_string());
298
299        assert!(res.is_ok());
300        assert_eq!(res.unwrap().1, expected);
301    }
302
303    #[test]
304    fn literal_string_double_quote() {
305        let res = Literal::string_literal(r#""a""b""#);
306        let expected = Literal::String(r#"a"b"#.to_string());
307
308        assert!(res.is_ok());
309        assert_eq!(res.unwrap().1, expected);
310    }
311}