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