Skip to main content

sqlite3_parser/parser/ast/
mod.rs

1//! Abstract Syntax Tree
2#[cfg(feature = "extra_checks")]
3pub mod check;
4pub mod fmt;
5
6use std::num::ParseIntError;
7use std::ops::Deref;
8use std::str::{self, Bytes, FromStr as _};
9
10use bumpalo::{collections::Vec, Bump};
11#[cfg(feature = "serde")]
12use serde::Serialize;
13
14#[cfg(feature = "extra_checks")]
15use check::ColumnCount;
16use fmt::TokenStream;
17
18use crate::custom_err;
19use crate::dialect::TokenType::{self, *};
20use crate::dialect::{from_token, is_identifier, Token};
21use crate::parser::{parse::YYCODETYPE, ParserError};
22
23/// `?` or `$` Prepared statement arg placeholder(s)
24#[derive(Default)]
25pub struct ParameterInfo {
26    /// Number of SQL parameters in a prepared statement, like `sqlite3_bind_parameter_count`
27    pub count: u16,
28    /// Parameter name(s) if any
29    pub names: indexmap::IndexSet<String>,
30}
31
32// https://sqlite.org/lang_expr.html#parameters
33impl TokenStream for ParameterInfo {
34    type Error = ParseIntError;
35
36    fn append(&mut self, ty: TokenType, value: Option<&str>) -> Result<(), Self::Error> {
37        if ty == TK_VARIABLE {
38            if let Some(variable) = value {
39                if variable == "?" {
40                    self.count = self.count.saturating_add(1);
41                } else if variable.as_bytes()[0] == b'?' {
42                    let n = u16::from_str(&variable[1..])?;
43                    if n > self.count {
44                        self.count = n;
45                    }
46                } else if self.names.insert(variable.to_owned()) {
47                    self.count = self.count.saturating_add(1);
48                }
49            }
50        }
51        Ok(())
52    }
53}
54
55/// Statement or Explain statement
56// https://sqlite.org/syntax/sql-stmt.html
57#[derive(Debug, PartialEq, Eq)]
58#[cfg_attr(feature = "serde", derive(Serialize))]
59pub enum Cmd<'bump> {
60    /// `EXPLAIN` statement
61    Explain(Stmt<'bump>),
62    /// `EXPLAIN QUERY PLAN` statement
63    ExplainQueryPlan(Stmt<'bump>),
64    /// statement
65    Stmt(Stmt<'bump>),
66}
67
68pub(crate) enum ExplainKind {
69    Explain,
70    QueryPlan,
71}
72
73/// SQL statement
74// https://sqlite.org/syntax/sql-stmt.html
75#[derive(Debug, PartialEq, Eq)]
76#[cfg_attr(feature = "serde", derive(Serialize))]
77pub enum Stmt<'bump> {
78    /// `ALTER TABLE`: table name, body
79    AlterTable(QualifiedName<'bump>, AlterTableBody<'bump>),
80    /// `ANALYSE`: object name
81    Analyze(Option<QualifiedName<'bump>>),
82    /// `ATTACH DATABASE`
83    Attach {
84        /// filename
85        // TODO distinction between ATTACH and ATTACH DATABASE
86        expr: Expr<'bump>,
87        /// schema name
88        db_name: Expr<'bump>,
89        /// password
90        key: Option<Expr<'bump>>,
91    },
92    /// `BEGIN`: tx type, tx name
93    Begin(Option<TransactionType>, Option<Name<'bump>>),
94    /// `COMMIT`/`END`: tx name
95    Commit(Option<Name<'bump>>), // TODO distinction between COMMIT and END
96    /// `CREATE INDEX`
97    CreateIndex {
98        /// `UNIQUE`
99        unique: bool,
100        /// `IF NOT EXISTS`
101        if_not_exists: bool,
102        /// index name
103        idx_name: QualifiedName<'bump>,
104        /// table name
105        tbl_name: Name<'bump>,
106        /// indexed columns or expressions
107        columns: &'bump [SortedColumn<'bump>],
108        /// partial index
109        where_clause: Option<Expr<'bump>>,
110    },
111    /// `CREATE TABLE`
112    CreateTable {
113        /// `TEMPORARY`
114        temporary: bool, // TODO distinction between TEMP and TEMPORARY
115        /// `IF NOT EXISTS`
116        if_not_exists: bool,
117        /// table name
118        tbl_name: QualifiedName<'bump>,
119        /// table body
120        body: CreateTableBody<'bump>,
121    },
122    /// `CREATE TRIGGER`
123    CreateTrigger {
124        /// `TEMPORARY`
125        temporary: bool,
126        /// `IF NOT EXISTS`
127        if_not_exists: bool,
128        /// trigger name
129        trigger_name: QualifiedName<'bump>,
130        /// `BEFORE`/`AFTER`/`INSTEAD OF`
131        time: Option<TriggerTime>,
132        /// `DELETE`/`INSERT`/`UPDATE`
133        event: TriggerEvent<'bump>,
134        /// table name
135        tbl_name: QualifiedName<'bump>,
136        /// `FOR EACH ROW`
137        for_each_row: bool,
138        /// `WHEN`
139        when_clause: Option<Expr<'bump>>,
140        /// statements
141        commands: &'bump [TriggerCmd<'bump>],
142    },
143    /// `CREATE VIEW`
144    CreateView {
145        /// `TEMPORARY`
146        temporary: bool,
147        /// `IF NOT EXISTS`
148        if_not_exists: bool,
149        /// view name
150        view_name: QualifiedName<'bump>,
151        /// columns
152        columns: Option<&'bump [IndexedColumn<'bump>]>, // TODO check no duplicate directly
153        /// query
154        select: &'bump Select<'bump>,
155    },
156    /// `CREATE VIRTUAL TABLE`
157    CreateVirtualTable {
158        /// `IF NOT EXISTS`
159        if_not_exists: bool,
160        /// table name
161        tbl_name: QualifiedName<'bump>,
162        /// module
163        module_name: Name<'bump>,
164        /// args
165        args: Option<&'bump [&'bump str]>,
166    },
167    /// `DELETE`
168    Delete {
169        /// CTE
170        with: Option<With<'bump>>, // TODO check usages in where_clause
171        /// `FROM` table name
172        tbl_name: QualifiedName<'bump>,
173        /// `INDEXED`
174        indexed: Option<Indexed<'bump>>,
175        /// `WHERE` clause
176        where_clause: Option<Expr<'bump>>,
177        /// `RETURNING`
178        returning: Option<&'bump [ResultColumn<'bump>]>,
179        /// `ORDER BY`
180        order_by: Option<&'bump [SortedColumn<'bump>]>,
181        /// `LIMIT`
182        limit: Option<&'bump Limit<'bump>>,
183    },
184    /// `DETACH DATABASE`: db name
185    Detach(Expr<'bump>), // TODO distinction between DETACH and DETACH DATABASE
186    /// `DROP INDEX`
187    DropIndex {
188        /// `IF EXISTS`
189        if_exists: bool,
190        /// index name
191        idx_name: QualifiedName<'bump>,
192    },
193    /// `DROP TABLE`
194    DropTable {
195        /// `IF EXISTS`
196        if_exists: bool,
197        /// table name
198        tbl_name: QualifiedName<'bump>,
199    },
200    /// `DROP TRIGGER`
201    DropTrigger {
202        /// `IF EXISTS`
203        if_exists: bool,
204        /// trigger name
205        trigger_name: QualifiedName<'bump>,
206    },
207    /// `DROP VIEW`
208    DropView {
209        /// `IF EXISTS`
210        if_exists: bool,
211        /// view name
212        view_name: QualifiedName<'bump>,
213    },
214    /// `INSERT`
215    Insert {
216        /// CTE
217        with: Option<With<'bump>>, // TODO check usages in body
218        /// `OR`
219        or_conflict: Option<ResolveType>, // TODO distinction between REPLACE and INSERT OR REPLACE
220        /// table name
221        tbl_name: QualifiedName<'bump>,
222        /// `COLUMNS`
223        columns: Option<DistinctNames<'bump>>,
224        /// `VALUES` or `SELECT`
225        body: InsertBody<'bump>,
226        /// `RETURNING`
227        returning: Option<&'bump [ResultColumn<'bump>]>,
228    },
229    /// `PRAGMA`: pragma name, body
230    Pragma(QualifiedName<'bump>, Option<PragmaBody<'bump>>),
231    /// `REINDEX`
232    Reindex {
233        /// collation or index or table name
234        obj_name: Option<QualifiedName<'bump>>,
235    },
236    /// `RELEASE`: savepoint name
237    Release(Name<'bump>), // TODO distinction between RELEASE and RELEASE SAVEPOINT
238    /// `ROLLBACK`
239    Rollback {
240        /// transaction name
241        tx_name: Option<Name<'bump>>,
242        /// savepoint name
243        savepoint_name: Option<Name<'bump>>, // TODO distinction between TO and TO SAVEPOINT
244    },
245    /// `SAVEPOINT`: savepoint name
246    Savepoint(Name<'bump>),
247    /// `SELECT`
248    Select(&'bump Select<'bump>),
249    /// `UPDATE`
250    Update {
251        /// CTE
252        with: Option<With<'bump>>, // TODO check usages in where_clause
253        /// `OR`
254        or_conflict: Option<ResolveType>,
255        /// table name
256        tbl_name: QualifiedName<'bump>,
257        /// `INDEXED`
258        indexed: Option<Indexed<'bump>>,
259        /// `SET` assignments
260        sets: &'bump [Set<'bump>], // FIXME unique
261        /// `FROM`
262        from: Option<FromClause<'bump>>,
263        /// `WHERE` clause
264        where_clause: Option<Expr<'bump>>,
265        /// `RETURNING`
266        returning: Option<&'bump [ResultColumn<'bump>]>,
267        /// `ORDER BY`
268        order_by: Option<&'bump [SortedColumn<'bump>]>,
269        /// `LIMIT`
270        limit: Option<&'bump Limit<'bump>>,
271    },
272    /// `VACUUM`: database name, into expr
273    Vacuum(Option<Name<'bump>>, Option<Expr<'bump>>),
274}
275
276impl<'bump> Stmt<'bump> {
277    /// CREATE INDEX constructor
278    pub fn create_index(
279        unique: bool,
280        if_not_exists: bool,
281        idx_name: QualifiedName<'bump>,
282        tbl_name: Name<'bump>,
283        columns: Vec<'bump, SortedColumn<'bump>>,
284        where_clause: Option<Expr<'bump>>,
285    ) -> Result<Self, ParserError> {
286        has_explicit_nulls(&columns)?;
287        Ok(Self::CreateIndex {
288            unique,
289            if_not_exists,
290            idx_name,
291            tbl_name,
292            columns: columns.into_bump_slice(),
293            where_clause,
294        })
295    }
296    /// UPDATE constructor
297    #[allow(clippy::too_many_arguments)]
298    pub fn update(
299        with: Option<With<'bump>>,
300        or_conflict: Option<ResolveType>,
301        tbl_name: QualifiedName<'bump>,
302        indexed: Option<Indexed<'bump>>,
303        sets: Vec<'bump, Set<'bump>>, // FIXME unique
304        from: Option<FromClause<'bump>>,
305        where_clause: Option<Expr<'bump>>,
306        returning: Option<Vec<'bump, ResultColumn<'bump>>>,
307        order_by: Option<Vec<'bump, SortedColumn<'bump>>>,
308        limit: Option<&'bump Limit<'bump>>,
309    ) -> Result<Self, ParserError> {
310        #[cfg(feature = "extra_checks")]
311        if let Some(FromClause {
312            select: Some(ref select),
313            ref joins,
314            ..
315        }) = from
316        {
317            if matches!(select,
318                SelectTable::Table(qn, _, _) | SelectTable::TableCall(qn, _, _)
319                    if *qn == tbl_name)
320                || joins.as_ref().is_some_and(|js| js.iter().any(|j|
321                    matches!(j.table, SelectTable::Table(ref qn, _, _) | SelectTable::TableCall(ref qn, _, _)
322                    if *qn == tbl_name)))
323            {
324                return Err(custom_err!(
325                    "target object/alias may not appear in FROM clause",
326                ));
327            }
328        }
329        #[cfg(feature = "extra_checks")]
330        if order_by.is_some() && limit.is_none() {
331            return Err(custom_err!("ORDER BY without LIMIT on UPDATE"));
332        }
333        Ok(Self::Update {
334            with,
335            or_conflict,
336            tbl_name,
337            indexed,
338            sets: sets.into_bump_slice(),
339            from,
340            where_clause,
341            returning: returning.map(|r| r.into_bump_slice()),
342            order_by: order_by.map(|ob| ob.into_bump_slice()),
343            limit,
344        })
345    }
346}
347
348/// SQL expression
349// https://sqlite.org/syntax/expr.html
350#[derive(Debug, PartialEq, Eq)]
351#[cfg_attr(feature = "serde", derive(Serialize))]
352pub enum Expr<'bump> {
353    /// `BETWEEN`
354    Between {
355        /// expression
356        lhs: &'bump Expr<'bump>,
357        /// `NOT`
358        not: bool,
359        /// start
360        start: &'bump Expr<'bump>,
361        /// end
362        end: &'bump Expr<'bump>,
363    },
364    /// binary expression
365    Binary(&'bump Expr<'bump>, Operator, &'bump Expr<'bump>),
366    /// `CASE` expression
367    Case {
368        /// operand
369        base: Option<&'bump Expr<'bump>>,
370        /// `WHEN` condition `THEN` result
371        when_then_pairs: &'bump [(Expr<'bump>, Expr<'bump>)],
372        /// `ELSE` result
373        else_expr: Option<&'bump Expr<'bump>>,
374    },
375    /// CAST expression
376    Cast {
377        /// expression
378        expr: &'bump Expr<'bump>,
379        /// `AS` type name
380        type_name: Option<Type<'bump>>,
381    },
382    /// `COLLATE`: expression
383    Collate(&'bump Expr<'bump>, &'bump str),
384    /// schema-name.table-name.column-name
385    DoublyQualified(Name<'bump>, Name<'bump>, Name<'bump>),
386    /// `EXISTS` subquery
387    Exists(&'bump Select<'bump>),
388    /// call to a built-in function
389    FunctionCall {
390        /// function name
391        name: Id<'bump>,
392        /// `DISTINCT`
393        distinctness: Option<Distinctness>,
394        /// arguments
395        args: Option<&'bump [Expr<'bump>]>,
396        /// `ORDER BY` or `WITHIN GROUP`
397        order_by: Option<FunctionCallOrder<'bump>>,
398        /// `FILTER`
399        filter_over: Option<FunctionTail<'bump>>,
400    },
401    /// Function call expression with '*' as arg
402    FunctionCallStar {
403        /// function name
404        name: Id<'bump>,
405        /// `FILTER`
406        filter_over: Option<FunctionTail<'bump>>,
407    },
408    /// Identifier
409    Id(Id<'bump>),
410    /// `IN`
411    InList {
412        /// expression
413        lhs: &'bump Expr<'bump>,
414        /// `NOT`
415        not: bool,
416        /// values
417        rhs: Option<&'bump [Expr<'bump>]>,
418    },
419    /// `IN` subselect
420    InSelect {
421        /// expression
422        lhs: &'bump Expr<'bump>,
423        /// `NOT`
424        not: bool,
425        /// subquery
426        rhs: &'bump Select<'bump>,
427    },
428    /// `IN` table name / function
429    InTable {
430        /// expression
431        lhs: &'bump Expr<'bump>,
432        /// `NOT`
433        not: bool,
434        /// table name
435        rhs: QualifiedName<'bump>,
436        /// table function arguments
437        args: Option<&'bump [Expr<'bump>]>,
438    },
439    /// `IS NULL`
440    IsNull(&'bump Expr<'bump>),
441    /// `LIKE`
442    Like {
443        /// expression
444        lhs: &'bump Expr<'bump>,
445        /// `NOT`
446        not: bool,
447        /// operator
448        op: LikeOperator,
449        /// pattern
450        rhs: &'bump Expr<'bump>,
451        /// `ESCAPE` char
452        escape: Option<&'bump Expr<'bump>>,
453    },
454    /// Literal expression
455    Literal(Literal<'bump>),
456    /// Name
457    Name(Name<'bump>),
458    /// `NOT NULL` or `NOTNULL`
459    NotNull(&'bump Expr<'bump>),
460    /// Parenthesized subexpression
461    Parenthesized(Vec<'bump, Expr<'bump>>),
462    /// Qualified name
463    Qualified(Name<'bump>, Name<'bump>),
464    /// `RAISE` function call
465    Raise(ResolveType, Option<&'bump Expr<'bump>>),
466    /// Subquery expression
467    Subquery(&'bump Select<'bump>),
468    /// Unary expression
469    Unary(UnaryOperator, &'bump Expr<'bump>),
470    /// Parameters
471    Variable(&'bump str),
472}
473
474/// Function call order
475#[derive(Debug, PartialEq, Eq)]
476#[cfg_attr(feature = "serde", derive(Serialize))]
477pub enum FunctionCallOrder<'bump> {
478    /// `ORDER BY cols`
479    SortList(&'bump [SortedColumn<'bump>]),
480    /// `WITHIN GROUP (ORDER BY expr)`
481    #[cfg(feature = "SQLITE_ENABLE_ORDERED_SET_AGGREGATES")]
482    WithinGroup(&'bump Expr<'bump>),
483}
484
485impl<'bump> FunctionCallOrder<'bump> {
486    /// Constructor
487    #[cfg(feature = "SQLITE_ENABLE_ORDERED_SET_AGGREGATES")]
488    pub fn within_group(expr: &'bump Expr<'bump>) -> Self {
489        Self::WithinGroup(expr)
490    }
491}
492
493impl<'bump> Expr<'bump> {
494    /// Constructor
495    pub fn parenthesized(x: Self, b: &'bump Bump) -> Self {
496        Self::Parenthesized(bumpalo::vec![in b; x])
497    }
498    /// Constructor
499    pub fn id(xt: YYCODETYPE, x: Token, b: &'bump Bump) -> Self {
500        Self::Id(Id::from_token(xt, x, b))
501    }
502    /// Constructor
503    pub fn collate(x: Self, ct: YYCODETYPE, c: Token, b: &'bump Bump) -> Self {
504        Self::Collate(b.alloc(x), from_token(ct, c, b))
505    }
506    /// Constructor
507    pub fn cast(x: Self, type_name: Option<Type<'bump>>, b: &'bump Bump) -> Self {
508        Self::Cast {
509            expr: b.alloc(x),
510            type_name,
511        }
512    }
513    /// Constructor
514    pub fn binary(left: Self, op: YYCODETYPE, right: Self, b: &'bump Bump) -> Self {
515        Self::Binary(b.alloc(left), Operator::from(op), b.alloc(right))
516    }
517    /// Constructor
518    pub fn ptr(left: Self, op: Token, right: Self, b: &'bump Bump) -> Self {
519        let mut ptr = Operator::ArrowRight;
520        if op.1 == b"->>" {
521            ptr = Operator::ArrowRightShift;
522        }
523        Self::Binary(b.alloc(left), ptr, b.alloc(right))
524    }
525    /// Constructor
526    pub fn like(
527        lhs: Self,
528        not: bool,
529        op: LikeOperator,
530        rhs: Self,
531        escape: Option<Self>,
532        b: &'bump Bump,
533    ) -> Self {
534        Self::Like {
535            lhs: b.alloc(lhs),
536            not,
537            op,
538            rhs: b.alloc(rhs),
539            escape: escape.map(|e| b.alloc(e) as _),
540        }
541    }
542    /// Constructor
543    pub fn not_null(x: Self, op: YYCODETYPE, b: &'bump Bump) -> Self {
544        if op == TK_ISNULL as YYCODETYPE {
545            Self::IsNull(b.alloc(x))
546        } else if op == TK_NOTNULL as YYCODETYPE {
547            Self::NotNull(b.alloc(x))
548        } else {
549            unreachable!()
550        }
551    }
552    /// Constructor
553    pub fn unary(op: UnaryOperator, x: Self, b: &'bump Bump) -> Self {
554        Self::Unary(op, b.alloc(x))
555    }
556    /// Constructor
557    pub fn between(lhs: Self, not: bool, start: Self, end: Self, b: &'bump Bump) -> Self {
558        Self::Between {
559            lhs: b.alloc(lhs),
560            not,
561            start: b.alloc(start),
562            end: b.alloc(end),
563        }
564    }
565    /// Constructor
566    pub fn in_list(lhs: Self, not: bool, rhs: Option<Vec<'bump, Self>>, b: &'bump Bump) -> Self {
567        Self::InList {
568            lhs: b.alloc(lhs),
569            not,
570            rhs: rhs.map(|r| r.into_bump_slice()),
571        }
572    }
573    /// Constructor
574    pub fn in_select(lhs: Self, not: bool, rhs: Select<'bump>, b: &'bump Bump) -> Self {
575        Self::InSelect {
576            lhs: b.alloc(lhs),
577            not,
578            rhs: b.alloc(rhs),
579        }
580    }
581    /// Constructor
582    pub fn in_table(
583        lhs: Self,
584        not: bool,
585        rhs: QualifiedName<'bump>,
586        args: Option<Vec<'bump, Self>>,
587        b: &'bump Bump,
588    ) -> Self {
589        Self::InTable {
590            lhs: b.alloc(lhs),
591            not,
592            rhs,
593            args: args.map(|a| a.into_bump_slice()),
594        }
595    }
596    /// Constructor
597    pub fn sub_query(query: Select<'bump>, b: &'bump Bump) -> Self {
598        Self::Subquery(b.alloc(query))
599    }
600    /// Constructor
601    pub fn function_call(
602        xt: YYCODETYPE,
603        x: Token,
604        distinctness: Option<Distinctness>,
605        args: Option<Vec<'bump, Self>>,
606        order_by: Option<FunctionCallOrder<'bump>>,
607        filter_over: Option<FunctionTail<'bump>>,
608        b: &'bump Bump,
609    ) -> Result<Self, ParserError> {
610        #[cfg(feature = "extra_checks")]
611        if let Some(Distinctness::Distinct) = distinctness {
612            if args.as_ref().map_or(0, Vec::len) != 1 {
613                return Err(custom_err!(
614                    "DISTINCT aggregates must have exactly one argument"
615                ));
616            }
617        }
618        Ok(Self::FunctionCall {
619            name: Id::from_token(xt, x, b),
620            distinctness,
621            args: args.map(|a| a.into_bump_slice()),
622            order_by,
623            filter_over,
624        })
625    }
626
627    /// Check if an expression is an integer
628    pub fn is_integer(&self) -> Option<i64> {
629        if let Self::Literal(Literal::Numeric(s)) = self {
630            i64::from_str(s).ok()
631        } else if let Self::Unary(UnaryOperator::Positive, e) = self {
632            e.is_integer()
633        } else if let Self::Unary(UnaryOperator::Negative, e) = self {
634            e.is_integer().map(i64::saturating_neg)
635        } else {
636            None
637        }
638    }
639    #[cfg(feature = "extra_checks")]
640    fn check_range(&self, term: &str, mx: u16) -> Result<(), ParserError> {
641        if let Some(i) = self.is_integer() {
642            if i < 1 || i > mx as i64 {
643                return Err(custom_err!(
644                    "{} BY term out of range - should be between 1 and {}",
645                    term,
646                    mx
647                ));
648            }
649        }
650        Ok(())
651    }
652}
653
654/// SQL literal
655#[derive(Debug, PartialEq, Eq)]
656#[cfg_attr(feature = "serde", derive(Serialize))]
657pub enum Literal<'bump> {
658    /// Number
659    Numeric(&'bump str),
660    /// String
661    // TODO Check that string is already quoted and correctly escaped
662    String(&'bump str),
663    /// BLOB
664    // TODO Check that string is valid (only hexa)
665    Blob(&'bump str),
666    /// Keyword
667    Keyword(&'bump str),
668    /// `NULL`
669    Null,
670    /// `CURRENT_DATE`
671    CurrentDate,
672    /// `CURRENT_TIME`
673    CurrentTime,
674    /// `CURRENT_TIMESTAMP`
675    CurrentTimestamp,
676}
677
678impl<'bump> Literal<'bump> {
679    /// Constructor
680    pub fn from_ctime_kw(token: Token) -> Self {
681        if b"CURRENT_DATE".eq_ignore_ascii_case(token.1) {
682            Self::CurrentDate
683        } else if b"CURRENT_TIME".eq_ignore_ascii_case(token.1) {
684            Self::CurrentTime
685        } else if b"CURRENT_TIMESTAMP".eq_ignore_ascii_case(token.1) {
686            Self::CurrentTimestamp
687        } else {
688            unreachable!()
689        }
690    }
691}
692
693/// Textual comparison operator in an expression
694#[derive(Copy, Clone, Debug, PartialEq, Eq)]
695#[cfg_attr(feature = "serde", derive(Serialize))]
696pub enum LikeOperator {
697    /// `GLOB`
698    Glob,
699    /// `LIKE`
700    Like,
701    /// `MATCH`
702    Match,
703    /// `REGEXP`
704    Regexp,
705}
706
707impl LikeOperator {
708    /// Constructor
709    pub fn from_token(token_type: YYCODETYPE, token: Token) -> Self {
710        if token_type == TK_MATCH as YYCODETYPE {
711            return Self::Match;
712        } else if token_type == TK_LIKE_KW as YYCODETYPE {
713            let token = token.1;
714            if b"LIKE".eq_ignore_ascii_case(token) {
715                return Self::Like;
716            } else if b"GLOB".eq_ignore_ascii_case(token) {
717                return Self::Glob;
718            } else if b"REGEXP".eq_ignore_ascii_case(token) {
719                return Self::Regexp;
720            }
721        }
722        unreachable!()
723    }
724}
725
726/// SQL operators
727#[derive(Copy, Clone, Debug, PartialEq, Eq)]
728#[cfg_attr(feature = "serde", derive(Serialize))]
729pub enum Operator {
730    /// `+`
731    Add,
732    /// `AND`
733    And,
734    /// `->`
735    ArrowRight,
736    /// `->>`
737    ArrowRightShift,
738    /// `&`
739    BitwiseAnd,
740    /// `|`
741    BitwiseOr,
742    /// String concatenation (`||`)
743    Concat,
744    /// `=` or `==`
745    Equals,
746    /// `/`
747    Divide,
748    /// `>`
749    Greater,
750    /// `>=`
751    GreaterEquals,
752    /// `IS`
753    Is,
754    /// `IS NOT`
755    IsNot,
756    /// `<<`
757    LeftShift,
758    /// `<`
759    Less,
760    /// `<=`
761    LessEquals,
762    /// `%`
763    Modulus,
764    /// `*`
765    Multiply,
766    /// `!=` or `<>`
767    NotEquals,
768    /// `OR`
769    Or,
770    /// `>>`
771    RightShift,
772    /// `-`
773    Subtract,
774}
775
776impl From<YYCODETYPE> for Operator {
777    fn from(token_type: YYCODETYPE) -> Self {
778        match token_type {
779            x if x == TK_AND as YYCODETYPE => Self::And,
780            x if x == TK_OR as YYCODETYPE => Self::Or,
781            x if x == TK_LT as YYCODETYPE => Self::Less,
782            x if x == TK_GT as YYCODETYPE => Self::Greater,
783            x if x == TK_GE as YYCODETYPE => Self::GreaterEquals,
784            x if x == TK_LE as YYCODETYPE => Self::LessEquals,
785            x if x == TK_EQ as YYCODETYPE => Self::Equals,
786            x if x == TK_NE as YYCODETYPE => Self::NotEquals,
787            x if x == TK_BITAND as YYCODETYPE => Self::BitwiseAnd,
788            x if x == TK_BITOR as YYCODETYPE => Self::BitwiseOr,
789            x if x == TK_LSHIFT as YYCODETYPE => Self::LeftShift,
790            x if x == TK_RSHIFT as YYCODETYPE => Self::RightShift,
791            x if x == TK_PLUS as YYCODETYPE => Self::Add,
792            x if x == TK_MINUS as YYCODETYPE => Self::Subtract,
793            x if x == TK_STAR as YYCODETYPE => Self::Multiply,
794            x if x == TK_SLASH as YYCODETYPE => Self::Divide,
795            x if x == TK_REM as YYCODETYPE => Self::Modulus,
796            x if x == TK_CONCAT as YYCODETYPE => Self::Concat,
797            x if x == TK_IS as YYCODETYPE => Self::Is,
798            x if x == TK_NOT as YYCODETYPE => Self::IsNot,
799            _ => unreachable!(),
800        }
801    }
802}
803
804/// Unary operators
805#[derive(Copy, Clone, Debug, PartialEq, Eq)]
806#[cfg_attr(feature = "serde", derive(Serialize))]
807pub enum UnaryOperator {
808    /// bitwise negation (`~`)
809    BitwiseNot,
810    /// negative-sign
811    Negative,
812    /// `NOT`
813    Not,
814    /// positive-sign
815    Positive,
816}
817
818impl From<YYCODETYPE> for UnaryOperator {
819    fn from(token_type: YYCODETYPE) -> Self {
820        match token_type {
821            x if x == TK_BITNOT as YYCODETYPE => Self::BitwiseNot,
822            x if x == TK_MINUS as YYCODETYPE => Self::Negative,
823            x if x == TK_NOT as YYCODETYPE => Self::Not,
824            x if x == TK_PLUS as YYCODETYPE => Self::Positive,
825            _ => unreachable!(),
826        }
827    }
828}
829
830/// `SELECT` statement
831// https://sqlite.org/lang_select.html
832// https://sqlite.org/syntax/factored-select-stmt.html
833#[derive(Debug, PartialEq, Eq)]
834#[cfg_attr(feature = "serde", derive(Serialize))]
835pub struct Select<'bump> {
836    /// CTE
837    pub with: Option<With<'bump>>, // TODO check usages in body
838    /// body
839    pub body: SelectBody<'bump>,
840    /// `ORDER BY`
841    pub order_by: Option<&'bump [SortedColumn<'bump>]>, // TODO: ORDER BY term does not match any column in the result set
842    /// `LIMIT`
843    pub limit: Option<&'bump Limit<'bump>>,
844}
845
846impl<'bump> Select<'bump> {
847    /// Constructor
848    pub fn new(
849        with: Option<With<'bump>>,
850        body: SelectBody<'bump>,
851        order_by: Option<Vec<'bump, SortedColumn<'bump>>>,
852        limit: Option<&'bump Limit<'bump>>,
853    ) -> Result<Self, ParserError> {
854        let select = Self {
855            with,
856            body,
857            order_by: order_by.map(|ob| ob.into_bump_slice()),
858            limit,
859        };
860        #[cfg(feature = "extra_checks")]
861        if let Self {
862            order_by: Some(scs),
863            ..
864        } = select
865        {
866            if let ColumnCount::Fixed(n) = select.column_count() {
867                for sc in scs {
868                    sc.expr.check_range("ORDER", n)?;
869                }
870            }
871        }
872        Ok(select)
873    }
874}
875
876/// `SELECT` body
877#[derive(Debug, PartialEq, Eq)]
878#[cfg_attr(feature = "serde", derive(Serialize))]
879pub struct SelectBody<'bump> {
880    /// first select
881    pub select: OneSelect<'bump>,
882    /// compounds
883    pub compounds: Option<Vec<'bump, CompoundSelect<'bump>>>,
884}
885
886impl<'bump> SelectBody<'bump> {
887    pub(crate) fn push(
888        &mut self,
889        cs: CompoundSelect<'bump>,
890        b: &'bump Bump,
891    ) -> Result<(), ParserError> {
892        #[cfg(feature = "extra_checks")]
893        if let ColumnCount::Fixed(n) = self.select.column_count() {
894            if let ColumnCount::Fixed(m) = cs.select.column_count() {
895                if n != m {
896                    return Err(custom_err!(
897                        "SELECTs to the left and right of {} do not have the same number of result columns",
898                        cs.operator
899                    ));
900                }
901            }
902        }
903        if let Some(ref mut v) = self.compounds {
904            v.push(cs);
905        } else {
906            self.compounds = Some(bumpalo::vec![in b; cs]);
907        }
908        Ok(())
909    }
910}
911
912/// Compound select
913#[derive(Debug, PartialEq, Eq)]
914#[cfg_attr(feature = "serde", derive(Serialize))]
915pub struct CompoundSelect<'bump> {
916    /// operator
917    pub operator: CompoundOperator,
918    /// select
919    pub select: OneSelect<'bump>,
920}
921
922/// Compound operators
923// https://sqlite.org/syntax/compound-operator.html
924#[derive(Copy, Clone, Debug, PartialEq, Eq)]
925#[cfg_attr(feature = "serde", derive(Serialize))]
926pub enum CompoundOperator {
927    /// `UNION`
928    Union,
929    /// `UNION ALL`
930    UnionAll,
931    /// `EXCEPT`
932    Except,
933    /// `INTERSECT`
934    Intersect,
935}
936
937/// `SELECT` core
938// https://sqlite.org/syntax/select-core.html
939#[derive(Debug, PartialEq, Eq)]
940#[cfg_attr(feature = "serde", derive(Serialize))]
941pub enum OneSelect<'bump> {
942    /// `SELECT`
943    Select {
944        /// `DISTINCT`
945        distinctness: Option<Distinctness>,
946        /// columns
947        columns: &'bump [ResultColumn<'bump>],
948        /// `FROM` clause
949        from: Option<FromClause<'bump>>,
950        /// `WHERE` clause
951        where_clause: Option<&'bump Expr<'bump>>,
952        /// `GROUP BY`
953        group_by: Option<&'bump [Expr<'bump>]>,
954        /// `HAVING`
955        having: Option<&'bump Expr<'bump>>, // TODO: HAVING clause on a non-aggregate query
956        /// `WINDOW` definition
957        window_clause: Option<&'bump [WindowDef<'bump>]>,
958    },
959    /// `VALUES`
960    Values(Vec<'bump, Vec<'bump, Expr<'bump>>>),
961}
962
963impl<'bump> OneSelect<'bump> {
964    /// Constructor
965    #[expect(clippy::too_many_arguments)]
966    pub fn new(
967        distinctness: Option<Distinctness>,
968        columns: Vec<'bump, ResultColumn<'bump>>,
969        from: Option<FromClause<'bump>>,
970        where_clause: Option<Expr<'bump>>,
971        group_by: Option<Vec<'bump, Expr<'bump>>>,
972        having: Option<Expr<'bump>>,
973        window_clause: Option<Vec<'bump, WindowDef<'bump>>>,
974        b: &'bump Bump,
975    ) -> Result<Self, ParserError> {
976        #[cfg(feature = "extra_checks")]
977        if from.is_none()
978            && columns
979                .iter()
980                .any(|rc| matches!(rc, ResultColumn::Star | ResultColumn::TableStar(_)))
981        {
982            return Err(custom_err!("no tables specified"));
983        }
984        let select = Self::Select {
985            distinctness,
986            columns: columns.into_bump_slice(),
987            from,
988            where_clause: where_clause.map(|wc| b.alloc(wc) as _),
989            group_by: group_by.map(|gb| gb.into_bump_slice()),
990            having: having.map(|h| b.alloc(h) as _),
991            window_clause: window_clause.map(|wc| wc.into_bump_slice()),
992        };
993        #[cfg(feature = "extra_checks")]
994        if let Self::Select {
995            group_by: Some(gb), ..
996        } = select
997        {
998            if let ColumnCount::Fixed(n) = select.column_count() {
999                for expr in gb {
1000                    expr.check_range("GROUP", n)?;
1001                }
1002            }
1003        }
1004        Ok(select)
1005    }
1006    /// Check all VALUES have the same number of terms
1007    pub fn push(
1008        values: &mut Vec<'bump, Vec<'bump, Expr<'bump>>>,
1009        v: Vec<'bump, Expr<'bump>>,
1010    ) -> Result<(), ParserError> {
1011        #[cfg(feature = "extra_checks")]
1012        if values[0].len() != v.len() {
1013            return Err(custom_err!("all VALUES must have the same number of terms"));
1014        }
1015        values.push(v);
1016        Ok(())
1017    }
1018}
1019
1020/// `SELECT` ... `FROM` clause
1021// https://sqlite.org/syntax/join-clause.html
1022#[derive(Debug, PartialEq, Eq)]
1023#[cfg_attr(feature = "serde", derive(Serialize))]
1024pub struct FromClause<'bump> {
1025    /// table
1026    pub select: Option<&'bump SelectTable<'bump>>, // FIXME mandatory
1027    /// `JOIN`ed tabled
1028    pub joins: Option<Vec<'bump, JoinedSelectTable<'bump>>>,
1029    op: Option<JoinOperator>, // FIXME transient
1030}
1031impl<'bump> FromClause<'bump> {
1032    pub(crate) fn empty() -> Self {
1033        Self {
1034            select: None,
1035            joins: None,
1036            op: None,
1037        }
1038    }
1039
1040    pub(crate) fn push(
1041        &mut self,
1042        table: SelectTable<'bump>,
1043        jc: Option<JoinConstraint<'bump>>,
1044        b: &'bump Bump,
1045    ) -> Result<(), ParserError> {
1046        let op = self.op.take();
1047        if let Some(op) = op {
1048            let jst = JoinedSelectTable {
1049                operator: op,
1050                table,
1051                constraint: jc,
1052            };
1053            if jst.operator.is_natural() && jst.constraint.is_some() {
1054                return Err(custom_err!(
1055                    "a NATURAL join may not have an ON or USING clause"
1056                ));
1057            }
1058            if let Some(ref mut joins) = self.joins {
1059                joins.push(jst);
1060            } else {
1061                self.joins = Some(bumpalo::vec![in b; jst]);
1062            }
1063        } else {
1064            if jc.is_some() {
1065                return Err(custom_err!("a JOIN clause is required before ON"));
1066            }
1067            debug_assert!(self.select.is_none());
1068            debug_assert!(self.joins.is_none());
1069            self.select = Some(b.alloc(table));
1070        }
1071        Ok(())
1072    }
1073
1074    pub(crate) fn push_op(&mut self, op: JoinOperator) {
1075        self.op = Some(op);
1076    }
1077}
1078
1079/// `SELECT` distinctness
1080#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1081#[cfg_attr(feature = "serde", derive(Serialize))]
1082pub enum Distinctness {
1083    /// `DISTINCT`
1084    Distinct,
1085    /// `ALL`
1086    All,
1087}
1088
1089/// `SELECT` or `RETURNING` result column
1090// https://sqlite.org/syntax/result-column.html
1091#[derive(Debug, PartialEq, Eq)]
1092#[cfg_attr(feature = "serde", derive(Serialize))]
1093pub enum ResultColumn<'bump> {
1094    /// expression
1095    Expr(Expr<'bump>, Option<As<'bump>>),
1096    /// `*`
1097    Star,
1098    /// table name.`*`
1099    TableStar(Name<'bump>),
1100}
1101
1102/// Alias
1103#[derive(Debug, PartialEq, Eq)]
1104#[cfg_attr(feature = "serde", derive(Serialize))]
1105pub enum As<'bump> {
1106    /// `AS`
1107    As(Name<'bump>),
1108    /// no `AS`
1109    Elided(Name<'bump>), // FIXME Ids
1110}
1111
1112/// `JOIN` clause
1113// https://sqlite.org/syntax/join-clause.html
1114#[derive(Debug, PartialEq, Eq)]
1115#[cfg_attr(feature = "serde", derive(Serialize))]
1116pub struct JoinedSelectTable<'bump> {
1117    /// operator
1118    pub operator: JoinOperator,
1119    /// table
1120    pub table: SelectTable<'bump>,
1121    /// constraint
1122    pub constraint: Option<JoinConstraint<'bump>>,
1123}
1124
1125/// Table or subquery
1126// https://sqlite.org/syntax/table-or-subquery.html
1127#[derive(Debug, PartialEq, Eq)]
1128#[cfg_attr(feature = "serde", derive(Serialize))]
1129pub enum SelectTable<'bump> {
1130    /// table
1131    Table(
1132        QualifiedName<'bump>,
1133        Option<As<'bump>>,
1134        Option<Indexed<'bump>>,
1135    ),
1136    /// table function call
1137    TableCall(
1138        QualifiedName<'bump>,
1139        Option<&'bump [Expr<'bump>]>,
1140        Option<As<'bump>>,
1141    ),
1142    /// `SELECT` subquery
1143    Select(&'bump Select<'bump>, Option<As<'bump>>),
1144    /// subquery
1145    Sub(FromClause<'bump>, Option<As<'bump>>),
1146}
1147
1148/// Join operators
1149// https://sqlite.org/syntax/join-operator.html
1150#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1151#[cfg_attr(feature = "serde", derive(Serialize))]
1152pub enum JoinOperator {
1153    /// `,`
1154    Comma,
1155    /// `JOIN`
1156    TypedJoin(Option<JoinType>),
1157}
1158
1159impl JoinOperator {
1160    pub(crate) fn from(
1161        token: Token,
1162        n1: Option<Name>,
1163        n2: Option<Name>,
1164    ) -> Result<Self, ParserError> {
1165        Ok({
1166            let mut jt = JoinType::try_from(token.1)?;
1167            for n in [&n1, &n2].into_iter().flatten() {
1168                jt |= JoinType::try_from(n.0.as_bytes())?;
1169            }
1170            if (jt & (JoinType::INNER | JoinType::OUTER)) == (JoinType::INNER | JoinType::OUTER)
1171                || (jt & (JoinType::OUTER | JoinType::LEFT | JoinType::RIGHT)) == JoinType::OUTER
1172            {
1173                return Err(custom_err!(
1174                    "unknown join type: {} {} {}",
1175                    str::from_utf8(token.1).unwrap_or("invalid utf8"),
1176                    n1.as_ref().map_or("", |n| n.0),
1177                    n2.as_ref().map_or("", |n| n.0)
1178                ));
1179            }
1180            Self::TypedJoin(Some(jt))
1181        })
1182    }
1183    fn is_natural(&self) -> bool {
1184        match self {
1185            Self::TypedJoin(Some(jt)) => jt.contains(JoinType::NATURAL),
1186            _ => false,
1187        }
1188    }
1189}
1190
1191// https://github.com/sqlite/sqlite/blob/80511f32f7e71062026edd471913ef0455563964/src/select.c#L197-L257
1192bitflags::bitflags! {
1193    /// `JOIN` types
1194    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1195    #[cfg_attr(feature = "serde", derive(Serialize))]
1196    pub struct JoinType: u8 {
1197        /// `INNER`
1198        const INNER   = 0x01;
1199        /// `CROSS` => INNER|CROSS
1200        const CROSS   = 0x02;
1201        /// `NATURAL`
1202        const NATURAL = 0x04;
1203        /// `LEFT` => LEFT|OUTER
1204        const LEFT    = 0x08;
1205        /// `RIGHT` => RIGHT|OUTER
1206        const RIGHT   = 0x10;
1207        /// `OUTER`
1208        const OUTER   = 0x20;
1209    }
1210}
1211
1212impl TryFrom<&[u8]> for JoinType {
1213    type Error = ParserError;
1214    fn try_from(s: &[u8]) -> Result<Self, ParserError> {
1215        if b"CROSS".eq_ignore_ascii_case(s) {
1216            Ok(Self::INNER | Self::CROSS)
1217        } else if b"FULL".eq_ignore_ascii_case(s) {
1218            Ok(Self::LEFT | Self::RIGHT | Self::OUTER)
1219        } else if b"INNER".eq_ignore_ascii_case(s) {
1220            Ok(Self::INNER)
1221        } else if b"LEFT".eq_ignore_ascii_case(s) {
1222            Ok(Self::LEFT | Self::OUTER)
1223        } else if b"NATURAL".eq_ignore_ascii_case(s) {
1224            Ok(Self::NATURAL)
1225        } else if b"RIGHT".eq_ignore_ascii_case(s) {
1226            Ok(Self::RIGHT | Self::OUTER)
1227        } else if b"OUTER".eq_ignore_ascii_case(s) {
1228            Ok(Self::OUTER)
1229        } else {
1230            Err(custom_err!(
1231                "unknown join type: {}",
1232                str::from_utf8(s).unwrap_or("invalid utf8")
1233            ))
1234        }
1235    }
1236}
1237
1238/// `JOIN` constraint
1239#[derive(Debug, PartialEq, Eq)]
1240#[cfg_attr(feature = "serde", derive(Serialize))]
1241pub enum JoinConstraint<'bump> {
1242    /// `ON`
1243    On(Expr<'bump>),
1244    /// `USING`: col names
1245    Using(DistinctNames<'bump>),
1246}
1247
1248/// identifier or one of several keywords or `INDEXED`
1249#[derive(Clone, Debug, PartialEq, Eq)]
1250#[cfg_attr(feature = "serde", derive(Serialize))]
1251pub struct Id<'bump>(pub &'bump str);
1252
1253impl<'bump> Id<'bump> {
1254    /// Constructor
1255    pub fn from_token(ty: YYCODETYPE, token: Token, b: &'bump Bump) -> Self {
1256        Self(from_token(ty, token, b))
1257    }
1258}
1259
1260// TODO ids (identifier or string)
1261
1262/// identifier or string or `CROSS` or `FULL` or `INNER` or `LEFT` or `NATURAL` or `OUTER` or `RIGHT`.
1263#[derive(Clone, Debug, Eq)]
1264#[cfg_attr(feature = "serde", derive(Serialize))]
1265pub struct Name<'bump>(pub &'bump str); // TODO distinction between Name and "Name"/[Name]/`Name`
1266
1267pub(crate) fn unquote(s: &str) -> (&str, u8) {
1268    if s.is_empty() {
1269        return (s, 0);
1270    }
1271    let bytes = s.as_bytes();
1272    let mut quote = bytes[0];
1273    if quote != b'"' && quote != b'`' && quote != b'\'' && quote != b'[' {
1274        return (s, 0);
1275    } else if quote == b'[' {
1276        quote = b']';
1277    }
1278    debug_assert!(bytes.len() > 1);
1279    debug_assert_eq!(quote, bytes[bytes.len() - 1]);
1280    let sub = &s[1..bytes.len() - 1];
1281    if quote == b']' || sub.len() < 2 {
1282        (sub, 0)
1283    } else {
1284        (sub, quote)
1285    }
1286}
1287
1288impl<'bump> Name<'bump> {
1289    /// Constructor
1290    pub fn from_token(ty: YYCODETYPE, token: Token, b: &'bump Bump) -> Self {
1291        Self(from_token(ty, token, b))
1292    }
1293
1294    fn as_bytes(&self) -> QuotedIterator<'_> {
1295        let (sub, quote) = unquote(self.0);
1296        QuotedIterator(sub.bytes(), quote)
1297    }
1298    #[cfg(feature = "extra_checks")]
1299    fn is_reserved(&self) -> bool {
1300        let bytes = self.as_bytes();
1301        let reserved = QuotedIterator("sqlite_".bytes(), 0);
1302        bytes.zip(reserved).fold(0u8, |acc, (b1, b2)| {
1303            acc + if b1.eq_ignore_ascii_case(&b2) { 1 } else { 0 }
1304        }) == 7u8
1305    }
1306}
1307
1308struct QuotedIterator<'s>(Bytes<'s>, u8);
1309impl Iterator for QuotedIterator<'_> {
1310    type Item = u8;
1311
1312    fn next(&mut self) -> Option<u8> {
1313        match self.0.next() {
1314            x @ Some(b) => {
1315                if b == self.1 && self.0.next() != Some(self.1) {
1316                    panic!("Malformed string literal: {:?}", self.0);
1317                }
1318                x
1319            }
1320            x => x,
1321        }
1322    }
1323
1324    fn size_hint(&self) -> (usize, Option<usize>) {
1325        if self.1 == 0 {
1326            return self.0.size_hint();
1327        }
1328        (0, None)
1329    }
1330}
1331
1332fn eq_ignore_case_and_quote(mut it: QuotedIterator<'_>, mut other: QuotedIterator<'_>) -> bool {
1333    loop {
1334        match (it.next(), other.next()) {
1335            (Some(b1), Some(b2)) => {
1336                if !b1.eq_ignore_ascii_case(&b2) {
1337                    return false;
1338                }
1339            }
1340            (None, None) => break,
1341            _ => return false,
1342        }
1343    }
1344    true
1345}
1346
1347/// Ignore case and quote
1348impl<'bump> std::hash::Hash for Name<'bump> {
1349    fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
1350        self.as_bytes()
1351            .for_each(|b| hasher.write_u8(b.to_ascii_lowercase()));
1352    }
1353}
1354/// Ignore case and quote
1355impl<'bump> PartialEq for Name<'bump> {
1356    fn eq(&self, other: &Self) -> bool {
1357        eq_ignore_case_and_quote(self.as_bytes(), other.as_bytes())
1358    }
1359}
1360/// Ignore case and quote
1361impl<'bump> PartialEq<str> for Name<'bump> {
1362    fn eq(&self, other: &str) -> bool {
1363        eq_ignore_case_and_quote(self.as_bytes(), QuotedIterator(other.bytes(), 0u8))
1364    }
1365}
1366/// Ignore case and quote
1367impl<'bump> PartialEq<&str> for Name<'bump> {
1368    fn eq(&self, other: &&str) -> bool {
1369        eq_ignore_case_and_quote(self.as_bytes(), QuotedIterator(other.bytes(), 0u8))
1370    }
1371}
1372
1373/// Qualified name
1374#[derive(Debug, PartialEq, Eq)]
1375#[cfg_attr(feature = "serde", derive(Serialize))]
1376pub struct QualifiedName<'bump> {
1377    /// schema
1378    pub db_name: Option<Name<'bump>>,
1379    /// object name
1380    pub name: Name<'bump>,
1381    /// alias
1382    pub alias: Option<Name<'bump>>, // FIXME restrict alias usage (fullname vs xfullname)
1383}
1384
1385impl<'bump> QualifiedName<'bump> {
1386    /// Constructor
1387    pub fn single(name: Name<'bump>) -> Self {
1388        Self {
1389            db_name: None,
1390            name,
1391            alias: None,
1392        }
1393    }
1394    /// Constructor
1395    pub fn fullname(db_name: Name<'bump>, name: Name<'bump>) -> Self {
1396        Self {
1397            db_name: Some(db_name),
1398            name,
1399            alias: None,
1400        }
1401    }
1402    /// Constructor
1403    pub fn xfullname(db_name: Name<'bump>, name: Name<'bump>, alias: Name<'bump>) -> Self {
1404        Self {
1405            db_name: Some(db_name),
1406            name,
1407            alias: Some(alias),
1408        }
1409    }
1410    /// Constructor
1411    pub fn alias(name: Name<'bump>, alias: Name<'bump>) -> Self {
1412        Self {
1413            db_name: None,
1414            name,
1415            alias: Some(alias),
1416        }
1417    }
1418}
1419
1420/// Ordered set of distinct column names
1421#[derive(Debug, PartialEq, Eq)]
1422#[cfg_attr(feature = "serde", derive(Serialize))]
1423pub struct DistinctNames<'bump>(Vec<'bump, Name<'bump>>);
1424
1425impl<'bump> DistinctNames<'bump> {
1426    /// Initialize
1427    pub fn new(name: Name<'bump>, bump: &'bump Bump) -> Self {
1428        let mut dn = Self(Vec::new_in(bump));
1429        dn.0.push(name);
1430        dn
1431    }
1432    /// Single column name
1433    pub fn single(name: Name<'bump>, bump: &'bump Bump) -> Self {
1434        let mut dn = Self(Vec::with_capacity_in(1, bump));
1435        dn.0.push(name);
1436        dn
1437    }
1438    /// Push a distinct name or fail
1439    pub fn insert(&mut self, name: Name<'bump>) -> Result<(), ParserError> {
1440        if self.0.contains(&name) {
1441            return Err(custom_err!("column \"{}\" specified more than once", name));
1442        }
1443        self.0.push(name);
1444        Ok(())
1445    }
1446}
1447impl<'bump> Deref for DistinctNames<'bump> {
1448    type Target = Vec<'bump, Name<'bump>>;
1449
1450    fn deref(&self) -> &Vec<'bump, Name<'bump>> {
1451        &self.0
1452    }
1453}
1454
1455/// `ALTER TABLE` body
1456// https://sqlite.org/lang_altertable.html
1457#[derive(Debug, PartialEq, Eq)]
1458#[cfg_attr(feature = "serde", derive(Serialize))]
1459pub enum AlterTableBody<'bump> {
1460    /// `RENAME TO`: new table name
1461    RenameTo(Name<'bump>),
1462    /// `ADD COLUMN`
1463    AddColumn(ColumnDefinition<'bump>), // TODO distinction between ADD and ADD COLUMN
1464    /// `ALTER COLUMN _ DROP NOT NULL`
1465    DropColumnNotNull(Name<'bump>), // TODO distinction between ALTER and ALTER COLUMN
1466    /// `ALTER COLUMN _ SET NOT NULL`
1467    SetColumnNotNull(Name<'bump>, Option<ResolveType>), // TODO distinction between ALTER and ALTER COLUMN
1468    /// `RENAME COLUMN`
1469    RenameColumn {
1470        /// old name
1471        old: Name<'bump>,
1472        /// new name
1473        new: Name<'bump>,
1474    },
1475    /// `DROP COLUMN`
1476    DropColumn(Name<'bump>), // TODO distinction between DROP and DROP COLUMN
1477    /// `ADD CONSTRAINT`
1478    AddConstraint(NamedTableConstraint<'bump>), // TODO only CHECK constraint supported
1479    /// `DROP CONSTRAINT`
1480    DropConstraint(Name<'bump>),
1481}
1482
1483bitflags::bitflags! {
1484    /// `CREATE TABLE` flags
1485    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1486    #[cfg_attr(feature = "serde", derive(Serialize))]
1487    pub struct TabFlags: u32 {
1488        //const TF_Readonly = 0x00000001; // Read-only system table
1489        /// Has one or more hidden columns
1490        const HasHidden = 0x00000002;
1491        /// Table has a primary key
1492        const HasPrimaryKey = 0x00000004;
1493        /// Integer primary key is autoincrement
1494        const Autoincrement = 0x00000008;
1495        //const TF_HasStat1 = 0x00000010; // nRowLogEst set from sqlite_stat1
1496        /// Has one or more VIRTUAL columns
1497        const HasVirtual = 0x00000020;
1498        /// Has one or more STORED columns
1499        const HasStored = 0x00000040;
1500        /// Combo: HasVirtual + HasStored
1501        const HasGenerated = 0x00000060;
1502        /// No rowid. PRIMARY KEY is the key
1503        const WithoutRowid = 0x00000080;
1504        //const TF_MaybeReanalyze = 0x00000100; // Maybe run ANALYZE on this table
1505        // No user-visible "rowid" column
1506        //const NoVisibleRowid = 0x00000200;
1507        // Out-of-Order hidden columns
1508        //const OOOHidden = 0x00000400;
1509        /// Contains NOT NULL constraints
1510        const HasNotNull = 0x00000800;
1511        //const Shadow = 0x00001000; // True for a shadow table
1512        //const TF_HasStat4 = 0x00002000; // STAT4 info available for this table
1513        //const Ephemeral = 0x00004000; // An ephemeral table
1514        //const TF_Eponymous = 0x00008000; // An eponymous virtual table
1515        /// STRICT mode
1516        const Strict = 0x00010000;
1517    }
1518}
1519
1520/// `CREATE TABLE` body
1521// https://sqlite.org/lang_createtable.html
1522// https://sqlite.org/syntax/create-table-stmt.html
1523#[derive(Debug, PartialEq, Eq)]
1524#[cfg_attr(feature = "serde", derive(Serialize))]
1525pub enum CreateTableBody<'bump> {
1526    /// columns and constraints
1527    ColumnsAndConstraints {
1528        /// table column definitions
1529        columns: Vec<'bump, ColumnDefinition<'bump>>,
1530        /// table constraints
1531        constraints: Option<&'bump [NamedTableConstraint<'bump>]>,
1532        /// table flags
1533        flags: TabFlags,
1534    },
1535    /// `AS` select
1536    AsSelect(&'bump Select<'bump>),
1537}
1538
1539impl<'bump> CreateTableBody<'bump> {
1540    /// Constructor
1541    pub fn columns_and_constraints(
1542        columns: Vec<'bump, ColumnDefinition<'bump>>,
1543        constraints: Option<Vec<'bump, NamedTableConstraint<'bump>>>,
1544        mut flags: TabFlags,
1545    ) -> Result<Self, ParserError> {
1546        for col in &columns {
1547            if col.flags.contains(ColFlags::PRIMKEY) {
1548                flags |= TabFlags::HasPrimaryKey;
1549            }
1550        }
1551        if let Some(ref constraints) = constraints {
1552            for c in constraints {
1553                if let NamedTableConstraint {
1554                    constraint: TableConstraint::PrimaryKey { .. },
1555                    ..
1556                } = c
1557                {
1558                    if flags.contains(TabFlags::HasPrimaryKey) {
1559                        // FIXME table name
1560                        #[cfg(feature = "extra_checks")]
1561                        return Err(custom_err!("table has more than one primary key"));
1562                    } else {
1563                        flags |= TabFlags::HasPrimaryKey;
1564                    }
1565                }
1566            }
1567        }
1568        Ok(Self::ColumnsAndConstraints {
1569            columns,
1570            constraints: constraints.map(|cs| cs.into_bump_slice()),
1571            flags,
1572        })
1573    }
1574}
1575
1576bitflags::bitflags! {
1577    /// Column definition flags
1578    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1579    #[cfg_attr(feature = "serde", derive(Serialize))]
1580    pub struct ColFlags: u16 {
1581        /// Column is part of the primary key
1582        const PRIMKEY = 0x0001;
1583        // A hidden column in a virtual table
1584        //const HIDDEN = 0x0002;
1585        /// Type name follows column name
1586        const HASTYPE = 0x0004;
1587        /// Column def contains "UNIQUE" or "PK"
1588        const UNIQUE = 0x0008;
1589        //const SORTERREF =  0x0010;   /* Use sorter-refs with this column */
1590        /// GENERATED ALWAYS AS ... VIRTUAL
1591        const VIRTUAL = 0x0020;
1592        /// GENERATED ALWAYS AS ... STORED
1593        const STORED = 0x0040;
1594        //const NOTAVAIL = 0x0080;   /* STORED column not yet calculated */
1595        //const BUSY = 0x0100; /* Blocks recursion on GENERATED columns */
1596        /// Has collating sequence name in zCnName
1597        const HASCOLL = 0x0200;
1598        //const NOEXPAND = 0x0400;   /* Omit this column when expanding "*" */
1599        /// Combo: STORED, VIRTUAL
1600        const GENERATED = Self::STORED.bits() | Self::VIRTUAL.bits();
1601        // Combo: HIDDEN, STORED, VIRTUAL
1602        //const NOINSERT = Self::HIDDEN.bits() | Self::STORED.bits() | Self::VIRTUAL.bits();
1603    }
1604}
1605
1606/// Table column definition
1607// https://sqlite.org/syntax/column-def.html
1608#[derive(Debug, PartialEq, Eq)]
1609#[cfg_attr(feature = "serde", derive(Serialize))]
1610pub struct ColumnDefinition<'bump> {
1611    /// column name
1612    pub col_name: Name<'bump>,
1613    /// column type
1614    pub col_type: Option<Type<'bump>>,
1615    /// column constraints
1616    pub constraints: &'bump [NamedColumnConstraint<'bump>],
1617    /// column flags
1618    pub flags: ColFlags,
1619}
1620
1621impl<'bump> ColumnDefinition<'bump> {
1622    /// Constructor
1623    pub fn new(
1624        col_name: Name<'bump>,
1625        mut col_type: Option<Type<'bump>>,
1626        constraints: Vec<'bump, NamedColumnConstraint<'bump>>,
1627        b: &'bump Bump,
1628    ) -> Result<Self, ParserError> {
1629        let mut flags = ColFlags::empty();
1630        #[allow(unused_variables)]
1631        let mut default = false;
1632        for constraint in &constraints {
1633            match &constraint.constraint {
1634                #[allow(unused_assignments)]
1635                ColumnConstraint::Default(..) => {
1636                    default = true;
1637                }
1638                ColumnConstraint::Collate { .. } => {
1639                    flags |= ColFlags::HASCOLL;
1640                }
1641                ColumnConstraint::Generated { typ, .. } => {
1642                    flags |= ColFlags::VIRTUAL;
1643                    if let Some(id) = typ {
1644                        if id.0.eq_ignore_ascii_case("STORED") {
1645                            flags |= ColFlags::STORED;
1646                        }
1647                    }
1648                }
1649                #[cfg(feature = "extra_checks")]
1650                ColumnConstraint::ForeignKey {
1651                    clause:
1652                        ForeignKeyClause {
1653                            tbl_name, columns, ..
1654                        },
1655                    ..
1656                } => {
1657                    // The child table may reference the primary key of the parent without specifying the primary key column
1658                    if columns.as_ref().map_or(0, |cs| cs.len()) > 1 {
1659                        return Err(custom_err!(
1660                            "foreign key on {} should reference only one column of table {}",
1661                            col_name,
1662                            tbl_name
1663                        ));
1664                    }
1665                }
1666                #[allow(unused_variables)]
1667                ColumnConstraint::PrimaryKey { auto_increment, .. } => {
1668                    #[cfg(feature = "extra_checks")]
1669                    if *auto_increment
1670                        && col_type
1671                            .as_ref()
1672                            .is_none_or(|t| !unquote(t.name).0.eq_ignore_ascii_case("INTEGER"))
1673                    {
1674                        return Err(custom_err!(
1675                            "AUTOINCREMENT is only allowed on an INTEGER PRIMARY KEY"
1676                        ));
1677                    }
1678                    flags |= ColFlags::PRIMKEY | ColFlags::UNIQUE;
1679                }
1680                ColumnConstraint::Unique(..) => {
1681                    flags |= ColFlags::UNIQUE;
1682                }
1683                _ => {}
1684            }
1685        }
1686        #[cfg(feature = "extra_checks")]
1687        if flags.contains(ColFlags::PRIMKEY) && flags.intersects(ColFlags::GENERATED) {
1688            return Err(custom_err!(
1689                "generated columns cannot be part of the PRIMARY KEY"
1690            ));
1691        } else if default && flags.intersects(ColFlags::GENERATED) {
1692            return Err(custom_err!("cannot use DEFAULT on a generated column"));
1693        }
1694        if flags.intersects(ColFlags::GENERATED) {
1695            // https://github.com/sqlite/sqlite/blob/e452bf40a14aca57fd9047b330dff282f3e4bbcc/src/build.c#L1511-L1514
1696            if let Some(ref mut col_type) = col_type {
1697                let mut split = col_type.name.split_ascii_whitespace();
1698                if split
1699                    .next_back()
1700                    .is_some_and(|s| s.eq_ignore_ascii_case("ALWAYS"))
1701                    && split
1702                        .next_back()
1703                        .is_some_and(|s| s.eq_ignore_ascii_case("GENERATED"))
1704                {
1705                    // str_split_whitespace_remainder
1706                    let mut new_type = bumpalo::collections::String::new_in(b);
1707                    for (i, item) in split.enumerate() {
1708                        if i > 0 {
1709                            new_type.push(' ');
1710                        }
1711                        new_type.push_str(item);
1712                    }
1713                    col_type.name = new_type.into_bump_str();
1714                }
1715            }
1716            if col_type.as_ref().is_some_and(|ct| ct.name.is_empty()) {
1717                col_type = None;
1718            }
1719        }
1720        if col_type.as_ref().is_some_and(|t| !t.name.is_empty()) {
1721            flags |= ColFlags::HASTYPE;
1722        }
1723        Ok(Self {
1724            col_name,
1725            col_type,
1726            constraints: constraints.into_bump_slice(),
1727            flags,
1728        })
1729    }
1730    /// Collector
1731    pub fn add_column(columns: &mut Vec<'bump, Self>, cd: Self) -> Result<(), ParserError> {
1732        if columns.iter().any(|c| c.col_name == cd.col_name) {
1733            return Err(custom_err!("duplicate column name: {}", cd.col_name));
1734        } else if cd.flags.contains(ColFlags::PRIMKEY)
1735            && columns.iter().any(|c| c.flags.contains(ColFlags::PRIMKEY))
1736        {
1737            #[cfg(feature = "extra_checks")]
1738            return Err(custom_err!("table has more than one primary key")); // FIXME table name
1739        }
1740        columns.push(cd);
1741        Ok(())
1742    }
1743}
1744
1745/// Named column constraint
1746// https://sqlite.org/syntax/column-constraint.html
1747#[derive(Debug, PartialEq, Eq)]
1748#[cfg_attr(feature = "serde", derive(Serialize))]
1749pub struct NamedColumnConstraint<'bump> {
1750    /// constraint name
1751    pub name: Option<Name<'bump>>,
1752    /// constraint
1753    pub constraint: ColumnConstraint<'bump>,
1754}
1755
1756/// Column constraint
1757// https://sqlite.org/syntax/column-constraint.html
1758#[derive(Debug, PartialEq, Eq)]
1759#[cfg_attr(feature = "serde", derive(Serialize))]
1760pub enum ColumnConstraint<'bump> {
1761    /// `PRIMARY KEY`
1762    PrimaryKey {
1763        /// `ASC` / `DESC`
1764        order: Option<SortOrder>,
1765        /// `ON CONFLICT` clause
1766        conflict_clause: Option<ResolveType>,
1767        /// `AUTOINCREMENT`
1768        auto_increment: bool,
1769    },
1770    /// `NULL`
1771    NotNull {
1772        /// `NOT`
1773        nullable: bool,
1774        /// `ON CONFLICT` clause
1775        conflict_clause: Option<ResolveType>,
1776    },
1777    /// `UNIQUE`
1778    Unique(Option<ResolveType>),
1779    /// `CHECK`
1780    Check(Expr<'bump>),
1781    /// `DEFAULT`
1782    Default(Expr<'bump>),
1783    /// `DEFERRABLE`
1784    Defer(DeferSubclause), // FIXME
1785    /// `COLLATE`
1786    Collate {
1787        /// collation name
1788        collation_name: Name<'bump>, // FIXME Ids
1789    },
1790    /// `REFERENCES` foreign-key clause
1791    ForeignKey {
1792        /// clause
1793        clause: ForeignKeyClause<'bump>,
1794        /// `DEFERRABLE`
1795        defer_clause: Option<DeferSubclause>,
1796    },
1797    /// `GENERATED`
1798    Generated {
1799        /// expression
1800        expr: Expr<'bump>,
1801        /// `STORED` / `VIRTUAL`
1802        typ: Option<Id<'bump>>,
1803    },
1804}
1805
1806/// Named table constraint
1807// https://sqlite.org/syntax/table-constraint.html
1808#[derive(Debug, PartialEq, Eq)]
1809#[cfg_attr(feature = "serde", derive(Serialize))]
1810pub struct NamedTableConstraint<'bump> {
1811    /// constraint name
1812    pub name: Option<Name<'bump>>,
1813    /// constraint
1814    pub constraint: TableConstraint<'bump>,
1815}
1816
1817/// Table constraint
1818// https://sqlite.org/syntax/table-constraint.html
1819#[derive(Debug, PartialEq, Eq)]
1820#[cfg_attr(feature = "serde", derive(Serialize))]
1821pub enum TableConstraint<'bump> {
1822    /// `PRIMARY KEY`
1823    PrimaryKey {
1824        /// columns
1825        columns: &'bump [SortedColumn<'bump>],
1826        /// `AUTOINCREMENT`
1827        auto_increment: bool,
1828        /// `ON CONFLICT` clause
1829        conflict_clause: Option<ResolveType>,
1830    },
1831    /// `UNIQUE`
1832    Unique {
1833        /// columns
1834        columns: &'bump [SortedColumn<'bump>],
1835        /// `ON CONFLICT` clause
1836        conflict_clause: Option<ResolveType>,
1837    },
1838    /// `CHECK`
1839    Check(Expr<'bump>, Option<ResolveType>),
1840    /// `FOREIGN KEY`
1841    ForeignKey {
1842        /// columns
1843        columns: &'bump [IndexedColumn<'bump>],
1844        /// `REFERENCES`
1845        clause: ForeignKeyClause<'bump>,
1846        /// `DEFERRABLE`
1847        defer_clause: Option<DeferSubclause>,
1848    },
1849}
1850
1851impl<'bump> TableConstraint<'bump> {
1852    /// PK constructor
1853    pub fn primary_key(
1854        columns: Vec<'bump, SortedColumn<'bump>>,
1855        auto_increment: bool,
1856        conflict_clause: Option<ResolveType>,
1857    ) -> Result<Self, ParserError> {
1858        has_expression(&columns)?;
1859        has_explicit_nulls(&columns)?;
1860        Ok(Self::PrimaryKey {
1861            columns: columns.into_bump_slice(),
1862            auto_increment,
1863            conflict_clause,
1864        })
1865    }
1866    /// UNIQUE constructor
1867    pub fn unique(
1868        columns: Vec<'bump, SortedColumn<'bump>>,
1869        conflict_clause: Option<ResolveType>,
1870    ) -> Result<Self, ParserError> {
1871        has_expression(&columns)?;
1872        has_explicit_nulls(&columns)?;
1873        Ok(Self::Unique {
1874            columns: columns.into_bump_slice(),
1875            conflict_clause,
1876        })
1877    }
1878}
1879
1880/// Sort orders
1881#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1882#[cfg_attr(feature = "serde", derive(Serialize))]
1883pub enum SortOrder {
1884    /// `ASC`
1885    Asc,
1886    /// `DESC`
1887    Desc,
1888}
1889
1890/// `NULLS FIRST` or `NULLS LAST`
1891#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1892#[cfg_attr(feature = "serde", derive(Serialize))]
1893pub enum NullsOrder {
1894    /// `NULLS FIRST`
1895    First,
1896    /// `NULLS LAST`
1897    Last,
1898}
1899
1900/// `REFERENCES` clause
1901// https://sqlite.org/syntax/foreign-key-clause.html
1902#[derive(Debug, PartialEq, Eq)]
1903#[cfg_attr(feature = "serde", derive(Serialize))]
1904pub struct ForeignKeyClause<'bump> {
1905    /// foreign table name
1906    pub tbl_name: Name<'bump>,
1907    /// foreign table columns
1908    pub columns: Option<&'bump [IndexedColumn<'bump>]>,
1909    /// referential action(s) / deferrable option(s)
1910    pub args: &'bump [RefArg<'bump>],
1911}
1912
1913impl<'bump> ForeignKeyClause<'bump> {
1914    /// Constructor
1915    pub fn new(
1916        tbl_name: Name<'bump>,
1917        columns: Option<Vec<'bump, IndexedColumn<'bump>>>,
1918        args: Vec<'bump, RefArg<'bump>>,
1919    ) -> Self {
1920        ForeignKeyClause {
1921            tbl_name,
1922            columns: columns.map(|cs| cs.into_bump_slice()),
1923            args: args.into_bump_slice(),
1924        }
1925    }
1926}
1927
1928/// foreign-key reference args
1929#[derive(Debug, PartialEq, Eq)]
1930#[cfg_attr(feature = "serde", derive(Serialize))]
1931pub enum RefArg<'bump> {
1932    /// `ON DELETE`
1933    OnDelete(RefAct),
1934    /// `ON INSERT`
1935    OnInsert(RefAct),
1936    /// `ON UPDATE`
1937    OnUpdate(RefAct),
1938    /// `MATCH`
1939    Match(Name<'bump>),
1940}
1941
1942/// foreign-key reference actions
1943#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1944#[cfg_attr(feature = "serde", derive(Serialize))]
1945pub enum RefAct {
1946    /// `SET NULL`
1947    SetNull,
1948    /// `SET DEFAULT`
1949    SetDefault,
1950    /// `CASCADE`
1951    Cascade,
1952    /// `RESTRICT`
1953    Restrict,
1954    /// `NO ACTION`
1955    NoAction,
1956}
1957
1958/// foreign-key defer clause
1959#[derive(Clone, Debug, PartialEq, Eq)]
1960#[cfg_attr(feature = "serde", derive(Serialize))]
1961pub struct DeferSubclause {
1962    /// `DEFERRABLE`
1963    pub deferrable: bool,
1964    /// `INITIALLY` `DEFERRED` / `IMMEDIATE`
1965    pub init_deferred: Option<InitDeferredPred>,
1966}
1967
1968/// `INITIALLY` `DEFERRED` / `IMMEDIATE`
1969#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1970#[cfg_attr(feature = "serde", derive(Serialize))]
1971pub enum InitDeferredPred {
1972    /// `INITIALLY DEFERRED`
1973    InitiallyDeferred,
1974    /// `INITIALLY IMMEDIATE`
1975    InitiallyImmediate, // default
1976}
1977
1978/// Indexed column
1979// https://sqlite.org/syntax/indexed-column.html
1980#[derive(Debug, PartialEq, Eq)]
1981#[cfg_attr(feature = "serde", derive(Serialize))]
1982pub struct IndexedColumn<'bump> {
1983    /// column name
1984    pub col_name: Name<'bump>,
1985    /// `COLLATE`
1986    pub collation_name: Option<Name<'bump>>, // FIXME Ids
1987    /// `ORDER BY`
1988    pub order: Option<SortOrder>,
1989}
1990
1991/// `INDEXED BY` / `NOT INDEXED`
1992#[derive(Debug, PartialEq, Eq)]
1993#[cfg_attr(feature = "serde", derive(Serialize))]
1994pub enum Indexed<'bump> {
1995    /// `INDEXED BY`: idx name
1996    IndexedBy(Name<'bump>),
1997    /// `NOT INDEXED`
1998    NotIndexed,
1999}
2000
2001/// Sorted column
2002#[derive(Debug, PartialEq, Eq)]
2003#[cfg_attr(feature = "serde", derive(Serialize))]
2004pub struct SortedColumn<'bump> {
2005    /// expression
2006    pub expr: Expr<'bump>,
2007    /// `ASC` / `DESC`
2008    pub order: Option<SortOrder>,
2009    /// `NULLS FIRST` / `NULLS LAST`
2010    pub nulls: Option<NullsOrder>,
2011}
2012
2013fn has_expression(columns: &Vec<SortedColumn>) -> Result<(), ParserError> {
2014    for _column in columns {
2015        if false {
2016            return Err(custom_err!(
2017                "expressions prohibited in PRIMARY KEY and UNIQUE constraints"
2018            ));
2019        }
2020    }
2021    Ok(())
2022}
2023#[allow(unused_variables)]
2024fn has_explicit_nulls(columns: &[SortedColumn]) -> Result<(), ParserError> {
2025    #[cfg(feature = "extra_checks")]
2026    for column in columns {
2027        if let Some(ref nulls) = column.nulls {
2028            return Err(custom_err!(
2029                "unsupported use of NULLS {}",
2030                if *nulls == NullsOrder::First {
2031                    "FIRST"
2032                } else {
2033                    "LAST"
2034                }
2035            ));
2036        }
2037    }
2038    Ok(())
2039}
2040
2041/// `LIMIT`
2042#[derive(Debug, PartialEq, Eq)]
2043#[cfg_attr(feature = "serde", derive(Serialize))]
2044pub struct Limit<'bump> {
2045    /// count
2046    pub expr: Expr<'bump>,
2047    /// `OFFSET`
2048    pub offset: Option<Expr<'bump>>, // TODO distinction between LIMIT offset, count and LIMIT count OFFSET offset
2049}
2050
2051/// `INSERT` body
2052// https://sqlite.org/lang_insert.html
2053// https://sqlite.org/syntax/insert-stmt.html
2054#[derive(Debug, PartialEq, Eq)]
2055#[cfg_attr(feature = "serde", derive(Serialize))]
2056pub enum InsertBody<'bump> {
2057    /// `SELECT` or `VALUES`
2058    Select(&'bump Select<'bump>, Option<&'bump Upsert<'bump>>),
2059    /// `DEFAULT VALUES`
2060    DefaultValues,
2061}
2062
2063/// `UPDATE ... SET`
2064#[derive(Debug, PartialEq, Eq)]
2065#[cfg_attr(feature = "serde", derive(Serialize))]
2066pub struct Set<'bump> {
2067    /// column name(s)
2068    pub col_names: DistinctNames<'bump>,
2069    /// expression
2070    pub expr: Expr<'bump>,
2071}
2072
2073/// `PRAGMA` body
2074// https://sqlite.org/syntax/pragma-stmt.html
2075#[derive(Debug, PartialEq, Eq)]
2076#[cfg_attr(feature = "serde", derive(Serialize))]
2077pub enum PragmaBody<'bump> {
2078    /// `=`
2079    Equals(PragmaValue<'bump>),
2080    /// function call
2081    Call(PragmaValue<'bump>),
2082}
2083
2084/// `PRAGMA` value
2085// https://sqlite.org/syntax/pragma-value.html
2086pub type PragmaValue<'bump> = Expr<'bump>; // TODO
2087
2088/// `CREATE TRIGGER` time
2089#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2090#[cfg_attr(feature = "serde", derive(Serialize))]
2091pub enum TriggerTime {
2092    /// `BEFORE`
2093    Before, // default
2094    /// `AFTER`
2095    After,
2096    /// `INSTEAD OF`
2097    InsteadOf,
2098}
2099
2100/// `CREATE TRIGGER` event
2101#[derive(Debug, PartialEq, Eq)]
2102#[cfg_attr(feature = "serde", derive(Serialize))]
2103pub enum TriggerEvent<'bump> {
2104    /// `DELETE`
2105    Delete,
2106    /// `INSERT`
2107    Insert,
2108    /// `UPDATE`
2109    Update,
2110    /// `UPDATE OF`: col names
2111    UpdateOf(DistinctNames<'bump>),
2112}
2113
2114/// `CREATE TRIGGER` command
2115// https://sqlite.org/lang_createtrigger.html
2116// https://sqlite.org/syntax/create-trigger-stmt.html
2117#[derive(Debug, PartialEq, Eq)]
2118#[cfg_attr(feature = "serde", derive(Serialize))]
2119pub enum TriggerCmd<'bump> {
2120    /// `UPDATE`
2121    Update {
2122        /// `OR`
2123        or_conflict: Option<ResolveType>,
2124        /// table name
2125        tbl_name: QualifiedName<'bump>,
2126        /// `SET` assignments
2127        sets: &'bump [Set<'bump>], // FIXME unique
2128        /// `FROM`
2129        from: Option<FromClause<'bump>>,
2130        /// `WHERE` clause
2131        where_clause: Option<Expr<'bump>>,
2132    },
2133    /// `INSERT`
2134    Insert {
2135        /// `OR`
2136        or_conflict: Option<ResolveType>,
2137        /// table name
2138        tbl_name: QualifiedName<'bump>,
2139        /// `COLUMNS`
2140        col_names: Option<DistinctNames<'bump>>,
2141        /// `SELECT` or `VALUES`
2142        select: &'bump Select<'bump>,
2143        /// `ON CONFLICT` clause
2144        upsert: Option<&'bump Upsert<'bump>>,
2145    },
2146    /// `DELETE`
2147    Delete {
2148        /// table name
2149        tbl_name: QualifiedName<'bump>,
2150        /// `WHERE` clause
2151        where_clause: Option<Expr<'bump>>,
2152    },
2153    /// `SELECT`
2154    Select(&'bump Select<'bump>),
2155}
2156
2157/// Conflict resolution types
2158#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2159#[cfg_attr(feature = "serde", derive(Serialize))]
2160pub enum ResolveType {
2161    /// `ROLLBACK`
2162    Rollback,
2163    /// `ABORT`
2164    Abort, // default
2165    /// `FAIL`
2166    Fail,
2167    /// `IGNORE`
2168    Ignore,
2169    /// `REPLACE`
2170    Replace,
2171}
2172
2173/// `WITH` clause
2174// https://sqlite.org/lang_with.html
2175// https://sqlite.org/syntax/with-clause.html
2176#[derive(Debug, PartialEq, Eq)]
2177#[cfg_attr(feature = "serde", derive(Serialize))]
2178pub struct With<'bump> {
2179    /// `RECURSIVE`
2180    pub recursive: bool,
2181    /// CTEs
2182    pub ctes: &'bump [CommonTableExpr<'bump>],
2183}
2184
2185/// CTE materialization
2186#[derive(Clone, Debug, PartialEq, Eq)]
2187#[cfg_attr(feature = "serde", derive(Serialize))]
2188pub enum Materialized {
2189    /// No hint
2190    Any,
2191    /// `MATERIALIZED`
2192    Yes,
2193    /// `NOT MATERIALIZED`
2194    No,
2195}
2196
2197/// CTE
2198// https://sqlite.org/syntax/common-table-expression.html
2199#[derive(Debug, PartialEq, Eq)]
2200#[cfg_attr(feature = "serde", derive(Serialize))]
2201pub struct CommonTableExpr<'bump> {
2202    /// table name
2203    pub tbl_name: Name<'bump>,
2204    /// table columns
2205    pub columns: Option<&'bump [IndexedColumn<'bump>]>, // TODO: check no duplicate (eidlist_opt)
2206    /// `MATERIALIZED`
2207    pub materialized: Materialized,
2208    /// query
2209    pub select: &'bump Select<'bump>,
2210}
2211
2212impl<'bump> CommonTableExpr<'bump> {
2213    /// Constructor
2214    pub fn new(
2215        tbl_name: Name<'bump>,
2216        columns: Option<Vec<'bump, IndexedColumn<'bump>>>,
2217        materialized: Materialized,
2218        select: Select<'bump>,
2219        b: &'bump Bump,
2220    ) -> Result<Self, ParserError> {
2221        #[cfg(feature = "extra_checks")]
2222        if let Some(ref columns) = columns {
2223            if let check::ColumnCount::Fixed(cc) = select.column_count() {
2224                if cc as usize != columns.len() {
2225                    return Err(custom_err!(
2226                        "table {} has {} values for {} columns",
2227                        tbl_name,
2228                        cc,
2229                        columns.len()
2230                    ));
2231                }
2232            }
2233        }
2234        Ok(Self {
2235            tbl_name,
2236            columns: columns.map(|cs| cs.into_bump_slice()),
2237            materialized,
2238            select: b.alloc(select),
2239        })
2240    }
2241    /// Constructor
2242    pub fn add_cte(ctes: &mut Vec<Self>, cte: Self) -> Result<(), ParserError> {
2243        #[cfg(feature = "extra_checks")]
2244        if ctes.iter().any(|c| c.tbl_name == cte.tbl_name) {
2245            return Err(custom_err!("duplicate WITH table name: {}", cte.tbl_name));
2246        }
2247        ctes.push(cte);
2248        Ok(())
2249    }
2250}
2251
2252/// Column type
2253// https://sqlite.org/syntax/type-name.html
2254#[derive(Debug, PartialEq, Eq)]
2255#[cfg_attr(feature = "serde", derive(Serialize))]
2256pub struct Type<'bump> {
2257    /// type name
2258    pub name: &'bump str, // TODO Validate: Ids+
2259    /// type size
2260    pub size: Option<TypeSize<'bump>>,
2261}
2262
2263/// Column type size limit(s)
2264// https://sqlite.org/syntax/type-name.html
2265#[derive(Debug, PartialEq, Eq)]
2266#[cfg_attr(feature = "serde", derive(Serialize))]
2267pub enum TypeSize<'bump> {
2268    /// maximum size
2269    MaxSize(&'bump Expr<'bump>),
2270    /// precision
2271    TypeSize(&'bump Expr<'bump>, &'bump Expr<'bump>),
2272}
2273
2274/// Transaction types
2275#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2276#[cfg_attr(feature = "serde", derive(Serialize))]
2277pub enum TransactionType {
2278    /// `DEFERRED`
2279    Deferred, // default
2280    /// `IMMEDIATE`
2281    Immediate,
2282    /// `EXCLUSIVE`
2283    Exclusive,
2284}
2285
2286/// Upsert clause
2287// https://sqlite.org/lang_upsert.html
2288// https://sqlite.org/syntax/upsert-clause.html
2289#[derive(Debug, PartialEq, Eq)]
2290#[cfg_attr(feature = "serde", derive(Serialize))]
2291pub struct Upsert<'bump> {
2292    /// conflict targets
2293    pub index: Option<UpsertIndex<'bump>>,
2294    /// `DO` clause
2295    pub do_clause: UpsertDo<'bump>,
2296    /// next upsert
2297    pub next: Option<&'bump Upsert<'bump>>,
2298}
2299
2300/// Upsert conflict targets
2301#[derive(Debug, PartialEq, Eq)]
2302#[cfg_attr(feature = "serde", derive(Serialize))]
2303pub struct UpsertIndex<'bump> {
2304    /// columns
2305    pub targets: &'bump [SortedColumn<'bump>],
2306    /// `WHERE` clause
2307    pub where_clause: Option<Expr<'bump>>,
2308}
2309
2310impl<'bump> UpsertIndex<'bump> {
2311    /// constructor
2312    pub fn new(
2313        targets: Vec<'bump, SortedColumn<'bump>>,
2314        where_clause: Option<Expr<'bump>>,
2315    ) -> Result<Self, ParserError> {
2316        has_explicit_nulls(&targets)?;
2317        Ok(Self {
2318            targets: targets.into_bump_slice(),
2319            where_clause,
2320        })
2321    }
2322}
2323
2324/// Upsert `DO` action
2325#[derive(Debug, PartialEq, Eq)]
2326#[cfg_attr(feature = "serde", derive(Serialize))]
2327pub enum UpsertDo<'bump> {
2328    /// `SET`
2329    Set {
2330        /// assignments
2331        sets: &'bump [Set<'bump>],
2332        /// `WHERE` clause
2333        where_clause: Option<Expr<'bump>>,
2334    },
2335    /// `NOTHING`
2336    Nothing,
2337}
2338
2339/// Function call tail
2340#[derive(Debug, PartialEq, Eq)]
2341#[cfg_attr(feature = "serde", derive(Serialize))]
2342pub struct FunctionTail<'bump> {
2343    /// `FILTER` clause
2344    pub filter_clause: Option<&'bump Expr<'bump>>,
2345    /// `OVER` clause
2346    pub over_clause: Option<&'bump Over<'bump>>,
2347}
2348
2349/// Function call `OVER` clause
2350// https://sqlite.org/syntax/over-clause.html
2351#[derive(Debug, PartialEq, Eq)]
2352#[cfg_attr(feature = "serde", derive(Serialize))]
2353pub enum Over<'bump> {
2354    /// Window definition
2355    Window(&'bump Window<'bump>),
2356    /// Window name
2357    Name(Name<'bump>),
2358}
2359
2360/// `OVER` window definition
2361#[derive(Debug, PartialEq, Eq)]
2362#[cfg_attr(feature = "serde", derive(Serialize))]
2363pub struct WindowDef<'bump> {
2364    /// window name
2365    pub name: Name<'bump>,
2366    /// window definition
2367    pub window: Window<'bump>,
2368}
2369
2370/// Window definition
2371// https://sqlite.org/syntax/window-defn.html
2372#[derive(Debug, PartialEq, Eq)]
2373#[cfg_attr(feature = "serde", derive(Serialize))]
2374pub struct Window<'bump> {
2375    /// base window name
2376    pub base: Option<Name<'bump>>,
2377    /// `PARTITION BY`
2378    pub partition_by: Option<&'bump [Expr<'bump>]>,
2379    /// `ORDER BY`
2380    pub order_by: Option<&'bump [SortedColumn<'bump>]>,
2381    /// frame spec
2382    pub frame_clause: Option<FrameClause<'bump>>,
2383}
2384
2385impl<'bump> Window<'bump> {
2386    /// Constructor
2387    pub fn new(
2388        base: Option<Name<'bump>>,
2389        partition_by: Option<Vec<'bump, Expr<'bump>>>,
2390        order_by: Option<Vec<'bump, SortedColumn<'bump>>>,
2391        frame_clause: Option<FrameClause<'bump>>,
2392    ) -> Self {
2393        Self {
2394            base,
2395            partition_by: partition_by.map(|pb| pb.into_bump_slice()),
2396            order_by: order_by.map(|ob| ob.into_bump_slice()),
2397            frame_clause,
2398        }
2399    }
2400}
2401
2402/// Frame specification
2403// https://sqlite.org/syntax/frame-spec.html
2404#[derive(Debug, PartialEq, Eq)]
2405#[cfg_attr(feature = "serde", derive(Serialize))]
2406pub struct FrameClause<'bump> {
2407    /// unit
2408    pub mode: FrameMode,
2409    /// start bound
2410    pub start: FrameBound<'bump>,
2411    /// end bound
2412    pub end: Option<FrameBound<'bump>>,
2413    /// `EXCLUDE`
2414    pub exclude: Option<FrameExclude>,
2415}
2416
2417/// Frame modes
2418#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2419#[cfg_attr(feature = "serde", derive(Serialize))]
2420pub enum FrameMode {
2421    /// `GROUPS`
2422    Groups,
2423    /// `RANGE`
2424    Range,
2425    /// `ROWS`
2426    Rows,
2427}
2428
2429/// Frame bounds
2430#[derive(Debug, PartialEq, Eq)]
2431#[cfg_attr(feature = "serde", derive(Serialize))]
2432pub enum FrameBound<'bump> {
2433    /// `CURRENT ROW`
2434    CurrentRow,
2435    /// `FOLLOWING`
2436    Following(Expr<'bump>),
2437    /// `PRECEDING`
2438    Preceding(Expr<'bump>),
2439    /// `UNBOUNDED FOLLOWING`
2440    UnboundedFollowing,
2441    /// `UNBOUNDED PRECEDING`
2442    UnboundedPreceding,
2443}
2444
2445/// Frame exclusions
2446#[derive(Clone, Debug, PartialEq, Eq)]
2447#[cfg_attr(feature = "serde", derive(Serialize))]
2448pub enum FrameExclude {
2449    /// `NO OTHERS`
2450    NoOthers,
2451    /// `CURRENT ROW`
2452    CurrentRow,
2453    /// `GROUP`
2454    Group,
2455    /// `TIES`
2456    Ties,
2457}
2458
2459#[cfg(test)]
2460mod test {
2461    use super::Name;
2462
2463    #[test]
2464    fn test_dequote() {
2465        let b = bumpalo::Bump::new();
2466        assert_eq!(name("x", &b), "x");
2467        assert_eq!(name("`x`", &b), "x");
2468        assert_eq!(name("`x``y`", &b), "x`y");
2469        assert_eq!(name(r#""x""#, &b), "x");
2470        assert_eq!(name(r#""x""y""#, &b), "x\"y");
2471        assert_eq!(name("[x]", &b), "x");
2472    }
2473
2474    fn name<'bump>(s: &'static str, b: &'bump bumpalo::Bump) -> Name<'bump> {
2475        Name(b.alloc_str(s))
2476    }
2477}