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 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 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 fn raw_string_quoted(
63 input: &str,
64 is_single_quote: bool,
65 ) -> IResult<&str, String, ParseSQLError<&str>> {
66 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"), 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 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 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}