1use nom::branch::alt;
2use nom::character::complete::{digit1, line_ending, multispace0, multispace1};
3use nom::character::is_alphanumeric;
4use nom::combinator::{map, not, peek};
5use nom::{IResult, InputLength};
6use serde::Deserialize;
7use serde::Serialize;
8use std::fmt;
9use std::str;
10use std::str::FromStr;
11
12use super::column::Column;
13use super::keywords::{escape, sql_keyword};
14use nom::bytes::complete::{is_not, tag, tag_no_case, take, take_while1};
15use nom::combinator::opt;
16use nom::error::{ErrorKind, ParseError};
17use nom::multi::{fold_many0, many0};
18use nom::sequence::{delimited, pair, preceded, terminated, tuple};
19
20#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
21pub enum SqlType {
22 Bool,
23 Char(u32),
24 Varchar(u32),
25 Int,
26 UnsignedInt,
27 Smallint,
28 UnsignedSmallint,
29 Bigint,
30 UnsignedBigint,
31 Tinyint,
32 UnsignedTinyint,
33 Blob,
34 Longblob,
35 Mediumblob,
36 Tinyblob,
37 Double,
38 Float,
39 Real,
40 Tinytext,
41 Mediumtext,
42 Longtext,
43 Text,
44 Date,
45 Time,
46 DateTime(u16),
47 Timestamp(u16),
48 Binary(u16),
49 Varbinary(u16),
50 Enum(Vec<Literal>),
51 Set(Vec<Literal>),
52 Decimal(u16, u16),
53 Json,
54 Point,
55 Geometry,
56}
57
58impl fmt::Display for SqlType {
59 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
60 match *self {
61 SqlType::Bool => write!(f, "BOOL"),
62 SqlType::Char(len) => write!(f, "CHAR({})", len),
63 SqlType::Varchar(len) => write!(f, "VARCHAR({})", len),
64 SqlType::Int => write!(f, "INT"),
65 SqlType::UnsignedInt => write!(f, "INT UNSIGNED"),
66 SqlType::Smallint => write!(f, "SMALLINT"),
67 SqlType::UnsignedSmallint => write!(f, "SMALLINT UNSIGNED"),
68 SqlType::Bigint => write!(f, "BIGINT"),
69 SqlType::UnsignedBigint => write!(f, "BIGINT UNSIGNED"),
70 SqlType::Tinyint => write!(f, "TINYINT"),
71 SqlType::UnsignedTinyint => write!(f, "TINYINT UNSIGNED"),
72 SqlType::Blob => write!(f, "BLOB"),
73 SqlType::Longblob => write!(f, "LONGBLOB"),
74 SqlType::Mediumblob => write!(f, "MEDIUMBLOB"),
75 SqlType::Tinyblob => write!(f, "TINYBLOB"),
76 SqlType::Double => write!(f, "DOUBLE"),
77 SqlType::Float => write!(f, "FLOAT"),
78 SqlType::Real => write!(f, "REAL"),
79 SqlType::Tinytext => write!(f, "TINYTEXT"),
80 SqlType::Mediumtext => write!(f, "MEDIUMTEXT"),
81 SqlType::Longtext => write!(f, "LONGTEXT"),
82 SqlType::Text => write!(f, "TEXT"),
83 SqlType::Date => write!(f, "DATE"),
84 SqlType::Time => write!(f, "TIME"),
85 SqlType::DateTime(len) => {
86 if len > 0 {
87 write!(f, "DATETIME({})", len)
88 } else {
89 write!(f, "DATETIME")
90 }
91 }
92 SqlType::Timestamp(len) => {
93 if len > 0 {
94 write!(f, "TIMESTAMP({})", len)
95 } else {
96 write!(f, "TIMESTAMP")
97 }
98 }
99 SqlType::Binary(len) => write!(f, "BINARY({})", len),
100 SqlType::Varbinary(len) => write!(f, "VARBINARY({})", len),
101 SqlType::Enum(ref v) => write!(
102 f,
103 "ENUM({})",
104 v.iter()
105 .map(|v| v.to_string())
106 .collect::<Vec<String>>()
107 .join(",")
108 ),
109 SqlType::Set(ref v) => write!(
110 f,
111 "SET({})",
112 v.iter()
113 .map(|v| v.to_string())
114 .collect::<Vec<String>>()
115 .join(",")
116 ),
117 SqlType::Decimal(m, d) => write!(f, "DECIMAL({}, {})", m, d),
118 SqlType::Json => write!(f, "JSON"),
119 SqlType::Point => write!(f, "POINT"),
120 SqlType::Geometry => write!(f, "GEOMETRY"),
121 }
122 }
123}
124
125#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
126pub struct Real {
127 pub integral: i32,
128 pub fractional: i32,
129}
130
131#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
132pub enum ItemPlaceholder {
133 QuestionMark,
134 DollarNumber(i32),
135 ColonNumber(i32),
136}
137
138#[allow(clippy::to_string_trait_impl)]
139impl ToString for ItemPlaceholder {
140 fn to_string(&self) -> String {
141 match *self {
142 ItemPlaceholder::QuestionMark => "?".to_string(),
143 ItemPlaceholder::DollarNumber(ref i) => format!("${}", i),
144 ItemPlaceholder::ColonNumber(ref i) => format!(":{}", i),
145 }
146 }
147}
148
149#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
150pub enum Literal {
151 Null,
152 Integer(i64),
153 UnsignedInteger(u64),
154 FixedPoint(Real),
155 String(String),
156 Blob(Vec<u8>),
157 CurrentTime,
158 CurrentDate,
159 CurrentTimestamp,
160 Placeholder(ItemPlaceholder),
161}
162
163impl From<i64> for Literal {
164 fn from(i: i64) -> Self {
165 Literal::Integer(i)
166 }
167}
168
169impl From<u64> for Literal {
170 fn from(i: u64) -> Self {
171 Literal::UnsignedInteger(i)
172 }
173}
174
175impl From<i32> for Literal {
176 fn from(i: i32) -> Self {
177 Literal::Integer(i.into())
178 }
179}
180
181impl From<u32> for Literal {
182 fn from(i: u32) -> Self {
183 Literal::UnsignedInteger(i.into())
184 }
185}
186
187impl From<String> for Literal {
188 fn from(s: String) -> Self {
189 Literal::String(s)
190 }
191}
192
193impl<'a> From<&'a str> for Literal {
194 fn from(s: &'a str) -> Self {
195 Literal::String(String::from(s))
196 }
197}
198
199#[allow(clippy::to_string_trait_impl)]
200impl ToString for Literal {
201 fn to_string(&self) -> String {
202 match *self {
203 Literal::Null => "NULL".to_string(),
204 Literal::Integer(ref i) => format!("{}", i),
205 Literal::UnsignedInteger(ref i) => format!("{}", i),
206 Literal::FixedPoint(ref f) => format!("{}.{}", f.integral, f.fractional),
207 Literal::String(ref s) => format!("'{}'", s.replace('\'', "''")),
208 Literal::Blob(ref bv) => bv
209 .iter()
210 .map(|v| format!("{:x}", v))
211 .collect::<Vec<String>>()
212 .join(" "),
213 Literal::CurrentTime => "CURRENT_TIME".to_string(),
214 Literal::CurrentDate => "CURRENT_DATE".to_string(),
215 Literal::CurrentTimestamp => "CURRENT_TIMESTAMP".to_string(),
216 Literal::Placeholder(ref item) => item.to_string(),
217 }
218 }
219}
220
221impl Literal {
222 pub fn to_raw_string(&self) -> String {
223 match *self {
224 Literal::Integer(ref i) => format!("{}", i),
225 Literal::UnsignedInteger(ref i) => format!("{}", i),
226 Literal::FixedPoint(ref f) => format!("{}.{}", f.integral, f.fractional),
227 Literal::String(ref s) => s.clone(),
228 _ => "".to_string(),
229 }
230 }
231}
232
233#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
234pub enum TableKey {
235 PrimaryKey(Vec<Column>),
236 UniqueKey(String, Vec<Column>),
237 FulltextKey(String, Vec<Column>, Option<String>),
238 Key(String, Vec<Column>),
239 SpatialKey(String, Vec<Column>),
240 Constraint(
241 String,
242 Vec<Column>,
243 String,
244 Vec<Column>,
245 Option<ReferenceOption>,
246 Option<ReferenceOption>,
247 ),
248}
249
250#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, derive_more::Display)]
251pub enum ReferenceOption {
252 #[display(fmt = "RESTRICT")]
253 Restrict,
254 #[display(fmt = "CASCADE")]
255 Cascade,
256 #[display(fmt = "SET NULL")]
257 SetNull,
258 #[display(fmt = "NO ACTION")]
259 NoAction,
260 #[display(fmt = "SET DEFAULT")]
261 SetDefault,
262}
263
264pub fn reference_option(i: &[u8]) -> IResult<&[u8], ReferenceOption> {
265 alt((
266 map(tag_no_case("RESTRICT"), |_| ReferenceOption::Restrict),
267 map(tag_no_case("CASCADE"), |_| ReferenceOption::Cascade),
268 map(tag_no_case("SET NULL"), |_| ReferenceOption::SetNull),
269 map(tag_no_case("NO ACTION"), |_| ReferenceOption::NoAction),
270 map(tag_no_case("SET DEFAULT"), |_| ReferenceOption::SetDefault),
271 ))(i)
272}
273
274impl fmt::Display for TableKey {
275 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
276 match *self {
277 TableKey::PrimaryKey(ref columns) => {
278 write!(f, "PRIMARY KEY ")?;
279 write!(
280 f,
281 "({})",
282 columns
283 .iter()
284 .map(|c| c.to_string())
285 .collect::<Vec<_>>()
286 .join(", ")
287 )
288 }
289 TableKey::UniqueKey(ref name, ref columns) => {
290 write!(f, "UNIQUE KEY {} ", escape(name))?;
291 write!(
292 f,
293 "({})",
294 columns
295 .iter()
296 .map(|c| c.to_string())
297 .collect::<Vec<_>>()
298 .join(", ")
299 )
300 }
301 TableKey::FulltextKey(ref name, ref columns, ref parser) => {
302 write!(f, "FULLTEXT KEY {} ", escape(name))?;
303 write!(
304 f,
305 "({})",
306 columns
307 .iter()
308 .map(|c| c.to_string())
309 .collect::<Vec<_>>()
310 .join(", ")
311 )?;
312 if let Some(parser) = parser {
313 write!(f, "/*!50100 WITH PARSER `{}` */", parser)?;
314 }
315 Ok(())
316 }
317 TableKey::Key(ref name, ref columns) => {
318 write!(f, "KEY {} ", escape(name))?;
319 write!(
320 f,
321 "({})",
322 columns
323 .iter()
324 .map(|c| c.to_string())
325 .collect::<Vec<_>>()
326 .join(", ")
327 )
328 }
329 TableKey::SpatialKey(ref name, ref columns) => {
330 write!(f, "SPATIAL KEY {} ", escape(name))?;
331 write!(
332 f,
333 "({})",
334 columns
335 .iter()
336 .map(|c| c.to_string())
337 .collect::<Vec<_>>()
338 .join(", ")
339 )
340 }
341 TableKey::Constraint(
342 ref name,
343 ref columns,
344 ref table,
345 ref foreign,
346 ref on_delete,
347 ref on_update,
348 ) => {
349 write!(f, "CONSTRAINT {} FOREIGN KEY ", escape(name))?;
350 write!(
351 f,
352 "({})",
353 columns
354 .iter()
355 .map(|c| c.to_string())
356 .collect::<Vec<_>>()
357 .join(", ")
358 )?;
359 write!(f, " REFERENCES {} ", escape(table))?;
360 write!(
361 f,
362 "({})",
363 foreign
364 .iter()
365 .map(|c| c.to_string())
366 .collect::<Vec<_>>()
367 .join(", ")
368 )?;
369 if let Some(on_delete) = on_delete {
370 write!(f, " ON DELETE {}", &on_delete.to_string())?;
371 }
372 if let Some(on_update) = on_update {
373 write!(f, " ON UPDATE {}", &on_update.to_string())?;
374 }
375 Ok(())
376 }
377 }
378 }
379}
380
381#[inline]
382pub fn is_sql_identifier(chr: u8) -> bool {
383 is_alphanumeric(chr) || chr == b'_' || chr == b'@'
384}
385
386#[inline]
387pub fn is_quoted_sql_identifier(chr: u8) -> bool {
388 chr > b' '
389 && chr != b'`'
390 && chr != b'['
391 && chr != b']'
392 && chr != b','
393 && chr != b'('
394 && chr != b')'
395 && chr != 0x7f
396}
397
398#[inline]
399fn len_as_u16(len: &[u8]) -> u16 {
400 match str::from_utf8(len) {
401 Ok(s) => match u16::from_str(s) {
402 Ok(v) => v,
403 Err(e) => std::panic::panic_any(e),
404 },
405 Err(e) => std::panic::panic_any(e),
406 }
407}
408
409pub fn len_as_u32(len: &[u8]) -> u32 {
410 match str::from_utf8(len) {
411 Ok(s) => match u32::from_str(s) {
412 Ok(v) => v,
413 Err(e) => std::panic::panic_any(e),
414 },
415 Err(e) => std::panic::panic_any(e),
416 }
417}
418
419fn precision_helper(i: &[u8]) -> IResult<&[u8], (u16, Option<u16>)> {
420 let (remaining_input, (m, d)) = tuple((
421 digit1,
422 opt(preceded(tag(","), preceded(multispace0, digit1))),
423 ))(i)?;
424
425 Ok((remaining_input, (len_as_u16(m), d.map(len_as_u16))))
426}
427
428pub fn precision(i: &[u8]) -> IResult<&[u8], (u16, Option<u16>)> {
429 delimited(tag("("), precision_helper, tag(")"))(i)
430}
431
432fn opt_signed(i: &[u8]) -> IResult<&[u8], Option<&[u8]>> {
433 opt(alt((tag_no_case("unsigned"), tag_no_case("signed"))))(i)
434}
435
436fn opt_unsigned(i: &[u8]) -> IResult<&[u8], Option<&[u8]>> {
437 opt(tag_no_case("unsigned"))(i)
438}
439
440fn delim_digit(i: &[u8]) -> IResult<&[u8], &[u8]> {
441 delimited(tag("("), digit1, tag(")"))(i)
442}
443
444fn tiny_int(i: &[u8]) -> IResult<&[u8], SqlType> {
447 let (remaining_input, (_, _len, _, signed)) = tuple((
448 tag_no_case("tinyint"),
449 opt(delim_digit),
450 multispace0,
451 opt_signed,
452 ))(i)?;
453
454 match signed {
455 Some(sign) => {
456 if str::from_utf8(sign)
457 .unwrap()
458 .eq_ignore_ascii_case("unsigned")
459 {
460 Ok((remaining_input, SqlType::UnsignedTinyint))
461 } else {
462 Ok((remaining_input, SqlType::Tinyint))
463 }
464 }
465 None => Ok((remaining_input, SqlType::Tinyint)),
466 }
467}
468
469fn big_int(i: &[u8]) -> IResult<&[u8], SqlType> {
472 let (remaining_input, (_, _len, _, signed)) = tuple((
473 tag_no_case("bigint"),
474 opt(delim_digit),
475 multispace0,
476 opt_signed,
477 ))(i)?;
478
479 match signed {
480 Some(sign) => {
481 if str::from_utf8(sign)
482 .unwrap()
483 .eq_ignore_ascii_case("unsigned")
484 {
485 Ok((remaining_input, SqlType::UnsignedBigint))
486 } else {
487 Ok((remaining_input, SqlType::Bigint))
488 }
489 }
490 None => Ok((remaining_input, SqlType::Bigint)),
491 }
492}
493
494fn sql_int_type(i: &[u8]) -> IResult<&[u8], SqlType> {
497 let (remaining_input, (_, _len, _, signed)) = tuple((
498 alt((tag_no_case("integer"), tag_no_case("int"))),
499 opt(delim_digit),
500 multispace0,
501 opt_signed,
502 ))(i)?;
503
504 match signed {
505 Some(sign) => {
506 if str::from_utf8(sign)
507 .unwrap()
508 .eq_ignore_ascii_case("unsigned")
509 {
510 Ok((remaining_input, SqlType::UnsignedInt))
511 } else {
512 Ok((remaining_input, SqlType::Int))
513 }
514 }
515 None => Ok((remaining_input, SqlType::Int)),
516 }
517}
518fn small_int_type(i: &[u8]) -> IResult<&[u8], SqlType> {
519 let (remaining_input, (_, _len, _, signed)) = tuple((
520 tag_no_case("smallint"),
521 opt(delim_digit),
522 multispace0,
523 opt_signed,
524 ))(i)?;
525
526 match signed {
527 Some(sign) => {
528 if str::from_utf8(sign)
529 .unwrap()
530 .eq_ignore_ascii_case("unsigned")
531 {
532 Ok((remaining_input, SqlType::UnsignedSmallint))
533 } else {
534 Ok((remaining_input, SqlType::Smallint))
535 }
536 }
537 None => Ok((remaining_input, SqlType::Smallint)),
538 }
539}
540
541fn decimal_or_numeric(i: &[u8]) -> IResult<&[u8], SqlType> {
545 let (remaining_input, (_, precision, _, _unsigned)) = tuple((
546 alt((tag_no_case("decimal"), tag_no_case("numeric"))),
547 opt(precision),
548 multispace0,
549 opt_unsigned,
550 ))(i)?;
551
552 match precision {
553 None => Ok((remaining_input, SqlType::Decimal(32, 0))),
554 Some((m, None)) => Ok((remaining_input, SqlType::Decimal(m, 0))),
555 Some((m, Some(d))) => Ok((remaining_input, SqlType::Decimal(m, d))),
556 }
557}
558
559fn type_identifier_first_half(i: &[u8]) -> IResult<&[u8], SqlType> {
560 alt((
561 tiny_int,
562 big_int,
563 sql_int_type,
564 small_int_type,
565 map(tag_no_case("bool"), |_| SqlType::Bool),
566 map(
567 tuple((
568 tag_no_case("char"),
569 delim_digit,
570 multispace0,
571 opt(tag_no_case("binary")),
572 )),
573 |t| SqlType::Char(len_as_u32(t.1)),
574 ),
575 map(preceded(tag_no_case("datetime"), opt(delim_digit)), |fsp| {
576 SqlType::DateTime(match fsp {
577 Some(fsp) => len_as_u16(fsp),
578 None => 0_u16,
579 })
580 }),
581 map(tag_no_case("date"), |_| SqlType::Date),
582 map(
583 preceded(tag_no_case("timestamp"), opt(delim_digit)),
584 |fsp| {
585 SqlType::Timestamp(match fsp {
586 Some(fsp) => len_as_u16(fsp),
587 None => 0_u16,
588 })
589 },
590 ),
591 map(tag_no_case("time"), |_| SqlType::Time),
592 map(
593 tuple((tag_no_case("double"), multispace0, opt_unsigned)),
594 |_| SqlType::Double,
595 ),
596 map(
597 terminated(
598 preceded(
599 tag_no_case("enum"),
600 delimited(tag("("), value_list, tag(")")),
601 ),
602 multispace0,
603 ),
604 SqlType::Enum,
605 ),
606 map(
607 terminated(
608 preceded(
609 tag_no_case("set"),
610 delimited(tag("("), value_list, tag(")")),
611 ),
612 multispace0,
613 ),
614 SqlType::Set,
615 ),
616 map(
617 tuple((
618 tag_no_case("float"),
619 multispace0,
620 opt(precision),
621 multispace0,
622 opt_unsigned,
623 )),
624 |_| SqlType::Float,
625 ),
626 map(
627 tuple((tag_no_case("real"), multispace0, opt_unsigned)),
628 |_| SqlType::Real,
629 ),
630 map(tag_no_case("text"), |_| SqlType::Text),
631 map(
632 tuple((
633 tag_no_case("varchar"),
634 delim_digit,
635 multispace0,
636 opt(tag_no_case("binary")),
637 )),
638 |t| SqlType::Varchar(len_as_u32(t.1)),
639 ),
640 map(tag_no_case("json"), |_| SqlType::Json),
641 map(tag_no_case("point"), |_| SqlType::Point),
642 map(tag_no_case("geometry"), |_| SqlType::Geometry),
643 decimal_or_numeric,
644 ))(i)
645}
646
647fn type_identifier_second_half(i: &[u8]) -> IResult<&[u8], SqlType> {
648 alt((
649 map(
650 tuple((tag_no_case("binary"), delim_digit, multispace0)),
651 |t| SqlType::Binary(len_as_u16(t.1)),
652 ),
653 map(tag_no_case("blob"), |_| SqlType::Blob),
654 map(tag_no_case("longblob"), |_| SqlType::Longblob),
655 map(tag_no_case("mediumblob"), |_| SqlType::Mediumblob),
656 map(tag_no_case("mediumtext"), |_| SqlType::Mediumtext),
657 map(tag_no_case("longtext"), |_| SqlType::Longtext),
658 map(tag_no_case("tinyblob"), |_| SqlType::Tinyblob),
659 map(tag_no_case("tinytext"), |_| SqlType::Tinytext),
660 map(
661 tuple((tag_no_case("varbinary"), delim_digit, multispace0)),
662 |t| SqlType::Varbinary(len_as_u16(t.1)),
663 ),
664 ))(i)
665}
666
667pub fn type_identifier(i: &[u8]) -> IResult<&[u8], SqlType> {
669 alt((type_identifier_first_half, type_identifier_second_half))(i)
670}
671
672pub fn column_identifier_no_alias(i: &[u8]) -> IResult<&[u8], Column> {
674 let (remaining_input, (column, len)) =
675 tuple((sql_identifier, opt(delimited(tag("("), digit1, tag(")")))))(i)?;
676 Ok((
677 remaining_input,
678 Column {
679 name: str::from_utf8(column).unwrap().to_string(),
680 query: None,
681 len: len.map(|l| u32::from_str(str::from_utf8(l).unwrap()).unwrap()),
682 },
683 ))
684}
685pub fn column_identifier_query(i: &[u8]) -> IResult<&[u8], Column> {
686 let (remaining_input, query) =
687 delimited(tag("("), take_until_unbalanced('(', ')'), tag(")"))(i)?;
688 Ok((
689 remaining_input,
690 Column {
691 name: "".to_string(),
692 query: Some(str::from_utf8(query).unwrap().to_string()),
693 len: None,
694 },
695 ))
696}
697
698pub fn sql_identifier(i: &[u8]) -> IResult<&[u8], &[u8]> {
700 alt((
701 preceded(not(peek(sql_keyword)), take_while1(is_sql_identifier)),
702 delimited(tag("`"), take_while1(is_quoted_sql_identifier), tag("`")),
703 delimited(tag("["), take_while1(is_quoted_sql_identifier), tag("]")),
704 ))(i)
705}
706pub fn take_until_unbalanced(
707 opening_bracket: char,
708 closing_bracket: char,
709) -> impl Fn(&[u8]) -> IResult<&[u8], &[u8]> {
710 move |i: &[u8]| {
711 let mut index = 0;
712 let mut bracket_counter = 0;
713 while index < i.len() {
714 match i[index] {
715 b'\\' => {
716 index += 1;
717 }
718 c if c == opening_bracket as u8 => {
719 bracket_counter += 1;
720 }
721 c if c == closing_bracket as u8 => {
722 bracket_counter -= 1;
723 }
724 _ => {}
725 };
726 if bracket_counter == -1 {
727 return Ok((&i[index..], &i[0..index]));
728 };
729 index += 1;
730 }
731
732 if bracket_counter == 0 {
733 Ok(("".as_bytes(), i))
734 } else {
735 Err(nom::Err::Error(nom::error::Error::from_error_kind(
736 i,
737 ErrorKind::TakeUntil,
738 )))
739 }
740 }
741}
742
743pub(crate) fn eof<I: Copy + InputLength, E: ParseError<I>>(input: I) -> IResult<I, I, E> {
744 if input.input_len() == 0 {
745 Ok((input, input))
746 } else {
747 Err(nom::Err::Error(E::from_error_kind(input, ErrorKind::Eof)))
748 }
749}
750
751pub fn statement_terminator(i: &[u8]) -> IResult<&[u8], ()> {
753 let (remaining_input, _) =
754 delimited(multispace0, alt((tag(";"), line_ending, eof)), multispace0)(i)?;
755
756 Ok((remaining_input, ()))
757}
758
759pub(crate) fn ws_sep_comma(i: &[u8]) -> IResult<&[u8], &[u8]> {
760 delimited(multispace0, tag(","), multispace0)(i)
761}
762
763pub(crate) fn ws_sep_equals<'a, I>(i: I) -> IResult<I, I>
764where
765 I: nom::InputTakeAtPosition + nom::InputTake + nom::Compare<&'a str>,
766 <I as nom::InputTakeAtPosition>::Item: nom::AsChar + Clone,
768 {
770 delimited(multispace0, tag("="), multispace0)(i)
771}
772
773pub fn integer_literal(i: &[u8]) -> IResult<&[u8], Literal> {
775 map(pair(opt(tag("-")), digit1), |tup| {
776 let mut intval = i64::from_str(str::from_utf8(tup.1).unwrap()).unwrap();
777 if (tup.0).is_some() {
778 intval *= -1;
779 }
780 Literal::Integer(intval)
781 })(i)
782}
783
784fn unpack(v: &[u8]) -> i32 {
785 i32::from_str(str::from_utf8(v).unwrap()).unwrap()
786}
787
788pub fn float_literal(i: &[u8]) -> IResult<&[u8], Literal> {
790 map(tuple((opt(tag("-")), digit1, tag("."), digit1)), |tup| {
791 Literal::FixedPoint(Real {
792 integral: if (tup.0).is_some() {
793 -unpack(tup.1)
794 } else {
795 unpack(tup.1)
796 },
797 fractional: unpack(tup.3),
798 })
799 })(i)
800}
801
802fn raw_string_quoted(input: &[u8], is_single_quote: bool) -> IResult<&[u8], Vec<u8>> {
804 let quote_slice: &[u8] = if is_single_quote { b"\'" } else { b"\"" };
806 let double_quote_slice: &[u8] = if is_single_quote { b"\'\'" } else { b"\"\"" };
807 let backslash_quote: &[u8] = if is_single_quote { b"\\\'" } else { b"\\\"" };
808 delimited(
809 tag(quote_slice),
810 fold_many0(
811 alt((
812 is_not(backslash_quote),
813 map(tag(double_quote_slice), |_| -> &[u8] {
814 if is_single_quote {
815 b"\'"
816 } else {
817 b"\""
818 }
819 }),
820 map(tag("\\\\"), |_| &b"\\"[..]),
821 map(tag("\\b"), |_| &b"\x7f"[..]),
822 map(tag("\\r"), |_| &b"\r"[..]),
823 map(tag("\\n"), |_| &b"\n"[..]),
824 map(tag("\\t"), |_| &b"\t"[..]),
825 map(tag("\\0"), |_| &b"\0"[..]),
826 map(tag("\\Z"), |_| &b"\x1A"[..]),
827 preceded(tag("\\"), take(1usize)),
828 )),
829 Vec::new,
830 |mut acc: Vec<u8>, bytes: &[u8]| {
831 acc.extend(bytes);
832 acc
833 },
834 ),
835 tag(quote_slice),
836 )(input)
837}
838
839fn raw_string_single_quoted(i: &[u8]) -> IResult<&[u8], Vec<u8>> {
840 raw_string_quoted(i, true)
841}
842
843fn raw_string_double_quoted(i: &[u8]) -> IResult<&[u8], Vec<u8>> {
844 raw_string_quoted(i, false)
845}
846
847pub fn string_literal(i: &[u8]) -> IResult<&[u8], Literal> {
848 map(
849 alt((raw_string_single_quoted, raw_string_double_quoted)),
850 |bytes| match String::from_utf8(bytes) {
851 Ok(s) => Literal::String(s),
852 Err(err) => Literal::Blob(err.into_bytes()),
853 },
854 )(i)
855}
856
857pub fn literal(i: &[u8]) -> IResult<&[u8], Literal> {
859 alt((
860 float_literal,
861 integer_literal,
862 string_literal,
863 map(tag_no_case("null"), |_| Literal::Null),
864 map(tag_no_case("current_timestamp"), |_| {
865 Literal::CurrentTimestamp
866 }),
867 map(tag_no_case("current_date"), |_| Literal::CurrentDate),
868 map(tag_no_case("current_time"), |_| Literal::CurrentTime),
869 map(tag("?"), |_| {
870 Literal::Placeholder(ItemPlaceholder::QuestionMark)
871 }),
872 map(preceded(tag(":"), digit1), |num| {
873 let value = i32::from_str(str::from_utf8(num).unwrap()).unwrap();
874 Literal::Placeholder(ItemPlaceholder::ColonNumber(value))
875 }),
876 map(preceded(tag("$"), digit1), |num| {
877 let value = i32::from_str(str::from_utf8(num).unwrap()).unwrap();
878 Literal::Placeholder(ItemPlaceholder::DollarNumber(value))
879 }),
880 ))(i)
881}
882
883pub fn value_list(i: &[u8]) -> IResult<&[u8], Vec<Literal>> {
885 many0(delimited(multispace0, literal, opt(ws_sep_comma)))(i)
886}
887
888pub fn schema_table_reference(i: &[u8]) -> IResult<&[u8], String> {
890 map(sql_identifier, |tup| {
891 String::from(str::from_utf8(tup).unwrap())
892 })(i)
893}
894
895pub fn parse_comment(i: &[u8]) -> IResult<&[u8], Literal> {
897 preceded(
898 delimited(multispace0, tag_no_case("comment"), multispace1),
899 string_literal,
900 )(i)
901}