1use nom::IResult;
2use nom::branch::alt;
3use nom::character::complete::{digit1, line_ending, multispace0, multispace1};
4use nom::combinator::{map, not, peek, recognize};
5use nom::{AsChar, Parser};
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};
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 CheckConstraint(String, String),
250}
251
252#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, derive_more::Display)]
253pub enum ReferenceOption {
254 #[display("RESTRICT")]
255 Restrict,
256 #[display("CASCADE")]
257 Cascade,
258 #[display("SET NULL")]
259 SetNull,
260 #[display("NO ACTION")]
261 NoAction,
262 #[display("SET DEFAULT")]
263 SetDefault,
264}
265
266pub fn reference_option(i: &[u8]) -> IResult<&[u8], ReferenceOption> {
267 alt((
268 map(tag_no_case("RESTRICT"), |_| ReferenceOption::Restrict),
269 map(tag_no_case("CASCADE"), |_| ReferenceOption::Cascade),
270 map(tag_no_case("SET NULL"), |_| ReferenceOption::SetNull),
271 map(tag_no_case("NO ACTION"), |_| ReferenceOption::NoAction),
272 map(tag_no_case("SET DEFAULT"), |_| ReferenceOption::SetDefault),
273 ))
274 .parse(i)
275}
276
277impl fmt::Display for TableKey {
278 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
279 match *self {
280 TableKey::PrimaryKey(ref columns) => {
281 write!(f, "PRIMARY KEY ")?;
282 write!(
283 f,
284 "({})",
285 columns
286 .iter()
287 .map(|c| c.to_string())
288 .collect::<Vec<_>>()
289 .join(", ")
290 )
291 }
292 TableKey::UniqueKey(ref name, ref columns) => {
293 write!(f, "UNIQUE KEY {} ", escape(name))?;
294 write!(
295 f,
296 "({})",
297 columns
298 .iter()
299 .map(|c| c.to_string())
300 .collect::<Vec<_>>()
301 .join(", ")
302 )
303 }
304 TableKey::FulltextKey(ref name, ref columns, ref parser) => {
305 write!(f, "FULLTEXT KEY {} ", escape(name))?;
306 write!(
307 f,
308 "({})",
309 columns
310 .iter()
311 .map(|c| c.to_string())
312 .collect::<Vec<_>>()
313 .join(", ")
314 )?;
315 if let Some(parser) = parser {
316 write!(f, "/*!50100 WITH PARSER `{}` */", parser)?;
317 }
318 Ok(())
319 }
320 TableKey::Key(ref name, ref columns) => {
321 write!(f, "KEY {} ", escape(name))?;
322 write!(
323 f,
324 "({})",
325 columns
326 .iter()
327 .map(|c| c.to_string())
328 .collect::<Vec<_>>()
329 .join(", ")
330 )
331 }
332 TableKey::SpatialKey(ref name, ref columns) => {
333 write!(f, "SPATIAL KEY {} ", escape(name))?;
334 write!(
335 f,
336 "({})",
337 columns
338 .iter()
339 .map(|c| c.to_string())
340 .collect::<Vec<_>>()
341 .join(", ")
342 )
343 }
344 TableKey::CheckConstraint(ref name, ref clause) => {
345 write!(f, "CONSTRAINT {} CHECK {}", escape(name), clause)
346 }
347 TableKey::Constraint(
348 ref name,
349 ref columns,
350 ref table,
351 ref foreign,
352 ref on_delete,
353 ref on_update,
354 ) => {
355 write!(f, "CONSTRAINT {} FOREIGN KEY ", escape(name))?;
356 write!(
357 f,
358 "({})",
359 columns
360 .iter()
361 .map(|c| c.to_string())
362 .collect::<Vec<_>>()
363 .join(", ")
364 )?;
365 write!(f, " REFERENCES {} ", escape(table))?;
366 write!(
367 f,
368 "({})",
369 foreign
370 .iter()
371 .map(|c| c.to_string())
372 .collect::<Vec<_>>()
373 .join(", ")
374 )?;
375 if let Some(on_delete) = on_delete {
376 write!(f, " ON DELETE {}", &on_delete.to_string())?;
377 }
378 if let Some(on_update) = on_update {
379 write!(f, " ON UPDATE {}", &on_update.to_string())?;
380 }
381 Ok(())
382 }
383 }
384 }
385}
386
387#[inline]
388pub fn is_sql_identifier(chr: u8) -> bool {
389 AsChar::is_alphanum(chr) || chr == b'_' || chr == b'@'
390}
391
392#[inline]
393pub fn is_quoted_sql_identifier(chr: u8) -> bool {
394 chr > b' '
395 && chr != b'`'
396 && chr != b'['
397 && chr != b']'
398 && chr != b','
399 && chr != b'('
400 && chr != b')'
401 && chr != 0x7f
402}
403
404#[inline]
405fn len_as_u16(len: &[u8]) -> u16 {
406 match str::from_utf8(len) {
407 Ok(s) => match u16::from_str(s) {
408 Ok(v) => v,
409 Err(e) => std::panic::panic_any(e),
410 },
411 Err(e) => std::panic::panic_any(e),
412 }
413}
414
415pub fn len_as_u32(len: &[u8]) -> u32 {
416 match str::from_utf8(len) {
417 Ok(s) => match u32::from_str(s) {
418 Ok(v) => v,
419 Err(e) => std::panic::panic_any(e),
420 },
421 Err(e) => std::panic::panic_any(e),
422 }
423}
424
425fn precision_helper(i: &[u8]) -> IResult<&[u8], (u16, Option<u16>)> {
426 let (remaining_input, (m, d)) = (
427 digit1,
428 opt(preceded(tag(","), preceded(multispace0, digit1))),
429 )
430 .parse(i)?;
431
432 Ok((remaining_input, (len_as_u16(m), d.map(len_as_u16))))
433}
434
435pub fn precision(i: &[u8]) -> IResult<&[u8], (u16, Option<u16>)> {
436 delimited(tag("("), precision_helper, tag(")")).parse(i)
437}
438
439fn opt_signed(i: &[u8]) -> IResult<&[u8], Option<&[u8]>> {
440 opt(alt((tag_no_case("unsigned"), tag_no_case("signed")))).parse(i)
441}
442
443fn opt_unsigned(i: &[u8]) -> IResult<&[u8], Option<&[u8]>> {
444 opt(tag_no_case("unsigned")).parse(i)
445}
446
447fn delim_digit(i: &[u8]) -> IResult<&[u8], &[u8]> {
448 delimited(tag("("), digit1, tag(")")).parse(i)
449}
450
451fn tiny_int(i: &[u8]) -> IResult<&[u8], SqlType> {
454 let (remaining_input, (_, _len, _, signed)) = (
455 tag_no_case("tinyint"),
456 opt(delim_digit),
457 multispace0,
458 opt_signed,
459 )
460 .parse(i)?;
461
462 match signed {
463 Some(sign) => {
464 if str::from_utf8(sign)
465 .unwrap()
466 .eq_ignore_ascii_case("unsigned")
467 {
468 Ok((remaining_input, SqlType::UnsignedTinyint))
469 } else {
470 Ok((remaining_input, SqlType::Tinyint))
471 }
472 }
473 None => Ok((remaining_input, SqlType::Tinyint)),
474 }
475}
476
477fn big_int(i: &[u8]) -> IResult<&[u8], SqlType> {
480 let (remaining_input, (_, _len, _, signed)) = (
481 tag_no_case("bigint"),
482 opt(delim_digit),
483 multispace0,
484 opt_signed,
485 )
486 .parse(i)?;
487
488 match signed {
489 Some(sign) => {
490 if str::from_utf8(sign)
491 .unwrap()
492 .eq_ignore_ascii_case("unsigned")
493 {
494 Ok((remaining_input, SqlType::UnsignedBigint))
495 } else {
496 Ok((remaining_input, SqlType::Bigint))
497 }
498 }
499 None => Ok((remaining_input, SqlType::Bigint)),
500 }
501}
502
503fn sql_int_type(i: &[u8]) -> IResult<&[u8], SqlType> {
506 let (remaining_input, (_, _len, _, signed)) = (
507 alt((tag_no_case("integer"), tag_no_case("int"))),
508 opt(delim_digit),
509 multispace0,
510 opt_signed,
511 )
512 .parse(i)?;
513
514 match signed {
515 Some(sign) => {
516 if str::from_utf8(sign)
517 .unwrap()
518 .eq_ignore_ascii_case("unsigned")
519 {
520 Ok((remaining_input, SqlType::UnsignedInt))
521 } else {
522 Ok((remaining_input, SqlType::Int))
523 }
524 }
525 None => Ok((remaining_input, SqlType::Int)),
526 }
527}
528fn small_int_type(i: &[u8]) -> IResult<&[u8], SqlType> {
529 let (remaining_input, (_, _len, _, signed)) = (
530 tag_no_case("smallint"),
531 opt(delim_digit),
532 multispace0,
533 opt_signed,
534 )
535 .parse(i)?;
536
537 match signed {
538 Some(sign) => {
539 if str::from_utf8(sign)
540 .unwrap()
541 .eq_ignore_ascii_case("unsigned")
542 {
543 Ok((remaining_input, SqlType::UnsignedSmallint))
544 } else {
545 Ok((remaining_input, SqlType::Smallint))
546 }
547 }
548 None => Ok((remaining_input, SqlType::Smallint)),
549 }
550}
551
552fn decimal_or_numeric(i: &[u8]) -> IResult<&[u8], SqlType> {
556 let (remaining_input, (_, precision, _, _unsigned)) = (
557 alt((tag_no_case("decimal"), tag_no_case("numeric"))),
558 opt(precision),
559 multispace0,
560 opt_unsigned,
561 )
562 .parse(i)?;
563
564 match precision {
565 None => Ok((remaining_input, SqlType::Decimal(32, 0))),
566 Some((m, None)) => Ok((remaining_input, SqlType::Decimal(m, 0))),
567 Some((m, Some(d))) => Ok((remaining_input, SqlType::Decimal(m, d))),
568 }
569}
570
571fn type_identifier_first_half(i: &[u8]) -> IResult<&[u8], SqlType> {
572 alt((
573 tiny_int,
574 big_int,
575 sql_int_type,
576 small_int_type,
577 map(tag_no_case("bool"), |_| SqlType::Bool),
578 map(
579 (
580 tag_no_case("char"),
581 delim_digit,
582 multispace0,
583 opt(tag_no_case("binary")),
584 ),
585 |t| SqlType::Char(len_as_u32(t.1)),
586 ),
587 map(preceded(tag_no_case("datetime"), opt(delim_digit)), |fsp| {
588 SqlType::DateTime(match fsp {
589 Some(fsp) => len_as_u16(fsp),
590 None => 0_u16,
591 })
592 }),
593 map(tag_no_case("date"), |_| SqlType::Date),
594 map(
595 preceded(tag_no_case("timestamp"), opt(delim_digit)),
596 |fsp| {
597 SqlType::Timestamp(match fsp {
598 Some(fsp) => len_as_u16(fsp),
599 None => 0_u16,
600 })
601 },
602 ),
603 map(tag_no_case("time"), |_| SqlType::Time),
604 map((tag_no_case("double"), multispace0, opt_unsigned), |_| {
605 SqlType::Double
606 }),
607 map(
608 terminated(
609 preceded(
610 tag_no_case("enum"),
611 delimited(tag("("), value_list, tag(")")),
612 ),
613 multispace0,
614 ),
615 SqlType::Enum,
616 ),
617 map(
618 terminated(
619 preceded(
620 tag_no_case("set"),
621 delimited(tag("("), value_list, tag(")")),
622 ),
623 multispace0,
624 ),
625 SqlType::Set,
626 ),
627 map(
628 (
629 tag_no_case("float"),
630 multispace0,
631 opt(precision),
632 multispace0,
633 opt_unsigned,
634 ),
635 |_| SqlType::Float,
636 ),
637 map((tag_no_case("real"), multispace0, opt_unsigned), |_| {
638 SqlType::Real
639 }),
640 map(tag_no_case("text"), |_| SqlType::Text),
641 map(
642 (
643 tag_no_case("varchar"),
644 delim_digit,
645 multispace0,
646 opt(tag_no_case("binary")),
647 ),
648 |t| SqlType::Varchar(len_as_u32(t.1)),
649 ),
650 map(tag_no_case("json"), |_| SqlType::Json),
651 map(tag_no_case("point"), |_| SqlType::Point),
652 map(tag_no_case("geometry"), |_| SqlType::Geometry),
653 decimal_or_numeric,
654 ))
655 .parse(i)
656}
657
658fn type_identifier_second_half(i: &[u8]) -> IResult<&[u8], SqlType> {
659 alt((
660 map((tag_no_case("binary"), delim_digit, multispace0), |t| {
661 SqlType::Binary(len_as_u16(t.1))
662 }),
663 map(tag_no_case("blob"), |_| SqlType::Blob),
664 map(tag_no_case("longblob"), |_| SqlType::Longblob),
665 map(tag_no_case("mediumblob"), |_| SqlType::Mediumblob),
666 map(tag_no_case("mediumtext"), |_| SqlType::Mediumtext),
667 map(tag_no_case("longtext"), |_| SqlType::Longtext),
668 map(tag_no_case("tinyblob"), |_| SqlType::Tinyblob),
669 map(tag_no_case("tinytext"), |_| SqlType::Tinytext),
670 map((tag_no_case("varbinary"), delim_digit, multispace0), |t| {
671 SqlType::Varbinary(len_as_u16(t.1))
672 }),
673 ))
674 .parse(i)
675}
676
677pub fn type_identifier(i: &[u8]) -> IResult<&[u8], SqlType> {
679 alt((type_identifier_first_half, type_identifier_second_half)).parse(i)
680}
681
682pub fn column_identifier_no_alias(i: &[u8]) -> IResult<&[u8], Column> {
684 let (remaining_input, (column, len)) =
685 (sql_identifier, opt(delimited(tag("("), digit1, tag(")")))).parse(i)?;
686 Ok((
687 remaining_input,
688 Column {
689 name: str::from_utf8(column).unwrap().replace("``", "`"),
690 query: None,
691 len: len.map(|l| u32::from_str(str::from_utf8(l).unwrap()).unwrap()),
692 desc: false,
693 },
694 ))
695}
696pub fn column_identifier_query(i: &[u8]) -> IResult<&[u8], Column> {
697 let (remaining_input, query) =
698 delimited(tag("("), take_until_unbalanced('(', ')'), tag(")")).parse(i)?;
699 Ok((
700 remaining_input,
701 Column {
702 name: "".to_string(),
703 query: Some(str::from_utf8(query).unwrap().to_string()),
704 len: None,
705 desc: false,
706 },
707 ))
708}
709
710pub fn sql_identifier(i: &[u8]) -> IResult<&[u8], &[u8]> {
712 alt((
713 preceded(not(peek(sql_keyword)), take_while1(is_sql_identifier)),
714 delimited(
715 tag("`"),
716 recognize(many0(alt((tag("``"), take_while1(|c| c != b'`'))))),
717 tag("`"),
718 ),
719 delimited(tag("["), take_while1(is_quoted_sql_identifier), tag("]")),
720 ))
721 .parse(i)
722}
723pub fn take_until_unbalanced(
724 opening_bracket: char,
725 closing_bracket: char,
726) -> impl Fn(&[u8]) -> IResult<&[u8], &[u8]> {
727 move |i: &[u8]| {
728 let mut index = 0;
729 let mut bracket_counter = 0;
730 while index < i.len() {
731 match i[index] {
732 b'\\' => {
733 index += 1;
734 }
735 c if c == opening_bracket as u8 => {
736 bracket_counter += 1;
737 }
738 c if c == closing_bracket as u8 => {
739 bracket_counter -= 1;
740 }
741 _ => {}
742 };
743 if bracket_counter == -1 {
744 return Ok((&i[index..], &i[0..index]));
745 };
746 index += 1;
747 }
748
749 if bracket_counter == 0 {
750 Ok(("".as_bytes(), i))
751 } else {
752 Err(nom::Err::Error(nom::error::Error::from_error_kind(
753 i,
754 ErrorKind::TakeUntil,
755 )))
756 }
757 }
758}
759
760pub(crate) fn eof<I: Copy + nom::Input, E: ParseError<I>>(input: I) -> IResult<I, I, E> {
761 if input.input_len() == 0 {
762 Ok((input, input))
763 } else {
764 Err(nom::Err::Error(E::from_error_kind(input, ErrorKind::Eof)))
765 }
766}
767
768pub fn statement_terminator(i: &[u8]) -> IResult<&[u8], ()> {
770 let (remaining_input, _) =
771 delimited(multispace0, alt((tag(";"), line_ending, eof)), multispace0).parse(i)?;
772
773 Ok((remaining_input, ()))
774}
775
776pub(crate) fn ws_sep_comma(i: &[u8]) -> IResult<&[u8], &[u8]> {
777 delimited(multispace0, tag(","), multispace0).parse(i)
778}
779
780pub(crate) fn ws_sep_equals<'a, I>(i: I) -> IResult<I, I>
781where
782 I: nom::Input + nom::Compare<&'a str>,
783 <I as nom::Input>::Item: nom::AsChar + Clone,
785 {
787 delimited(multispace0, tag("="), multispace0).parse(i)
788}
789
790pub fn integer_literal(i: &[u8]) -> IResult<&[u8], Literal> {
792 map(pair(opt(tag("-")), digit1), |tup| {
793 let mut intval = i64::from_str(str::from_utf8(tup.1).unwrap()).unwrap();
794 if (tup.0).is_some() {
795 intval *= -1;
796 }
797 Literal::Integer(intval)
798 })
799 .parse(i)
800}
801
802fn unpack(v: &[u8]) -> i32 {
803 i32::from_str(str::from_utf8(v).unwrap()).unwrap()
804}
805
806pub fn float_literal(i: &[u8]) -> IResult<&[u8], Literal> {
808 map((opt(tag("-")), digit1, tag("."), digit1), |tup| {
809 Literal::FixedPoint(Real {
810 integral: if (tup.0).is_some() {
811 -unpack(tup.1)
812 } else {
813 unpack(tup.1)
814 },
815 fractional: unpack(tup.3),
816 })
817 })
818 .parse(i)
819}
820
821fn raw_string_quoted(input: &[u8], is_single_quote: bool) -> IResult<&[u8], Vec<u8>> {
823 let quote_slice: &[u8] = if is_single_quote { b"\'" } else { b"\"" };
825 let double_quote_slice: &[u8] = if is_single_quote { b"\'\'" } else { b"\"\"" };
826 let backslash_quote: &[u8] = if is_single_quote { b"\\\'" } else { b"\\\"" };
827 delimited(
828 tag(quote_slice),
829 fold_many0(
830 alt((
831 is_not(backslash_quote),
832 map(tag(double_quote_slice), |_| -> &[u8] {
833 if is_single_quote { b"\'" } else { b"\"" }
834 }),
835 map(tag("\\\\"), |_| &b"\\"[..]),
836 map(tag("\\b"), |_| &b"\x7f"[..]),
837 map(tag("\\r"), |_| &b"\r"[..]),
838 map(tag("\\n"), |_| &b"\n"[..]),
839 map(tag("\\t"), |_| &b"\t"[..]),
840 map(tag("\\0"), |_| &b"\0"[..]),
841 map(tag("\\Z"), |_| &b"\x1A"[..]),
842 preceded(tag("\\"), take(1usize)),
843 )),
844 Vec::new,
845 |mut acc: Vec<u8>, bytes: &[u8]| {
846 acc.extend(bytes);
847 acc
848 },
849 ),
850 tag(quote_slice),
851 )
852 .parse(input)
853}
854
855fn raw_string_single_quoted(i: &[u8]) -> IResult<&[u8], Vec<u8>> {
856 raw_string_quoted(i, true)
857}
858
859fn raw_string_double_quoted(i: &[u8]) -> IResult<&[u8], Vec<u8>> {
860 raw_string_quoted(i, false)
861}
862
863pub fn string_literal(i: &[u8]) -> IResult<&[u8], Literal> {
864 map(
865 alt((raw_string_single_quoted, raw_string_double_quoted)),
866 |bytes| match String::from_utf8(bytes) {
867 Ok(s) => Literal::String(s),
868 Err(err) => Literal::Blob(err.into_bytes()),
869 },
870 )
871 .parse(i)
872}
873
874pub fn literal(i: &[u8]) -> IResult<&[u8], Literal> {
876 alt((
877 float_literal,
878 integer_literal,
879 string_literal,
880 map(tag_no_case("null"), |_| Literal::Null),
881 map(tag_no_case("current_timestamp"), |_| {
882 Literal::CurrentTimestamp
883 }),
884 map(tag_no_case("current_date"), |_| Literal::CurrentDate),
885 map(tag_no_case("current_time"), |_| Literal::CurrentTime),
886 map(tag("?"), |_| {
887 Literal::Placeholder(ItemPlaceholder::QuestionMark)
888 }),
889 map(preceded(tag(":"), digit1), |num| {
890 let value = i32::from_str(str::from_utf8(num).unwrap()).unwrap();
891 Literal::Placeholder(ItemPlaceholder::ColonNumber(value))
892 }),
893 map(preceded(tag("$"), digit1), |num| {
894 let value = i32::from_str(str::from_utf8(num).unwrap()).unwrap();
895 Literal::Placeholder(ItemPlaceholder::DollarNumber(value))
896 }),
897 ))
898 .parse(i)
899}
900
901pub fn value_list(i: &[u8]) -> IResult<&[u8], Vec<Literal>> {
903 many0(delimited(multispace0, literal, opt(ws_sep_comma))).parse(i)
904}
905
906pub fn schema_table_reference(i: &[u8]) -> IResult<&[u8], String> {
908 map(sql_identifier, |tup| {
909 str::from_utf8(tup).unwrap().replace("``", "`")
910 })
911 .parse(i)
912}
913
914pub fn parse_comment(i: &[u8]) -> IResult<&[u8], Literal> {
916 preceded(
917 delimited(multispace0, tag_no_case("comment"), multispace1),
918 string_literal,
919 )
920 .parse(i)
921}