Skip to main content

senax_mysql_parser/
common.rs

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    /// CHECK constraint: name, raw clause (parenthesized expression as written).
249    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
451// TODO: rather than copy paste these functions, should create a function that returns a parser
452// based on the sql int type, just like nom does
453fn 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
477// TODO: rather than copy paste these functions, should create a function that returns a parser
478// based on the sql int type, just like nom does
479fn 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
503// TODO: rather than copy paste these functions, should create a function that returns a parser
504// based on the sql int type, just like nom does
505fn 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
552// TODO(malte): not strictly ok to treat DECIMAL and NUMERIC as identical; the
553// former has "at least" M precision, the latter "exactly".
554// See https://dev.mysql.com/doc/refman/5.7/en/precision-math-decimal-characteristics.html
555fn 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
677// A SQL type specifier.
678pub fn type_identifier(i: &[u8]) -> IResult<&[u8], SqlType> {
679    alt((type_identifier_first_half, type_identifier_second_half)).parse(i)
680}
681
682// Parses a SQL column identifier in the table.column format
683pub 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
710// Parses a SQL identifier (alphanumeric1 and "_").
711pub 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
768// Parse a terminator that ends a SQL statement.
769pub 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    // Compare required by tag
784    <I as nom::Input>::Item: nom::AsChar + Clone,
785    // AsChar and Clone required by multispace0
786{
787    delimited(multispace0, tag("="), multispace0).parse(i)
788}
789
790// Integer literal value
791pub 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
806// Floating point literal value
807pub 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
821/// String literal value
822fn raw_string_quoted(input: &[u8], is_single_quote: bool) -> IResult<&[u8], Vec<u8>> {
823    // TODO: clean up these assignments. lifetimes and temporary values made it difficult
824    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
874// Any literal value.
875pub 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
901// Parse a list of values (e.g., for INSERT syntax).
902pub fn value_list(i: &[u8]) -> IResult<&[u8], Vec<Literal>> {
903    many0(delimited(multispace0, literal, opt(ws_sep_comma))).parse(i)
904}
905
906// Parse a reference to a named schema.table, with an optional alias
907pub 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
914// Parse rule for a comment part.
915pub 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}