senax_mysql_parser/
common.rs

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
444// TODO: rather than copy paste these functions, should create a function that returns a parser
445// based on the sql int type, just like nom does
446fn 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
469// TODO: rather than copy paste these functions, should create a function that returns a parser
470// based on the sql int type, just like nom does
471fn 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
494// TODO: rather than copy paste these functions, should create a function that returns a parser
495// based on the sql int type, just like nom does
496fn 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
541// TODO(malte): not strictly ok to treat DECIMAL and NUMERIC as identical; the
542// former has "at least" M precision, the latter "exactly".
543// See https://dev.mysql.com/doc/refman/5.7/en/precision-math-decimal-characteristics.html
544fn 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
667// A SQL type specifier.
668pub fn type_identifier(i: &[u8]) -> IResult<&[u8], SqlType> {
669    alt((type_identifier_first_half, type_identifier_second_half))(i)
670}
671
672// Parses a SQL column identifier in the table.column format
673pub 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
698// Parses a SQL identifier (alphanumeric1 and "_").
699pub 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
751// Parse a terminator that ends a SQL statement.
752pub 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    // Compare required by tag
767    <I as nom::InputTakeAtPosition>::Item: nom::AsChar + Clone,
768    // AsChar and Clone required by multispace0
769{
770    delimited(multispace0, tag("="), multispace0)(i)
771}
772
773// Integer literal value
774pub 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
788// Floating point literal value
789pub 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
802/// String literal value
803fn raw_string_quoted(input: &[u8], is_single_quote: bool) -> IResult<&[u8], Vec<u8>> {
804    // TODO: clean up these assignments. lifetimes and temporary values made it difficult
805    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
857// Any literal value.
858pub 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
883// Parse a list of values (e.g., for INSERT syntax).
884pub fn value_list(i: &[u8]) -> IResult<&[u8], Vec<Literal>> {
885    many0(delimited(multispace0, literal, opt(ws_sep_comma)))(i)
886}
887
888// Parse a reference to a named schema.table, with an optional alias
889pub 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
895// Parse rule for a comment part.
896pub fn parse_comment(i: &[u8]) -> IResult<&[u8], Literal> {
897    preceded(
898        delimited(multispace0, tag_no_case("comment"), multispace1),
899        string_literal,
900    )(i)
901}