Skip to main content

inillucent_sql/
dml.rs

1//! Binding INSERT, UPDATE and DELETE.
2//!
3//! Invariant: a bound DML statement names every value it will write, in table
4//! column order, before anything is compiled. A column the statement did not
5//! mention is not left to be filled in later by whoever runs it - it carries
6//! its `DEFAULT`, or a NULL, as an expression like any other. That is what
7//! makes `INSERT INTO t(b) VALUES(1)` and `INSERT INTO t VALUES(NULL, 1)`
8//! compile to the same shape, and it is why the constraint checks can be
9//! written once against a row image rather than twice against two.
10//!
11//! Constraints are bound here too, out of the `CREATE TABLE` text the file
12//! stores. The catalog keeps them as source, because the catalog sits below
13//! the binder and cannot bind anything; the binder parses that source against
14//! the table it belongs to and gets an ordinary expression back. A CHECK is
15//! therefore evaluated by exactly the machinery that evaluates a WHERE clause,
16//! which is the only way to be sure the two agree about what `x > 0` means
17//! when `x` is text.
18
19use inillucent_base::limits::Limits;
20use inillucent_value::Collation;
21
22use crate::ast::{self, ConflictAction};
23use crate::bind::{
24    no_such_column, refused, unsupported, Binder, BoundExpr, BoundOrderTerm, BoundResultColumn,
25    BoundSelect, BoundSource,
26};
27use crate::catalog_view::{IndexInfo, TableInfo, TableKind, TriggerEventInfo, TriggerInfo};
28use crate::diagnostic::ParseError;
29use crate::lexer::Span;
30use crate::parser::parse_expression;
31
32/// The internal tables an application may write, as SQLite allows.
33///
34/// **Four, and two of them are the schema.** Every table whose
35/// name begins with `sqlite_` used to be refused, which is wrong for all four,
36/// because writing them is the documented way to use them:
37///
38/// - `sqlite_schema`, and `sqlite_master` which is its other name, are what
39///   `PRAGMA writable_schema` is for, and `.dump` emits
40///   `INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)VALUES(...)`
41///   for a virtual table - which is the only way a dump can restore one
42///   without building empty shadow tables over the ones it is about to fill
43///   (task-1979, R2). Whether the pragma is on is the *engine's* question and
44///   not the binder's: `ImportedDatabase::refuse_schema_write` refuses the
45///   statement when it is off, the way `refuse_shadow_write` refuses a write a
46///   defensive connection may not make.
47///
48/// - `sqlite_sequence` holds one row per `AUTOINCREMENT` table, and
49///   `UPDATE sqlite_sequence SET seq = 0 WHERE name = 't'` is how the counter is
50///   reset. `DELETE FROM sqlite_sequence` is how it is reset for every table at
51///   once. Refusing them left no way at all to do either.
52/// - `sqlite_stat1` is what `ANALYZE` writes, and `.dump` emits
53///   `INSERT INTO sqlite_stat1 VALUES(...)` for it - so a dump this engine
54///   produced could not be replayed into it.
55///
56/// They are ordinary tables in every other respect: the rows are what they are,
57/// and a value written into one is used exactly as `ANALYZE` or the rowid
58/// allocator would have used the one it replaced.
59const WRITABLE_INTERNAL: [&[u8]; 4] = [
60    b"sqlite_sequence",
61    b"sqlite_stat1",
62    b"sqlite_schema",
63    b"sqlite_master",
64];
65
66/// Where one column's value comes from in an INSERT.
67#[derive(Clone, Debug, PartialEq)]
68pub enum ColumnSource {
69    /// The value at this position of the source row.
70    Row(usize),
71    /// An expression evaluated once per row, which is what a `DEFAULT` is.
72    Expr(BoundExpr),
73    /// A generated column, computed from the rest of the row rather than from
74    /// anything the statement supplied.
75    ///
76    /// It is its own variant because it is evaluated at a different *time*: a
77    /// `DEFAULT` is a value like any other, while a generated column reads the
78    /// row it is part of and so cannot be computed until the rest of it is.
79    Generated(BoundExpr),
80}
81
82/// What an INSERT inserts.
83#[derive(Clone, Debug, PartialEq)]
84pub enum BoundInsertSource {
85    /// Literal rows, each already bound.
86    Values(Vec<Vec<BoundExpr>>),
87    /// A query, whose result columns feed the target columns in order.
88    Select(Box<BoundSelect>),
89}
90
91/// One `CHECK` constraint, bound against its table.
92#[derive(Clone, Debug, PartialEq)]
93pub struct BoundCheck {
94    /// The constraint's name, when it was written with one.
95    pub name: Option<Vec<u8>>,
96    /// The predicate.
97    pub expr: BoundExpr,
98}
99
100/// A `NOT NULL` column's `DEFAULT`, bound so a `REPLACE` can stand it in.
101///
102/// **REPLACE's rule for a `NOT NULL` violation is to substitute the column's
103/// default, and to fall back to `ABORT` only when there is no default.** So
104/// `UPDATE OR REPLACE t SET c = NULL` on `c TEXT NOT NULL DEFAULT 'd'` stores
105/// `'d'`, and this engine used to refuse the statement instead.
106///
107/// The write path cannot bind one for itself: a default is schema text, and by
108/// the time a row is being checked the parser is long out of scope. The binder
109/// already binds one for every column a statement *omits*; these are the same
110/// expressions bound for the columns it supplies, which is where a NULL that
111/// needs replacing can come from.
112///
113/// Only the columns that can need it are here - `NOT NULL` and with a default -
114/// so an ordinary table carries an empty vector and the write path skips the
115/// whole apparatus.
116#[derive(Clone, Debug, PartialEq)]
117pub struct BoundDefault {
118    /// The column the default belongs to.
119    pub column: u16,
120    /// The default expression, bound.
121    pub expr: BoundExpr,
122}
123
124/// A `VIRTUAL` generated column whose value a write has to look at.
125///
126/// A virtual column is in no record, so the row a write builds does not hold
127/// it. `NOT NULL` and a `STRICT` table's type check test the value that would be
128/// read back, which has to be computed from the row. Only the columns that
129/// declare one of those are here, so a table with no such column carries an
130/// empty vector and the write path does nothing extra.
131#[derive(Clone, Debug, PartialEq)]
132pub struct BoundVirtualColumn {
133    /// The column, by declared position.
134    pub column: u16,
135    /// The column's value as it is read: the expression, converted by the
136    /// column's affinity.
137    pub expr: BoundExpr,
138}
139
140/// The expressions one index needs evaluated per row to be maintained.
141///
142/// **An index is usually just columns of the row, and then it needs none of
143/// this.** A partial index holds only the rows its predicate accepts, and an
144/// index on an expression holds a value no column carries - so for those two,
145/// maintaining the index means evaluating something per row rather than
146/// copying a slot. They travel on the bound statement for the same reason the
147/// table's `CHECK` predicates do: the binder is what can turn schema text into
148/// a `BoundExpr`, and the write path is what runs it.
149///
150/// The list holds only the indexes that need it, so a table with neither kind
151/// leaves it empty and the write path's loop runs zero times - which is every
152/// table the gate measures.
153#[derive(Clone, Debug, PartialEq)]
154pub struct BoundIndexExprs {
155    /// The index's position in the table's `indexes`.
156    pub position: usize,
157    /// The partial-index predicate, when it has one.
158    pub predicate: Option<BoundExpr>,
159    /// One per key column: the expression it indexes, or `None` for a column.
160    pub keys: Vec<Option<BoundExpr>>,
161}
162
163/// One statement of a trigger body, bound.
164///
165/// The four the grammar allows and no more. A trigger body is not a general
166/// statement list: it cannot create objects, cannot open transactions, and
167/// cannot return rows to the caller, so a variant for anything else would be a
168/// shape the binder is required to refuse.
169#[derive(Clone, Debug, PartialEq)]
170pub enum BoundTriggerStatement {
171    /// `INSERT`.
172    Insert(Box<BoundInsert>),
173    /// `UPDATE`.
174    Update(Box<BoundUpdate>),
175    /// `DELETE`.
176    Delete(Box<BoundDelete>),
177    /// `SELECT`, which a body runs for its side effects - in practice for the
178    /// `RAISE()` inside it.
179    Select(Box<BoundSelect>),
180}
181
182/// A trigger, bound against the write that fires it.
183///
184/// It is bound per statement rather than once per schema because the body's
185/// FROM terms take statement-wide source numbers, and those only exist relative
186/// to the statement they are inlined into.
187#[derive(Clone, Debug, PartialEq)]
188pub struct BoundTrigger {
189    /// The trigger's name, for the diagnostic when its body fails.
190    pub name: Vec<u8>,
191    /// The folded name of the table it is attached to.
192    ///
193    /// Read by the executor to decide whether a body statement is writing the
194    /// trigger's *own* table, which is what `PRAGMA recursive_triggers` is
195    /// about: with it on, such a write fires this trigger again.
196    pub table: Vec<u8>,
197    /// Whether it fires before or after the row is written.
198    pub time: ast::TriggerTime,
199    /// The `WHEN` guard, when one was written.
200    pub when: Option<BoundExpr>,
201    /// The body statements, in written order.
202    pub body: Vec<BoundTriggerStatement>,
203    /// Whether the binder synthesised this from a `REFERENCES` clause rather
204    /// than reading it from a `CREATE TRIGGER`.
205    ///
206    /// **Read by `DROP TABLE` (task-1979, F6).** Dropping a table with foreign
207    /// keys on runs an implicit `DELETE FROM` first, so the keys that reference
208    /// it are enforced - and SQLite's rule is that the implicit delete fires no
209    /// triggers of its own while still performing every foreign key action. A
210    /// delete bound for that purpose keeps the triggers this flag marks and
211    /// drops the rest.
212    pub foreign_key: bool,
213    /// Whether the foreign key this enforces has one table as both its child
214    /// and its parent.
215    ///
216    /// **Also read by `DROP TABLE` (task-1979, F6).** The implicit delete keeps
217    /// the foreign key triggers and drops this one, because emptying a table
218    /// cannot leave a row of that same table pointing at nothing - see
219    /// `ForeignKeyTrigger::self_referencing`, which is where the value comes
220    /// from. Always false on a trigger the schema wrote.
221    pub self_referencing: bool,
222}
223
224/// A bound `INSERT`.
225#[derive(Clone, Debug, PartialEq)]
226pub struct BoundInsert {
227    /// The table being written, shared with the catalog it came from.
228    pub table: std::rc::Rc<TableInfo>,
229    /// The statement-wide number of the FROM term being written.
230    ///
231    /// It used to be implicitly zero, because a DML statement had exactly one
232    /// source. A trigger body is compiled into the statement that fires it, so
233    /// its target takes the next number after the firing statement's - and a
234    /// compiler that assumed zero read the wrong cursor for every fire after
235    /// the first.
236    pub target_source: usize,
237    /// Where each table column's value comes from, in column order.
238    pub columns: Vec<ColumnSource>,
239    /// Where the rowid comes from, when the statement supplies one.
240    pub rowid: Option<ColumnSource>,
241    /// Which value of the supplied row is the rowid, when the statement named
242    /// it outright.
243    ///
244    /// `INSERT INTO t(rowid, a) VALUES (7, 'x')` is legal on any rowid table,
245    /// including one with no `INTEGER PRIMARY KEY` to alias it and including a
246    /// virtual table. It is recorded separately from `rowid` because it is not
247    /// a column: nothing writes it into the record.
248    pub named_rowid: Option<usize>,
249    /// The rows.
250    pub source: BoundInsertSource,
251    /// How many values each source row supplies.
252    pub arity: usize,
253    /// The statement's conflict algorithm, when it wrote one.
254    pub on_conflict: Option<ConflictAction>,
255    /// The table's `CHECK` constraints.
256    pub checks: Vec<BoundCheck>,
257    /// The `DEFAULT`s a `REPLACE` may stand in for a NULL, by column.
258    pub not_null_defaults: Vec<BoundDefault>,
259    /// The virtual generated columns the row has to satisfy.
260    pub virtual_columns: Vec<BoundVirtualColumn>,
261    /// The expressions the table's partial and expression indexes need.
262    pub index_exprs: Vec<BoundIndexExprs>,
263    /// The `ON CONFLICT ... DO UPDATE` clause, when there is one.
264    pub upsert: Vec<BoundUpsert>,
265    /// `sqlite_sequence`'s root page, when the target is `AUTOINCREMENT`.
266    ///
267    /// Resolved here rather than in the compiler because it is a fact about the
268    /// catalog, and the catalog is what the binder holds. It is zero for every
269    /// other table, which is also what it reads as before the first
270    /// `AUTOINCREMENT` table in a database is created.
271    pub sequence_root: u32,
272    /// The `RETURNING` columns.
273    pub returning: Vec<BoundResultColumn>,
274    /// The triggers this write fires, in schema order.
275    pub triggers: Vec<BoundTrigger>,
276    /// The foreign-key actions a `REPLACE` fires for the row it removes.
277    ///
278    /// A `REPLACE` that deletes a row to make room for another is a delete,
279    /// and the keys pointing at that row have to be told. Written `DELETE`
280    /// triggers are *not* fired - that is SQLite's rule with its default
281    /// `recursive_triggers = off` - so these are only the ones a key implies.
282    pub replace_triggers: Vec<BoundTrigger>,
283}
284
285/// The constraint an `ON CONFLICT` clause names.
286///
287/// **An index by position, not a set of columns.** A table may hold a partial
288/// unique index and a plain one over the same columns, or two expression
289/// indexes over the same column, and a conflict target picks exactly one of
290/// them. Comparing column sets could not tell them apart, so the clause that
291/// matched was the first one that happened to share the columns.
292#[derive(Clone, Copy, Debug, PartialEq, Eq)]
293pub enum UpsertConstraint {
294    /// No target was written, so the clause answers a conflict on any constraint.
295    Any,
296    /// The table's own key: the rowid, or the primary key of a `WITHOUT ROWID` table.
297    OwnKey,
298    /// The unique index at this position in `TableInfo::indexes`.
299    Index(usize),
300}
301
302/// A bound `ON CONFLICT ... DO UPDATE` clause.
303#[derive(Clone, Debug, PartialEq)]
304pub struct BoundUpsert {
305    /// The constraint the clause's conflict target names.
306    pub constraint: UpsertConstraint,
307    /// The assignments, or empty for `DO NOTHING`.
308    pub assignments: Vec<BoundAssignment>,
309    /// Whether the action is `DO UPDATE`.
310    pub do_update: bool,
311    /// The `WHERE` on the `DO UPDATE`.
312    pub filter: Option<BoundExpr>,
313    /// The `UPDATE` triggers the clause fires, and the foreign key checks an
314    /// update of the assigned columns needs. Empty for `DO NOTHING`.
315    pub triggers: Vec<BoundTrigger>,
316}
317
318/// One `SET` assignment.
319#[derive(Clone, Debug, PartialEq)]
320pub struct BoundAssignment {
321    /// The column being assigned, as a declared position.
322    pub column: u16,
323    /// Whether the assignment names the row's own rowid rather than a declared
324    /// column, in which case `column` says nothing.
325    ///
326    /// **`UPDATE t SET rowid = 100` was `no such column: rowid` (task-1979,
327    /// F9).** An assignment target was looked up with `column_position`, which
328    /// only knows the columns the table declares, and a table with no INTEGER
329    /// PRIMARY KEY declares none for its rowid. SQLite accepts all three
330    /// spellings of the rowid on either kind of table and moves the row to the
331    /// new key.
332    pub rowid: bool,
333    /// The new value.
334    pub value: BoundExpr,
335}
336
337/// A bound `UPDATE`.
338#[derive(Clone, Debug, PartialEq)]
339pub struct BoundUpdate {
340    /// The table being written, shared with the catalog it came from.
341    pub table: std::rc::Rc<TableInfo>,
342    /// The schema the statement wrote before the target's name, when it wrote one and no alias.
343    /// `EXPLAIN QUERY PLAN` repeats it.
344    pub written_schema: Option<Vec<u8>>,
345    /// The statement-wide number of the FROM term being written.
346    ///
347    /// It used to be implicitly zero, because a DML statement had exactly one
348    /// source. A trigger body is compiled into the statement that fires it, so
349    /// its target takes the next number after the firing statement's - and a
350    /// compiler that assumed zero read the wrong cursor for every fire after
351    /// the first.
352    pub source: usize,
353    /// The extra FROM terms of an `UPDATE ... FROM`, in written order.
354    ///
355    /// **The rows being updated come from a join.** `UPDATE t SET v = s.v FROM s
356    /// WHERE s.a = t.a` is the shape a migration writes to copy a column across
357    /// tables, and the values it assigns are not expressions over the target
358    /// row: they read a *different* row, one the join found. So the query that
359    /// finds the keys carries these terms too, and projects the assigned values
360    /// beside the key; see [`BoundUpdate::from`], which is this field.
361    ///
362    /// Empty for every ordinary `UPDATE`, which is what keeps the wider row off
363    /// the path the gate's `txn.large` measures.
364    pub from: Vec<crate::bind::BoundSource>,
365    /// The assignments, in table column order with duplicates already refused.
366    pub assignments: Vec<BoundAssignment>,
367    /// The `STORED` generated columns, recomputed after the assignments.
368    ///
369    /// **A stored generated column is part of the row, so a row that is
370    /// rewritten rewrites it (task-1913).** It is never named in a `SET`, so
371    /// an `UPDATE` used to leave whatever was written when the row was
372    /// inserted: `c GENERATED ALWAYS AS (a + 1) STORED` still read 2 after
373    /// `UPDATE g SET a = 5`, where SQLite reads 6. The wrong value is on the
374    /// disk rather than in an answer, so a later read of the same file is
375    /// wrong too, and an index on the column indexes the stale value.
376    ///
377    /// A `VIRTUAL` column is not here: it has no slot in the record and is
378    /// computed when it is read, which is why only this half needed fixing.
379    ///
380    /// These are evaluated against the row *after* the assignments, which is
381    /// the one difference from [`BoundUpdate::assignments`] - those read the
382    /// before image so `SET a = b, b = a` swaps.
383    pub generated: Vec<BoundAssignment>,
384    /// The `WHERE` clause.
385    pub filter: Option<BoundExpr>,
386    /// The statement's conflict algorithm, when it wrote one.
387    pub on_conflict: Option<ConflictAction>,
388    /// The table's `CHECK` constraints.
389    pub checks: Vec<BoundCheck>,
390    /// The `DEFAULT`s a `REPLACE` may stand in for a NULL, by column.
391    pub not_null_defaults: Vec<BoundDefault>,
392    /// The virtual generated columns the row has to satisfy.
393    pub virtual_columns: Vec<BoundVirtualColumn>,
394    /// The expressions the table's partial and expression indexes need.
395    pub index_exprs: Vec<BoundIndexExprs>,
396    /// `INDEXED BY` or `NOT INDEXED` on the target, which the query that finds
397    /// the rows to change obeys; `inillucent_exec::dml::hint_target` puts it there.
398    pub index_hint: crate::bind::IndexChoice,
399    /// The `RETURNING` columns.
400    pub returning: Vec<BoundResultColumn>,
401    /// The `ORDER BY` that decides which rows a `LIMIT` keeps.
402    ///
403    /// Empty unless the statement wrote one, and then always with a `LIMIT`,
404    /// because the binder refuses an order with nothing to limit. It goes onto
405    /// the query that finds the rows to change, which is where SQLite puts it
406    /// too: a limited write is `WHERE rowid IN (SELECT rowid ... ORDER BY ...
407    /// LIMIT ...)` there.
408    pub order_by: Vec<BoundOrderTerm>,
409    /// The `LIMIT`.
410    pub limit: Option<BoundExpr>,
411    /// The `OFFSET`.
412    pub offset: Option<BoundExpr>,
413    /// The triggers this write fires, in schema order.
414    pub triggers: Vec<BoundTrigger>,
415    /// The triggers a row removed by `UPDATE OR REPLACE` fires, as
416    /// [`BoundInsert::replace_triggers`] describes.
417    pub replace_triggers: Vec<BoundTrigger>,
418    /// The rows to fire an `INSTEAD OF` trigger for, when the target is a view.
419    ///
420    /// A view has no rows of its own, so `OLD` has to come from running the
421    /// view. This is that query, with the statement's `WHERE` on it and one
422    /// result column per view column.
423    pub view_rows: Option<Box<BoundSelect>>,
424}
425
426/// A bound `DELETE`.
427#[derive(Clone, Debug, PartialEq)]
428pub struct BoundDelete {
429    /// The table being written, shared with the catalog it came from.
430    pub table: std::rc::Rc<TableInfo>,
431    /// The schema the statement wrote before the target's name, when it wrote one and no alias.
432    /// `EXPLAIN QUERY PLAN` repeats it.
433    pub written_schema: Option<Vec<u8>>,
434    /// The expressions the table's partial and expression indexes need.
435    ///
436    /// A delete needs them too: an entry only comes out of a partial index if
437    /// the row was in it, and a key the index computed has to be recomputed to
438    /// be found.
439    pub index_exprs: Vec<BoundIndexExprs>,
440    /// `INDEXED BY` or `NOT INDEXED` on the target, as on [`BoundUpdate`].
441    pub index_hint: crate::bind::IndexChoice,
442    /// The statement-wide number of the FROM term being written.
443    ///
444    /// It used to be implicitly zero, because a DML statement had exactly one
445    /// source. A trigger body is compiled into the statement that fires it, so
446    /// its target takes the next number after the firing statement's - and a
447    /// compiler that assumed zero read the wrong cursor for every fire after
448    /// the first.
449    pub source: usize,
450    /// The `WHERE` clause.
451    pub filter: Option<BoundExpr>,
452    /// The `RETURNING` columns.
453    pub returning: Vec<BoundResultColumn>,
454    /// The `ORDER BY` that decides which rows a `LIMIT` keeps.
455    ///
456    /// Empty unless the statement wrote one, and then always with a `LIMIT`,
457    /// because the binder refuses an order with nothing to limit. It goes onto
458    /// the query that finds the rows to change, which is where SQLite puts it
459    /// too: a limited write is `WHERE rowid IN (SELECT rowid ... ORDER BY ...
460    /// LIMIT ...)` there.
461    pub order_by: Vec<BoundOrderTerm>,
462    /// The `LIMIT`.
463    pub limit: Option<BoundExpr>,
464    /// The `OFFSET`.
465    pub offset: Option<BoundExpr>,
466    /// The triggers this write fires, in schema order.
467    pub triggers: Vec<BoundTrigger>,
468    /// The rows to fire an `INSTEAD OF` trigger for, when the target is a view.
469    pub view_rows: Option<Box<BoundSelect>>,
470}
471
472/// Reports whether an `INSERT` can resolve a conflict by deleting a row.
473///
474/// Either the statement said so, or one of the table's own constraints did.
475/// It is asked before the delete's keys are bound, because binding them costs
476/// a parse and a bind each and the answer is no for almost every insert.
477fn can_replace(table: &TableInfo, statement: Option<ConflictAction>) -> bool {
478    if statement == Some(ConflictAction::Replace) {
479        return true;
480    }
481    table
482        .indexes
483        .iter()
484        .any(|index| index.conflict == Some(ConflictAction::Replace))
485        || table.columns.iter().any(|column| {
486            column.not_null_conflict == Some(ConflictAction::Replace)
487                || column.primary_key_conflict == Some(ConflictAction::Replace)
488        })
489}
490
491/// Reports whether an unusable key's fault is one this write has to report.
492///
493/// A child's write reports a missing parent; a parent's write reports a
494/// mismatch. A statement that touches neither side of the broken key does not
495/// have to care, which is why the fault is carried rather than raised when the
496/// schema was read.
497fn fault_applies(
498    planned: &crate::catalog_view::ForeignKeyTrigger,
499    event: &TriggerEventInfo,
500) -> bool {
501    match event {
502        TriggerEventInfo::Insert => planned.is_check,
503        TriggerEventInfo::Delete => !planned.is_check,
504        TriggerEventInfo::Update(_) => true,
505    }
506}
507
508/// Marks a synthesised body's aborts as the foreign key's rather than a
509/// trigger's.
510///
511/// The generated text says `RAISE(ABORT, ...)` because that is what a person
512/// would have written, and what a person writes reports
513/// `SQLITE_CONSTRAINT_TRIGGER`. A foreign key reports its own code, and the
514/// only difference between the two is which constraint asked - so it is set
515/// here, on the bodies this binder generated, and nowhere else.
516fn report_as_foreign_key(trigger: &mut BoundTrigger) {
517    trigger.foreign_key = true;
518    mark_raises(trigger, true);
519}
520
521/// Sets which code every `RAISE` in a synthesised body reports.
522///
523/// **`ON DELETE RESTRICT` and `ON UPDATE RESTRICT` report the trigger's
524/// code.** SQLite enforces RESTRICT with a trigger program and reports
525/// `SQLITE_CONSTRAINT_TRIGGER` (1811) for it, while a `NO ACTION` key, which
526/// it checks with a counter, reports `SQLITE_CONSTRAINT_FOREIGNKEY` (787).
527/// The message is the same for both.
528///
529/// @param trigger - the bound body
530/// @param foreign_key - whether its aborts report the foreign key's code
531fn mark_raises(trigger: &mut BoundTrigger, foreign_key: bool) {
532    for statement in &mut trigger.body {
533        let BoundTriggerStatement::Select(select) = statement else {
534            continue;
535        };
536        for column in &mut select.columns {
537            if let BoundExpr::Raise {
538                foreign_key: marked,
539                ..
540            } = &mut column.expr
541            {
542                *marked = foreign_key;
543            }
544        }
545    }
546}
547
548/// Returns whether a view has an `INSTEAD OF` trigger for one event.
549///
550/// An `UPDATE` event matches any `INSTEAD OF UPDATE` trigger here, whatever its
551/// `OF` column list says, because the columns the statement assigns are not
552/// known yet when the target is resolved. `check_view_update_columns` applies
553/// the column list once they are.
554///
555/// @param table - the view
556/// @param event - the kind of write
557fn has_instead_of(table: &TableInfo, event: &TriggerEventInfo) -> bool {
558    table.triggers.iter().any(|trigger| {
559        trigger.time == ast::TriggerTime::InsteadOf
560            && matches!(
561                (&trigger.event, event),
562                (TriggerEventInfo::Insert, TriggerEventInfo::Insert)
563                    | (TriggerEventInfo::Delete, TriggerEventInfo::Delete)
564                    | (TriggerEventInfo::Update(_), TriggerEventInfo::Update(_))
565            )
566    })
567}
568
569/// Builds the message SQLite gives for a write to a view with no `INSTEAD OF`
570/// trigger for it.
571///
572/// @param table - the view
573fn view_not_writable(table: &TableInfo) -> ParseError {
574    refused(
575        format!(
576            "cannot modify {} because it is a view",
577            String::from_utf8_lossy(&table.name)
578        ),
579        Span::default(),
580    )
581}
582
583/// Refuses an `UPDATE` of a view when no `INSTEAD OF UPDATE` trigger covers the
584/// columns the statement assigns.
585///
586/// SQLite looks for a trigger whose `OF` list names an assigned column, so
587/// `UPDATE v SET a = 1` is refused when the only trigger is `UPDATE OF b`.
588///
589/// @param table - the target
590/// @param changed - the folded names of the assigned columns
591fn check_view_update_columns(table: &TableInfo, changed: &[Vec<u8>]) -> Result<(), ParseError> {
592    if table.kind != TableKind::View {
593        return Ok(());
594    }
595    let event = TriggerEventInfo::Update(Vec::new());
596    let covered = table
597        .triggers
598        .iter()
599        .any(|t| t.time == ast::TriggerTime::InsteadOf && t.fires_for(&event, changed));
600    if covered {
601        Ok(())
602    } else {
603        Err(view_not_writable(table))
604    }
605}
606
607/// The target position that stands for the rowid rather than a column.
608///
609/// A table cannot have this many columns - SQLite's limit is two thousand - so
610/// there is no position it can collide with, and one sentinel is cheaper than
611/// a parallel `Option` threaded through every target list.
612const ROWID_TARGET: u16 = u16::MAX;
613
614/// Returns whether a name is one of the rowid's three spellings.
615fn is_rowid_name(folded: &[u8]) -> bool {
616    matches!(folded, b"rowid" | b"oid" | b"_rowid_")
617}
618
619/// How deep one write may drive triggers firing other triggers.
620///
621/// SQLite's own limit is `SQLITE_MAX_TRIGGER_DEPTH`, enforced when the frame is
622/// pushed. Trigger bodies are inlined here rather than run as frames, so the
623/// same limit is enforced where the inlining happens - and it has to be, or a
624/// schema in which two triggers write each other's tables would compile until
625/// the compiler ran out of memory.
626///
627/// **This is one number now, and it is the one `.limit` reports.** There used
628/// to be two constants of this name: this one at 32, which was the number
629/// actually enforced, and `inillucent-exec`'s at 1000, checked at run time over
630/// a tree the binder had already capped at 32 - so that check could never fire.
631/// `crates/inillucent-base/manifests/limits.toml` advertised 1000 and
632/// `inillucent diagnose` printed 1000, and a chain of forty distinct triggers
633/// that the oracle ran was refused here (task-1946, H3). The binder reads
634/// `Limit::TriggerDepth` from the connection now, which `.limit trigger_depth`
635/// and the driver both set; this constant is what a binder built without limits
636/// falls back to, and it is the manifest's default.
637pub const MAX_TRIGGER_DEPTH: usize = 1000;
638
639/// How deep one chain of foreign-key actions may go.
640///
641/// A cascade reaches this only when the keys form a cycle, which in practice
642/// means a table whose parent column points at itself. SQLite's own limit is a
643/// run-time recursion depth; this one is a compile-time inlining depth, and it
644/// is smaller for that reason.
645pub const MAX_FOREIGN_KEY_DEPTH: usize = 64;
646
647/// How many foreign-key action bodies one statement may inline in total.
648///
649/// The depth limit alone is not enough: a table with three keys that all cycle
650/// would inline three bodies per level, so the limit that matters is the total.
651/// A chain, which is what a self-referencing tree produces, spends one per
652/// level and reaches the depth limit first.
653pub const MAX_FOREIGN_KEY_STATEMENTS: usize = 256;
654
655impl<'a> Binder<'a> {
656    /// Binds an `INSERT` or `REPLACE`.
657    pub fn bind_insert(&mut self, insert: &ast::Insert) -> Result<BoundInsert, ParseError> {
658        // **A `WITH` on a DML statement is the same `WITH` a `SELECT` has.** The
659        // CTEs are in scope for the whole statement - the source query of an
660        // `INSERT`, the `WHERE` of an `UPDATE` or `DELETE` - and the binder's
661        // CTE stack already handles nesting, so pushing them here is all it
662        // takes. They were refused rather than bound, which is what a migration
663        // script written for SQLite hits first.
664        let pushed = self.push_ctes(&insert.with)?;
665        let bound = self.bind_insert_body(insert);
666        if pushed {
667            self.pop_ctes();
668        }
669        bound
670    }
671
672    /// Returns the failure for an `INSERT` that supplies the wrong number of values.
673    ///
674    /// SQLite words it two ways. With a column list it counts against the list:
675    /// `2 values for 1 columns`. Without one it names the table, as written, with
676    /// the schema when one was written: `table main.u has 2 columns but 1 values
677    /// were supplied`. An alias on the table replaces the name.
678    ///
679    /// @param insert - the statement as written
680    /// @param supplied - how many values the source produces
681    /// @param wanted - how many columns the statement writes
682    fn insert_arity_failure(
683        &self,
684        insert: &ast::Insert,
685        supplied: usize,
686        wanted: usize,
687    ) -> ParseError {
688        if !insert.columns.is_empty() {
689            return refused(
690                format!("{supplied} values for {wanted} columns"),
691                Span::default(),
692            );
693        }
694        let written = self.insert_target_label(insert);
695        refused(
696            format!("table {written} has {wanted} columns but {supplied} values were supplied"),
697            Span::default(),
698        )
699    }
700
701    /// Returns the table as SQLite names it in an `INSERT` failure.
702    ///
703    /// The alias when the statement has one, otherwise the table name as written with
704    /// the schema in front of it when the statement wrote one.
705    ///
706    /// @param insert - the statement as written
707    fn insert_target_label(&self, insert: &ast::Insert) -> String {
708        let name = String::from_utf8_lossy(self.ast.text(insert.table)).into_owned();
709        match (insert.alias, insert.database) {
710            (Some(alias), _) => String::from_utf8_lossy(self.ast.text(alias)).into_owned(),
711            (None, Some(database)) => {
712                format!(
713                    "{}.{name}",
714                    String::from_utf8_lossy(self.ast.text(database))
715                )
716            }
717            (None, None) => name,
718        }
719    }
720
721    /// Binds an `INSERT` with its CTEs already in scope.
722    fn bind_insert_body(&mut self, insert: &ast::Insert) -> Result<BoundInsert, ParseError> {
723        let table = self.writable_target(
724            insert.database,
725            insert.table,
726            Span::default(),
727            &TriggerEventInfo::Insert,
728        )?;
729        let alias = match insert.alias {
730            Some(alias) => self.ast.text(alias).to_vec(),
731            None => table.name.clone(),
732        };
733        let target_source = self.push_write_source(std::rc::Rc::clone(&table), alias);
734        // `DEFAULT VALUES` supplies nothing, so every column takes its default
735        // - which is what an empty target list means here. The grammar does
736        // not allow a column list with it, so there is none to honour.
737        let targets = match insert.source {
738            ast::InsertSource::DefaultValues => Vec::new(),
739            ast::InsertSource::Select(_) => {
740                self.insert_targets(&table, &insert.columns, &self.insert_target_label(insert))?
741            }
742        };
743        let (source, arity) = self.bind_insert_source(&insert.source, &table, &targets)?;
744        if arity != targets.len() {
745            return Err(self.insert_arity_failure(insert, arity, targets.len()));
746        }
747        let (columns, rowid) = self.column_sources(&table, &targets)?;
748        let named_rowid = targets.iter().rposition(|target| *target == ROWID_TARGET);
749        let checks = self.bind_checks(&table)?;
750        let not_null_defaults = self.bind_not_null_defaults(&table)?;
751        let virtual_columns = self.bind_virtual_columns(&table)?;
752        let index_exprs = self.bind_index_exprs(&table)?;
753        let upsert = self.bind_upsert(&table, insert)?;
754        let returning = self.bind_returning(&insert.returning)?;
755        let on_conflict = self.trigger_conflict.or(insert.on_conflict);
756        let mut triggers = self.with_trigger_conflict(on_conflict, |binder| {
757            binder.bind_triggers(&table, TriggerEventInfo::Insert, &[])
758        })?;
759        triggers.extend(self.bind_foreign_keys(&table, TriggerEventInfo::Insert, &[])?);
760        let replace_triggers = self.bind_replace_triggers(&table, insert.on_conflict)?;
761        let sequence_root = if table.autoincrement {
762            self.catalog
763                .find_table(None, b"sqlite_sequence")
764                .map_or(0, |sequence| sequence.root)
765        } else {
766            0
767        };
768        Ok(BoundInsert {
769            table,
770            index_exprs,
771            target_source,
772            columns,
773            rowid,
774            named_rowid,
775            source,
776            arity,
777            on_conflict,
778            checks,
779            not_null_defaults,
780            virtual_columns,
781            upsert,
782            sequence_root,
783            returning,
784            triggers,
785            replace_triggers,
786        })
787    }
788
789    /// Binds the triggers a row removed by `REPLACE` fires.
790    ///
791    /// **Foreign key actions always, written `DELETE` triggers only when
792    /// `recursive_triggers` is on.** SQLite runs the foreign key actions of
793    /// every row a conflict removes, and fires the delete triggers the table
794    /// declares only under that pragma. The pragma is a run time setting, so
795    /// the written triggers are bound here and the executor drops them when it
796    /// is off.
797    ///
798    /// @param table - the table being written
799    /// @param on_conflict - the statement's own conflict clause
800    fn bind_replace_triggers(
801        &mut self,
802        table: &TableInfo,
803        on_conflict: Option<ConflictAction>,
804    ) -> Result<Vec<BoundTrigger>, ParseError> {
805        if !can_replace(table, on_conflict) {
806            return Ok(Vec::new());
807        }
808        let mut bound = self.bind_triggers(table, TriggerEventInfo::Delete, &[])?;
809        bound.extend(self.bind_foreign_keys(table, TriggerEventInfo::Delete, &[])?);
810        Ok(bound)
811    }
812
813    /// Binds an `UPDATE`.
814    pub fn bind_update(&mut self, update: &ast::Update) -> Result<BoundUpdate, ParseError> {
815        let pushed = self.push_ctes(&update.with)?;
816        let bound = self.bind_update_body(update);
817        if pushed {
818            self.pop_ctes();
819        }
820        bound
821    }
822
823    /// Binds an `UPDATE ... FROM` clause, after the target.
824    ///
825    /// Returns the terms the clause adds and the constraints its table-valued
826    /// functions' arguments became, which belong in the statement's `WHERE`.
827    ///
828    /// **A table-valued function's arguments are constraints on its hidden
829    /// columns**, which `bind_table_arguments` leaves for the statement's
830    /// `WHERE`. A `SELECT` adds them there; the `UPDATE` did not, so `UPDATE
831    /// todo SET position = j.key FROM json_each('[3,1,2]') AS j WHERE todo.id =
832    /// j.value` ran `json_each` with no document, found no rows and reported
833    /// success with nothing changed.
834    ///
835    /// **The terms this block owns, not every source bound since.** A derived
836    /// table binds its own inner terms into the same list, and taking
837    /// everything bound after the target made them top level terms of the
838    /// `UPDATE` as well: `FROM (SELECT id, pos FROM ord) AS p` joined `ord`
839    /// again, beside `p`, so every row was found once per row of `ord` and the
840    /// statement reported 9 changes for 3.
841    ///
842    /// @param from - the clause's terms, in written order
843    fn bind_update_from(
844        &mut self,
845        from: &[ast::FromTermId],
846    ) -> Result<(Vec<crate::bind::BoundSource>, Vec<BoundExpr>), ParseError> {
847        let before = self.sources.len();
848        for term in from {
849            self.bind_from_term(*term)?;
850        }
851        self.desugar_join_constraints(from)?;
852        let arguments = core::mem::take(&mut self.pending_constraints);
853        let joined: Vec<crate::bind::BoundSource> = self
854            .scope()
855            .iter()
856            .filter(|id| **id >= before)
857            .filter_map(|id| self.sources.get(*id).cloned())
858            .collect();
859        Ok((joined, arguments))
860    }
861
862    /// Binds an `UPDATE`'s `SET` list into one assignment per column.
863    ///
864    /// @param update - the statement as written
865    /// @param table - the target, whose columns the names resolve against
866    fn bind_update_assignments(
867        &mut self,
868        update: &ast::Update,
869        table: &TableInfo,
870    ) -> Result<Vec<BoundAssignment>, ParseError> {
871        let mut assignments = Vec::new();
872        for (names, value) in &update.assignments {
873            let values = self.assigned_values(names, *value)?;
874            for (name, bound) in names.iter().zip(values) {
875                let folded = self.ast.folded(*name).to_vec();
876                // `rowid`, `oid` and `_rowid_` name the row's key rather than a
877                // declared column, unless the table declares a column by one of
878                // those names - which is what `is_rowid_name` decides.
879                if table.is_rowid_name(&folded) {
880                    // **The last assignment to a column wins.** SQLite accepts
881                    // `SET a = 1, a = 2` and stores 2; it does not refuse the
882                    // repeat.
883                    assignments.retain(|held: &BoundAssignment| !held.rowid);
884                    assignments.push(BoundAssignment {
885                        column: 0,
886                        rowid: true,
887                        value: bound.clone(),
888                    });
889                    continue;
890                }
891                let Some(position) = table.column_position(&folded) else {
892                    return Err(no_such_column(self.ast.text(*name), Span::default()));
893                };
894                // **An assignment to a generated column is refused, not
895                // ignored (task-1913).** SQLite answers `cannot UPDATE
896                // generated column "c"`; this accepted the statement, reported
897                // it as a success, and wrote nothing the caller asked for -
898                // either the record took the value and the column stopped
899                // agreeing with its own expression, or the recompute above put
900                // it back and the assignment was silently dropped. `INSERT`
901                // already refused the same thing.
902                self.refuse_generated(table, position, "UPDATE", Span::default())?;
903                assignments.retain(|existing: &BoundAssignment| {
904                    existing.rowid || existing.column != position
905                });
906                assignments.push(BoundAssignment {
907                    column: position,
908                    rowid: false,
909                    value: bound.clone(),
910                });
911            }
912        }
913        // The rowid assignment sorts with the declared columns rather than
914        // ahead of them, because `column` says nothing for it and the order
915        // only has to be stable.
916        assignments.sort_by_key(|assignment| (assignment.rowid, assignment.column));
917        Ok(assignments)
918    }
919
920    /// Binds an `UPDATE` with its CTEs already in scope.
921    fn bind_update_body(&mut self, update: &ast::Update) -> Result<BoundUpdate, ParseError> {
922        if let Some(refusal) = order_without_limit(update.limited_at, update.limit, "UPDATE") {
923            return Err(refusal);
924        }
925        let (table, source) =
926            self.write_target_from_term(update.target, &TriggerEventInfo::Update(Vec::new()))?;
927        refuse_module_returning(&table, &update.returning, "UPDATE")?;
928        // **The `FROM` terms are bound after the target**, so the target keeps
929        // the lowest source number and every reference to an unqualified column
930        // resolves to it first - which is SQLite's rule and the reason
931        // `UPDATE t SET v = v + 1 FROM s` means the target's `v`.
932        let (joined, arguments) = self.bind_update_from(&update.from)?;
933        let assignments = self.bind_update_assignments(update, &table)?;
934        let mut filter = match update.filter {
935            Some(expr) => Some(self.bind_expr(expr)?),
936            None => None,
937        };
938        for constraint in arguments {
939            filter = Some(match filter.take() {
940                Some(existing) => BoundExpr::And(Box::new(existing), Box::new(constraint)),
941                None => constraint,
942            });
943        }
944        // **The schema's expressions see the target and nothing else.** A
945        // partial index's `WHERE a IS NOT NULL`, a `CHECK` and a generated
946        // column name the target's own columns. With the `FROM` terms still in
947        // scope, a `FROM` table that also had a column `a` made the index's `a`
948        // ambiguous, and `UPDATE t ... FROM r` was refused where SQLite runs it.
949        let saved_scopes = core::mem::replace(&mut self.scopes, vec![vec![source]]);
950        let schema = self.bind_update_schema(&table);
951        self.scopes = saved_scopes;
952        let (generated, checks, not_null_defaults, index_exprs, virtual_columns) = schema?;
953        // `RETURNING` reads the row written and nothing else: SQLite does not
954        // let a `FROM` term take part in it, so an unqualified `k` that both
955        // the target and a `FROM` term have is the target's.
956        let saved_scopes = core::mem::replace(&mut self.scopes, vec![vec![source]]);
957        let returning = self.bind_returning(&update.returning);
958        self.scopes = saved_scopes;
959        let returning = returning?;
960        // Bound as expressions, the way an aggregate's own `ORDER BY` is: a
961        // write has no result columns, so a bare integer names no ordinal.
962        let order_by = self.bind_aggregate_order(&update.order_by)?;
963        let limit = match update.limit {
964            Some(expr) => Some(self.bind_expr(expr)?),
965            None => None,
966        };
967        let offset = match update.offset {
968            Some(expr) => Some(self.bind_expr(expr)?),
969            None => None,
970        };
971        // The rowid is not a declared column, so no `UPDATE OF` trigger and no
972        // foreign key can be keyed on it and it contributes no name here.
973        let changed: Vec<Vec<u8>> = assignments
974            .iter()
975            .filter(|assignment| !assignment.rowid)
976            .filter_map(|assignment| table.column(assignment.column))
977            .map(|column| column.folded.clone())
978            .collect();
979        check_view_update_columns(&table, &changed)?;
980        let on_conflict = self.trigger_conflict.or(update.on_conflict);
981        let mut triggers = self.with_trigger_conflict(on_conflict, |binder| {
982            binder.bind_triggers(&table, TriggerEventInfo::Update(Vec::new()), &changed)
983        })?;
984        // Foreign keys see the generated columns whose inputs were assigned.
985        let key_changes = self.changed_with_generated(&table, &changed)?;
986        triggers.extend(self.bind_foreign_keys(
987            &table,
988            TriggerEventInfo::Update(Vec::new()),
989            &key_changes,
990        )?);
991        let view_rows = self
992            .view_rows(&table, filter.clone())
993            .map(|rows| join_view_rows(rows, &joined, &assignments))
994            .map(|rows| limit_view_rows(rows, &order_by, &limit, &offset));
995        let index_hint = self.write_hint(source, &index_exprs, filter.as_ref(), &joined)?;
996        let replace_triggers = self.bind_replace_triggers(&table, update.on_conflict)?;
997        let written_schema = self
998            .sources
999            .get(source)
1000            .and_then(|held| held.written_schema.clone());
1001        Ok(BoundUpdate {
1002            table,
1003            written_schema,
1004            index_exprs,
1005            index_hint,
1006            source,
1007            from: joined,
1008            assignments,
1009            generated,
1010            filter,
1011            on_conflict,
1012            checks,
1013            not_null_defaults,
1014            virtual_columns,
1015            returning,
1016            order_by,
1017            limit,
1018            offset,
1019            triggers,
1020            replace_triggers,
1021            view_rows,
1022        })
1023    }
1024
1025    /// Binds a `DELETE`.
1026    pub fn bind_delete(&mut self, delete: &ast::Delete) -> Result<BoundDelete, ParseError> {
1027        let pushed = self.push_ctes(&delete.with)?;
1028        let bound = self.bind_delete_body(delete);
1029        if pushed {
1030            self.pop_ctes();
1031        }
1032        bound
1033    }
1034
1035    /// Binds a `DELETE` with its CTEs already in scope.
1036    fn bind_delete_body(&mut self, delete: &ast::Delete) -> Result<BoundDelete, ParseError> {
1037        if let Some(refusal) = order_without_limit(delete.limited_at, delete.limit, "DELETE") {
1038            return Err(refusal);
1039        }
1040        let (table, source) =
1041            self.write_target_from_term(delete.target, &TriggerEventInfo::Delete)?;
1042        refuse_module_returning(&table, &delete.returning, "DELETE")?;
1043        let index_exprs = self.bind_index_exprs(&table)?;
1044        let filter = match delete.filter {
1045            Some(expr) => Some(self.bind_expr(expr)?),
1046            None => None,
1047        };
1048        let returning = self.bind_returning(&delete.returning)?;
1049        let order_by = self.bind_aggregate_order(&delete.order_by)?;
1050        let limit = match delete.limit {
1051            Some(expr) => Some(self.bind_expr(expr)?),
1052            None => None,
1053        };
1054        let offset = match delete.offset {
1055            Some(expr) => Some(self.bind_expr(expr)?),
1056            None => None,
1057        };
1058        // A `DELETE` hands its triggers no conflict action (`sqlite3DeleteFrom`
1059        // passes `OE_Default`), so what an outer `INSERT OR IGNORE` named stops
1060        // here instead of reaching the bodies of the triggers a delete fires.
1061        let mut triggers = self.with_trigger_conflict(None, |binder| {
1062            binder.bind_triggers(&table, TriggerEventInfo::Delete, &[])
1063        })?;
1064        triggers.extend(self.bind_foreign_keys(&table, TriggerEventInfo::Delete, &[])?);
1065        let view_rows = self
1066            .view_rows(&table, filter.clone())
1067            .map(|rows| limit_view_rows(rows, &order_by, &limit, &offset));
1068        // **A `DELETE` that removes every row empties the table without
1069        // looking at an index**, so SQLite never asks whether the named one can
1070        // answer it, and `DELETE FROM u INDEXED BY a_partial_index` runs. A
1071        // trigger, a foreign key, `RETURNING`, `ORDER BY` or `LIMIT` makes it
1072        // an ordinary delete, which does ask.
1073        let empties_the_table = filter.is_none()
1074            && triggers.is_empty()
1075            && returning.is_empty()
1076            && order_by.is_empty()
1077            && limit.is_none();
1078        let index_hint = if empties_the_table {
1079            crate::bind::IndexChoice::Any
1080        } else {
1081            self.write_hint(source, &index_exprs, filter.as_ref(), &[])?
1082        };
1083        let written_schema = self
1084            .sources
1085            .get(source)
1086            .and_then(|held| held.written_schema.clone());
1087        Ok(BoundDelete {
1088            table,
1089            written_schema,
1090            index_exprs,
1091            index_hint,
1092            source,
1093            filter,
1094            returning,
1095            order_by,
1096            limit,
1097            offset,
1098            triggers,
1099            view_rows,
1100        })
1101    }
1102
1103    /// Binds the triggers one write fires, bodies and all.
1104    ///
1105    /// The bodies are bound here, into the same binder, so their FROM terms take
1106    /// statement-wide source numbers alongside the write's own. That is what
1107    /// lets the compiler inline them: a trigger body is not a separate program
1108    /// with a separate cursor space, it is more of this statement.
1109    ///
1110    /// A trigger already being bound is skipped rather than bound again, which
1111    /// is SQLite's behaviour with its default `recursive_triggers = off` and is
1112    /// also the only reason inlining terminates.
1113    ///
1114    /// **Walked newest first.** `live.triggers` is in the order
1115    /// `inillucent_catalog::paged::tables_from_entries` appended them while
1116    /// reading `sqlite_schema` - the order the triggers were created in - and
1117    /// SQLite fires two triggers of the same timing and event in the opposite
1118    /// order: it keeps each table's trigger list with the most recently
1119    /// created one first, so that one fires first.
1120    /// `dml_differential.rs`'s `row_triggers_match_sqlite` has two `AFTER
1121    /// INSERT` triggers on one table - `t_ai`, created first, and `t_high`,
1122    /// created after it - and the pinned reference fires `t_high` before
1123    /// `t_ai` on every insert. Reversing the walk here, once, at the one place
1124    /// that reads `live.triggers` into a statement's own trigger list, is
1125    /// enough: nothing downstream reorders it again.
1126    fn bind_triggers(
1127        &mut self,
1128        table: &TableInfo,
1129        event: TriggerEventInfo,
1130        changed: &[Vec<u8>],
1131    ) -> Result<Vec<BoundTrigger>, ParseError> {
1132        if self.skip_triggers {
1133            return Ok(Vec::new());
1134        }
1135        // The catalog reference is copied out of `self` first: the trigger's
1136        // arena has to outlive the binder for the body to be bound in place,
1137        // and a borrow taken through `&self` would end at the first `&mut self`.
1138        let catalog = self.catalog;
1139        let database = catalog.database_name(table.database).to_vec();
1140        let Some(live) = catalog.find_table(Some(database.as_slice()), &table.folded) else {
1141            return Ok(Vec::new());
1142        };
1143        let (old, new) = match event {
1144            TriggerEventInfo::Insert => (false, true),
1145            TriggerEventInfo::Delete => (true, false),
1146            TriggerEventInfo::Update(_) => (true, true),
1147        };
1148        let mut bound = Vec::new();
1149        for trigger in live.triggers.iter().rev() {
1150            if !trigger.fires_for(&event, changed) {
1151                continue;
1152            }
1153            if self.firing.contains(&trigger.folded) {
1154                continue;
1155            }
1156            if self.firing.len() >= self.trigger_depth {
1157                // The number is in the message because a settable limit that
1158                // refuses without saying what it was leaves a reader guessing
1159                // between the default and whatever `.limit` last set.
1160                return Err(refused(
1161                    format!(
1162                        "too many levels of trigger recursion: the limit is {}",
1163                        self.trigger_depth
1164                    ),
1165                    Span::default(),
1166                ));
1167            }
1168            self.firing.push(trigger.folded.clone());
1169            let saved_ast = self.ast;
1170            let saved_scopes = core::mem::take(&mut self.scopes);
1171            let saved_aliases = self.row_aliases.take();
1172            let saved_target = self.view_target.take();
1173            // A trigger body is schema text: the statements in it were written
1174            // by whoever wrote the file, and they run because a write happened
1175            // rather than because anybody submitted them.
1176            let saved_site = self.call_site;
1177            self.call_site = crate::function::CallSite::Schema;
1178            self.ast = &trigger.ast;
1179            self.row_aliases = Some(crate::bind::RowAliases {
1180                table: table.clone(),
1181                old,
1182                new,
1183            });
1184            let result = self.bind_trigger_body(trigger, table);
1185            self.call_site = saved_site;
1186            self.ast = saved_ast;
1187            self.scopes = saved_scopes;
1188            self.row_aliases = saved_aliases;
1189            self.view_target = saved_target;
1190            self.firing.pop();
1191            let schema = catalog.database_name(table.database).to_vec();
1192            bound.push(result.map_err(|error| crate::bind::qualify_missing_table(error, &schema))?);
1193        }
1194        Ok(bound)
1195    }
1196
1197    /// Runs a bind with the conflict action the write's trigger bodies inherit.
1198    ///
1199    /// **A statement in a trigger body uses the conflict action of the statement
1200    /// that fired the trigger, whatever the body wrote.** SQLite sets the
1201    /// action for each step from the firing statement when that statement named
1202    /// one (`codeTriggerProgram`), so `INSERT OR REPLACE INTO t1` makes a body's
1203    /// plain `INSERT INTO t2` replace, and the body of a trigger that fires in
1204    /// turn inherits it again.
1205    ///
1206    /// @param inherited - the action the bodies inherit, `None` when none was written
1207    /// @param bind - binds the triggers
1208    fn with_trigger_conflict<T>(
1209        &mut self,
1210        inherited: Option<ast::ConflictAction>,
1211        bind: impl FnOnce(&mut Self) -> Result<T, ParseError>,
1212    ) -> Result<T, ParseError> {
1213        let saved = core::mem::replace(&mut self.trigger_conflict, inherited);
1214        let bound = bind(self);
1215        self.trigger_conflict = saved;
1216        bound
1217    }
1218
1219    /// Binds the triggers this write's foreign keys imply.
1220    ///
1221    /// The triggers themselves were generated when the schema was read - both
1222    /// directions of every key, since nothing in the file records the reverse
1223    /// one. What is decided here is which of them apply: whether keys are
1224    /// enforced at all, whether a check waits for the commit, and whether this
1225    /// particular write touches the columns a check is about.
1226    fn bind_foreign_keys(
1227        &mut self,
1228        table: &TableInfo,
1229        event: TriggerEventInfo,
1230        changed: &[Vec<u8>],
1231    ) -> Result<Vec<BoundTrigger>, ParseError> {
1232        if !self.foreign_keys || table.kind != TableKind::Table {
1233            return Ok(Vec::new());
1234        }
1235        let catalog = self.catalog;
1236        let database = catalog.database_name(table.database).to_vec();
1237        let Some(live) = catalog.find_table(Some(database.as_slice()), &table.folded) else {
1238            return Ok(Vec::new());
1239        };
1240        let mut bound = Vec::new();
1241        for planned in &live.foreign_key_triggers {
1242            if planned.is_check && (planned.deferred || self.defer_foreign_keys) {
1243                continue;
1244            }
1245            let Some(trigger) = planned.trigger.as_ref() else {
1246                if fault_applies(planned, &event) {
1247                    return Err(crate::bind::schema_refused(
1248                        String::from_utf8_lossy(&planned.fault).into_owned(),
1249                        Span::default(),
1250                    ));
1251                }
1252                continue;
1253            };
1254            if !trigger.fires_for(&event, changed) {
1255                continue;
1256            }
1257            if self.firing_foreign_keys.contains(&trigger.folded) {
1258                continue;
1259            }
1260            let mut one = self.bind_foreign_key_trigger(table, trigger, &event)?;
1261            one.self_referencing = planned.self_referencing;
1262            // A parent action that fires BEFORE the write is a RESTRICT, which
1263            // is the only parent action `foreign_key::parent_action` times so.
1264            if !planned.is_check && trigger.time == ast::TriggerTime::Before {
1265                mark_raises(&mut one, false);
1266            }
1267            // **`PRAGMA defer_foreign_keys` defers the parent's side too.** A
1268            // parent action whose body only checks - `RESTRICT`, and `NO
1269            // ACTION` - is dropped while it is on, and the commit's check of
1270            // every key takes its place: SQLite's `fkActionTrigger` builds no
1271            // `RESTRICT` program under `SQLITE_DeferFKs`, and its `NO ACTION`
1272            // check adds to the deferred counter. A `DELETE` a `RESTRICT` key
1273            // refused inside `BEGIN` therefore runs there, as it does in
1274            // SQLite. The actions that change rows still run.
1275            if self.defer_foreign_keys
1276                && !planned.is_check
1277                && one
1278                    .body
1279                    .iter()
1280                    .all(|statement| matches!(statement, BoundTriggerStatement::Select(_)))
1281            {
1282                continue;
1283            }
1284            bound.push(one);
1285        }
1286        Ok(bound)
1287    }
1288
1289    /// Binds one synthesised trigger, inside the recursion budget.
1290    ///
1291    /// The budget is spent here rather than where the trigger was generated,
1292    /// because what a cascade costs is the *bound* body: one copy per level it
1293    /// can reach, and it can reach itself only when the keys form a cycle.
1294    fn bind_foreign_key_trigger(
1295        &mut self,
1296        table: &TableInfo,
1297        trigger: &'a TriggerInfo,
1298        event: &TriggerEventInfo,
1299    ) -> Result<BoundTrigger, ParseError> {
1300        if self.foreign_key_depth >= MAX_FOREIGN_KEY_DEPTH || self.foreign_key_budget == 0 {
1301            return Err(refused(
1302                "too many levels of foreign key recursion",
1303                Span::default(),
1304            ));
1305        }
1306        self.foreign_key_depth = self.foreign_key_depth.saturating_add(1);
1307        self.foreign_key_budget = self.foreign_key_budget.saturating_sub(1);
1308        self.firing_foreign_keys.push(trigger.folded.clone());
1309        let (old, new) = match event {
1310            TriggerEventInfo::Insert => (false, true),
1311            TriggerEventInfo::Delete => (true, false),
1312            TriggerEventInfo::Update(_) => (true, true),
1313        };
1314        let saved_ast = self.ast;
1315        let saved_scopes = core::mem::take(&mut self.scopes);
1316        let saved_aliases = self.row_aliases.take();
1317        let saved_target = self.view_target.take();
1318        // A synthesised key action is generated from a `REFERENCES` clause the
1319        // schema wrote, so it is schema too - the same site a written trigger
1320        // gets, because the binder turns both into the same text.
1321        let saved_site = self.call_site;
1322        self.call_site = crate::function::CallSite::Schema;
1323        self.ast = &trigger.ast;
1324        self.row_aliases = Some(crate::bind::RowAliases {
1325            table: table.clone(),
1326            old,
1327            new,
1328        });
1329        let result = self.bind_trigger_body(trigger, table);
1330        self.call_site = saved_site;
1331        self.ast = saved_ast;
1332        self.scopes = saved_scopes;
1333        self.row_aliases = saved_aliases;
1334        self.view_target = saved_target;
1335        self.foreign_key_depth = self.foreign_key_depth.saturating_sub(1);
1336        self.firing_foreign_keys.pop();
1337        let mut bound = result?;
1338        report_as_foreign_key(&mut bound);
1339        Ok(bound)
1340    }
1341
1342    /// Binds one trigger's guard and body only to learn whether every name in
1343    /// them resolves.
1344    ///
1345    /// **This is `ALTER TABLE`'s check of the schema.** After a rename or a
1346    /// dropped column SQLite re-reads every trigger and refuses the statement
1347    /// when one names a table or column that is no longer there. The binder must
1348    /// have been built over the trigger's own arena (`Binder::new(catalog,
1349    /// &trigger.ast, ..)`), and the triggers of the tables the body writes are
1350    /// not expanded.
1351    ///
1352    /// @param trigger - the trigger
1353    /// @param table - the table the trigger is on
1354    pub fn check_trigger(
1355        &mut self,
1356        trigger: &TriggerInfo,
1357        table: &TableInfo,
1358    ) -> Result<(), ParseError> {
1359        let (old, new) = match trigger.event {
1360            TriggerEventInfo::Insert => (false, true),
1361            TriggerEventInfo::Delete => (true, false),
1362            TriggerEventInfo::Update(_) => (true, true),
1363        };
1364        self.skip_triggers = true;
1365        self.row_aliases = Some(crate::bind::RowAliases {
1366            table: table.clone(),
1367            old,
1368            new,
1369        });
1370        self.bind_trigger_body(trigger, table).map(|_| ())
1371    }
1372
1373    /// Binds one trigger's guard and body statements.
1374    fn bind_trigger_body(
1375        &mut self,
1376        trigger: &TriggerInfo,
1377        table: &TableInfo,
1378    ) -> Result<BoundTrigger, ParseError> {
1379        let when = match trigger.when {
1380            Some(expr) => Some(self.bind_expr(expr)?),
1381            None => None,
1382        };
1383        let mut body = Vec::new();
1384        for statement in &trigger.body {
1385            // Each statement gets a fresh scope stack. A body statement's names
1386            // resolve against its own tables and against OLD and NEW, never
1387            // outward into the statement that fired it.
1388            let saved = core::mem::take(&mut self.scopes);
1389            let one = self.bind_trigger_statement(statement);
1390            self.scopes = saved;
1391            body.push(one?);
1392        }
1393        Ok(BoundTrigger {
1394            name: trigger.name.clone(),
1395            table: table.folded.clone(),
1396            time: trigger.time,
1397            when,
1398            body,
1399            foreign_key: false,
1400            self_referencing: false,
1401        })
1402    }
1403
1404    /// Binds one statement of a trigger body.
1405    pub(crate) fn bind_trigger_statement(
1406        &mut self,
1407        statement: &ast::Statement,
1408    ) -> Result<BoundTriggerStatement, ParseError> {
1409        match statement {
1410            ast::Statement::Insert(insert) => {
1411                if !insert.returning.is_empty() {
1412                    return Err(refused(
1413                        "RETURNING is not allowed on a trigger body statement",
1414                        Span::default(),
1415                    ));
1416                }
1417                Ok(BoundTriggerStatement::Insert(Box::new(
1418                    self.bind_insert(insert)?,
1419                )))
1420            }
1421            ast::Statement::Update(update) => {
1422                if !update.returning.is_empty() {
1423                    return Err(refused(
1424                        "RETURNING is not allowed on a trigger body statement",
1425                        Span::default(),
1426                    ));
1427                }
1428                Ok(BoundTriggerStatement::Update(Box::new(
1429                    self.bind_update(update)?,
1430                )))
1431            }
1432            ast::Statement::Delete(delete) => {
1433                if !delete.returning.is_empty() {
1434                    return Err(refused(
1435                        "RETURNING is not allowed on a trigger body statement",
1436                        Span::default(),
1437                    ));
1438                }
1439                Ok(BoundTriggerStatement::Delete(Box::new(
1440                    self.bind_delete(delete)?,
1441                )))
1442            }
1443            ast::Statement::Select(select) => Ok(BoundTriggerStatement::Select(Box::new(
1444                self.bind_select(*select)?,
1445            ))),
1446            _ => Err(unsupported(
1447                "that statement in a trigger body",
1448                Span::default(),
1449            )),
1450        }
1451    }
1452
1453    /// Resolves a write target and refuses the things that cannot be written.
1454    fn writable_target(
1455        &mut self,
1456        database: Option<ast::NameId>,
1457        name: ast::NameId,
1458        span: Span,
1459        event: &TriggerEventInfo,
1460    ) -> Result<std::rc::Rc<TableInfo>, ParseError> {
1461        let qualifier = database.map(|id| self.ast.folded(id).to_vec());
1462        let folded = self.ast.folded(name).to_vec();
1463        // Shared with the catalog rather than cloned. A clone of a `TableInfo`
1464        // copies every column, index and the `CREATE` text, and an `INSERT` took
1465        // two of them: 8.6% of a script of single row inserts run through the
1466        // shell (task-2191). `shared_table` is what the `SELECT` path uses.
1467        let Some(table) = self.catalog.shared_table(qualifier.as_deref(), &folded) else {
1468            let written = match database {
1469                Some(schema) => {
1470                    [self.ast.text(schema), b".".as_slice(), self.ast.text(name)].concat()
1471                }
1472                None => self.ast.text(name).to_vec(),
1473            };
1474            return Err(crate::bind::no_such_table(&written, span));
1475        };
1476        match table.kind {
1477            TableKind::View => {
1478                // A view is writable exactly when it has an `INSTEAD OF`
1479                // trigger for this event: the trigger *is* the write, and the
1480                // view itself is never touched.
1481                if !has_instead_of(&table, event) {
1482                    return Err(view_not_writable(&table));
1483                }
1484                let expanded = self.expanded_view(&table, span)?;
1485                self.record_write_dependency(table.database);
1486                return Ok(std::rc::Rc::new(expanded));
1487            }
1488            TableKind::Virtual => {
1489                // A module decides whether it can be written; a module that
1490                // cannot refuses the call rather than the statement, because
1491                // "this table is read-only" is the module's fact and not the
1492                // binder's. What the binder still checks is that the table has
1493                // a module at all - a virtual table this build has no module
1494                // for has no columns either, and nothing can be written to it.
1495                if table.columns.is_empty() {
1496                    return Err(unsupported("that virtual table's module", span));
1497                }
1498                self.record_write_dependency(table.database);
1499                return Ok(table);
1500            }
1501            TableKind::Subquery => return Err(unsupported("writing to a subquery", span)),
1502            TableKind::Table => {}
1503        }
1504        if table.folded.starts_with(b"sqlite_")
1505            && !WRITABLE_INTERNAL.contains(&table.folded.as_slice())
1506        {
1507            return Err(unsupported(
1508                "writing to a table whose name begins with sqlite_",
1509                span,
1510            ));
1511        }
1512        self.record_write_dependency(table.database);
1513        Ok(table)
1514    }
1515
1516    /// Resolves the target of an UPDATE or DELETE, which is a FROM term.
1517    fn write_target_from_term(
1518        &mut self,
1519        id: ast::FromTermId,
1520        event: &TriggerEventInfo,
1521    ) -> Result<(std::rc::Rc<TableInfo>, usize), ParseError> {
1522        let Some(term) = self.ast.from_term(id) else {
1523            return Err(unsupported("missing target", Span::default()));
1524        };
1525        let ast::FromSource::Table {
1526            database,
1527            name,
1528            indexed_by,
1529            ..
1530        } = term.source
1531        else {
1532            return Err(unsupported("a target that is not a table", term.span));
1533        };
1534        let table = self.writable_target(database, name, term.span, event)?;
1535        // The same rule as a SELECT's: an `INDEXED BY` that names no index of
1536        // the table is refused rather than ignored (task-1979, F7). This path
1537        // has the table in hand rather than a bound source, so it asks the
1538        // table directly.
1539        if let ast::IndexHint::IndexedBy(index) = indexed_by {
1540            let folded = self.ast.folded(index).to_vec();
1541            if !table.indexes.iter().any(|held| held.folded == folded) {
1542                return Err(crate::bind::no_such_index(self.ast.text(index), term.span));
1543            }
1544        }
1545        let alias = match term.alias {
1546            Some(alias) => self.ast.text(alias).to_vec(),
1547            None => table.name.clone(),
1548        };
1549        if table.kind == TableKind::View {
1550            // The view goes in as an ordinary nested query, so the statement's
1551            // WHERE and SET bind against the view's own columns and against the
1552            // term the block producing OLD will iterate. Binding first and
1553            // re-pointing afterwards would be two chances to disagree.
1554            let inner = self.view_query(&table, term.span)?;
1555            let source = BoundSource {
1556                index_hint: crate::bind::IndexChoice::Any,
1557                id: self.sources.len(),
1558                rows: crate::bind::SourceRows::Subquery(Box::new(inner)),
1559                table: std::rc::Rc::clone(&table),
1560                alias,
1561                join: ast::JoinKind::Comma,
1562                constraint: None,
1563                suppressed: Vec::new(),
1564                index_exprs: Vec::new(),
1565                written_schema: None,
1566                derived: Default::default(),
1567            };
1568            self.view_target = Some(source.id);
1569            let scope = source.id;
1570            self.sources.push(source);
1571            self.scopes.push(vec![scope]);
1572            return Ok((table, scope));
1573        }
1574        let scope = self.push_write_source(std::rc::Rc::clone(&table), alias);
1575        let choice = self.index_choice(indexed_by);
1576        let written_schema = match (term.alias, database) {
1577            (None, Some(schema)) => Some(self.ast.text(schema).to_vec()),
1578            _ => None,
1579        };
1580        if let Some(source) = self.sources.get_mut(scope) {
1581            source.index_hint = choice;
1582            source.written_schema = written_schema;
1583        }
1584        Ok((table, scope))
1585    }
1586
1587    /// Returns a view's `TableInfo` with the columns its body produces.
1588    ///
1589    /// A view's catalog entry carries no column list - its columns are whatever
1590    /// binding its `SELECT` says they are - so a statement that writes one needs
1591    /// the body bound before `new.column` can resolve to anything at all.
1592    pub(crate) fn expanded_view(
1593        &mut self,
1594        table: &TableInfo,
1595        span: Span,
1596    ) -> Result<TableInfo, ParseError> {
1597        let bound = self.view_query(table, span)?;
1598        let mut expanded = table.clone();
1599        expanded.columns = crate::bind::subquery_columns(&bound, &[]);
1600        Ok(expanded)
1601    }
1602
1603    /// Binds a view's body, out of the arena the catalog snapshot holds.
1604    fn view_query(&mut self, table: &TableInfo, span: Span) -> Result<BoundSelect, ParseError> {
1605        let catalog = self.catalog;
1606        let database = catalog.database_name(table.database).to_vec();
1607        let Some(live) = catalog.find_table(Some(database.as_slice()), &table.folded) else {
1608            return Err(crate::bind::no_such_table(&table.name, span));
1609        };
1610        let Some(body) = live.view.as_ref() else {
1611            return Err(unsupported(
1612                "a view whose definition could not be parsed",
1613                span,
1614            ));
1615        };
1616        let names = body.columns.clone();
1617        let saved_ast = self.ast;
1618        let saved_scopes = core::mem::take(&mut self.scopes);
1619        self.ast = &body.ast;
1620        let bound = self.bind_select(body.select);
1621        self.ast = saved_ast;
1622        self.scopes = saved_scopes;
1623        let mut bound = bound?;
1624        // `CREATE VIEW v (a, b)` renames the body's columns, and those are the
1625        // names `new.a` resolves against.
1626        for (position, name) in names.iter().enumerate() {
1627            if let Some(column) = bound.columns.get_mut(position) {
1628                column.name = name.clone();
1629            }
1630        }
1631        Ok(bound)
1632    }
1633
1634    /// Builds the block whose rows an `INSTEAD OF UPDATE` or `DELETE` fires for.
1635    ///
1636    /// It reads the term `write_target_from_term` already pushed, so the filter
1637    /// handed in here - bound against that same term - needs no adjustment.
1638    fn view_rows(
1639        &mut self,
1640        table: &TableInfo,
1641        filter: Option<BoundExpr>,
1642    ) -> Option<Box<BoundSelect>> {
1643        // The kind is checked before the target is taken. A trigger body's own
1644        // UPDATE binds through here too, and taking first meant the body's
1645        // statement - whose target is an ordinary table - consumed the view
1646        // target belonging to the statement that fired it, which then compiled
1647        // as a write to a view's root page of zero.
1648        if table.kind != TableKind::View {
1649            return None;
1650        }
1651        let id = self.view_target.take()?;
1652        let mut source = self.sources.get(id)?.clone();
1653        source.derived.pinned = true;
1654        let columns = table
1655            .columns
1656            .iter()
1657            .enumerate()
1658            .map(|(position, column)| BoundResultColumn {
1659                expr: BoundExpr::Column {
1660                    source: id,
1661                    column: position as u16,
1662                    slot: position as u16,
1663                    affinity: column.affinity,
1664                    collation: Collation::from_name(
1665                        core::str::from_utf8(&column.collation).unwrap_or("BINARY"),
1666                    )
1667                    .unwrap_or(Collation::Binary),
1668                },
1669                name: column.name.clone(),
1670                origin: None,
1671                declared_type: column.declared_type.clone(),
1672                written: None,
1673            })
1674            .collect();
1675        Some(Box::new(crate::bind::block_over(source, filter, columns)))
1676    }
1677
1678    /// Returns the target's index hint, or refuses a write whose `INDEXED BY`
1679    /// index cannot find its rows.
1680    ///
1681    /// The same rule and the same test a `SELECT` gets from
1682    /// `crate::bind::refuse_unanswerable_hints`, asked of the query the write
1683    /// will run to find its rows: the target, any `UPDATE ... FROM` terms, and
1684    /// the statement's `WHERE`. The pinned 3.53.4 shell refuses
1685    /// `DELETE FROM h INDEXED BY h_part WHERE a = 1`, where `h_part` is declared
1686    /// `WHERE c > 3`, with `no query solution`.
1687    /// @param source - the target's statement-wide number
1688    /// @param index_exprs - the target's bound index expressions
1689    /// @param filter - the statement's `WHERE`
1690    /// @param joined - the `UPDATE ... FROM` terms, empty for a `DELETE`
1691    fn write_hint(
1692        &self,
1693        source: usize,
1694        index_exprs: &[BoundIndexExprs],
1695        filter: Option<&BoundExpr>,
1696        joined: &[BoundSource],
1697    ) -> Result<crate::bind::IndexChoice, ParseError> {
1698        let Some(target) = self.sources.get(source) else {
1699            return Ok(crate::bind::IndexChoice::Any);
1700        };
1701        if target.index_hint == crate::bind::IndexChoice::Any {
1702            return Ok(crate::bind::IndexChoice::Any);
1703        }
1704        let mut probe = target.clone();
1705        probe.index_exprs = index_exprs.to_vec();
1706        let mut block = crate::bind::block_over(probe, filter.cloned(), Vec::new());
1707        block.sources.extend(joined.iter().cloned());
1708        if crate::plan::unanswerable_index_hint(&block).is_some() {
1709            return Err(crate::bind::no_query_solution(Span::default()));
1710        }
1711        Ok(target.index_hint.clone())
1712    }
1713
1714    /// Makes the target table the statement's one visible source.
1715    ///
1716    /// It opens a scope holding just the target, so every name in the
1717    /// statement's `SET`, `WHERE` and `RETURNING` resolves against the table
1718    /// being written and nothing else.
1719    fn push_write_source(&mut self, table: std::rc::Rc<TableInfo>, alias: Vec<u8>) -> usize {
1720        let id = self.sources.len();
1721        self.sources.push(BoundSource {
1722            index_hint: crate::bind::IndexChoice::Any,
1723            id,
1724            rows: crate::bind::SourceRows::Table,
1725            table,
1726            alias,
1727            join: ast::JoinKind::Comma,
1728            constraint: None,
1729            suppressed: Vec::new(),
1730            index_exprs: Vec::new(),
1731            written_schema: None,
1732            derived: Default::default(),
1733        });
1734        self.scopes.push(vec![id]);
1735        id
1736    }
1737
1738    /// Refuses an attempt to write a generated column.
1739    ///
1740    /// SQLite's message names the column, because the usual cause is a script
1741    /// that inserts every column of a table one of whose columns has since been
1742    /// made generated. It names the statement too - `INSERT` or `UPDATE` - and
1743    /// so does this.
1744    ///
1745    /// @param table - the table being written
1746    /// @param position - the column the statement named
1747    /// @param verb - `INSERT into` or `UPDATE`, as SQLite writes it
1748    /// @param span - where the name was written
1749    fn refuse_generated(
1750        &self,
1751        table: &TableInfo,
1752        position: u16,
1753        verb: &str,
1754        span: Span,
1755    ) -> Result<(), ParseError> {
1756        let Some(column) = table.column(position) else {
1757            return Ok(());
1758        };
1759        if !column.generated {
1760            return Ok(());
1761        }
1762        Err(refused(
1763            format!(
1764                "cannot {verb} generated column \"{}\"",
1765                String::from_utf8_lossy(&column.name)
1766            ),
1767            span,
1768        ))
1769    }
1770
1771    /// Returns the target column positions an INSERT writes, in source order.
1772    ///
1773    /// With no column list the targets are every column in declaration order,
1774    /// which is why adding a column to a table changes what a positional
1775    /// INSERT means - SQLite's behaviour, and the reason the column list is
1776    /// worth writing.
1777    ///
1778    /// @param table - the table written
1779    /// @param columns - the column list as written
1780    /// @param label - the table as SQLite names it in a failure
1781    fn insert_targets(
1782        &self,
1783        table: &TableInfo,
1784        columns: &[ast::NameId],
1785        label: &str,
1786    ) -> Result<Vec<u16>, ParseError> {
1787        if columns.is_empty() {
1788            // A bare `INSERT INTO t VALUES (...)` supplies the columns a person
1789            // can write, which is every column that is not generated - so a
1790            // table with a generated column takes fewer values than it has
1791            // columns, exactly as SQLite counts them.
1792            // A hidden column is not one of them either: a module's arguments
1793            // and its `rank` are named by an application that wants them, and
1794            // an `INSERT INTO fts VALUES ('a', 'b')` supplies the two indexed
1795            // columns and nothing else.
1796            return Ok((0..table.columns.len() as u16)
1797                .filter(|position| {
1798                    table
1799                        .column(*position)
1800                        .is_some_and(|column| !column.generated && !column.hidden)
1801                })
1802                .collect());
1803        }
1804        let mut targets = Vec::with_capacity(columns.len());
1805        for name in columns {
1806            let folded = self.ast.folded(*name).to_vec();
1807            let position = match table.column_position(&folded) {
1808                Some(position) => position,
1809                // A rowid table lets the statement name its rowid, under any
1810                // of its three spellings, and that is not a column: it is the
1811                // key. A declared column of the same name wins, which is why
1812                // this is the fallback rather than the first thing tried.
1813                None if table.has_rowid() && is_rowid_name(&folded) => ROWID_TARGET,
1814                None => {
1815                    return Err(refused(
1816                        format!(
1817                            "table {label} has no column named {}",
1818                            String::from_utf8_lossy(self.ast.text(*name))
1819                        ),
1820                        Span::default(),
1821                    ))
1822                }
1823            };
1824            // A column named twice is accepted. The first value is the one a
1825            // table column takes and the last is the one the rowid takes, which
1826            // is how SQLite reads `INSERT INTO t(a, a)` and `INSERT INTO t(rowid, oid)`.
1827            if position != ROWID_TARGET {
1828                self.refuse_generated(table, position, "INSERT into", Span::default())?;
1829            }
1830            targets.push(position);
1831        }
1832        Ok(targets)
1833    }
1834
1835    /// Binds the rows an INSERT supplies.
1836    fn bind_insert_source(
1837        &mut self,
1838        source: &ast::InsertSource,
1839        table: &TableInfo,
1840        targets: &[u16],
1841    ) -> Result<(BoundInsertSource, usize), ParseError> {
1842        match source {
1843            ast::InsertSource::DefaultValues => {
1844                let _ = (table, targets);
1845                Ok((BoundInsertSource::Values(vec![Vec::new()]), 0))
1846            }
1847            ast::InsertSource::Select(id) => {
1848                // The target table is source zero while the rows are bound, so
1849                // that `INSERT INTO t SELECT ... FROM u` resolves `u`'s columns
1850                // and not `t`'s. Binding a SELECT replaces the source list, and
1851                // the target is pushed back afterwards.
1852                // The scope stack is emptied rather than pushed to, because a
1853                // pushed scope would still be searched *outward* into the
1854                // target's, and `INSERT INTO t SELECT a FROM u` would then
1855                // resolve `a` against `t` when `u` has no such column.
1856                let saved = core::mem::take(&mut self.scopes);
1857                let select = self.bind_select(*id);
1858                let bound = match select {
1859                    Ok(bound) => bound,
1860                    Err(error) => {
1861                        self.scopes = saved;
1862                        return Err(error);
1863                    }
1864                };
1865                self.scopes = saved;
1866                // A VALUES list followed by `UNION ALL` and more rows is a
1867                // compound, whose later arms the plain list would drop.
1868                if bound.values.is_empty() || !bound.compounds.is_empty() {
1869                    let arity = bound.columns.len();
1870                    return Ok((BoundInsertSource::Select(Box::new(bound)), arity));
1871                }
1872                let arity = bound.values.first().map_or(0, Vec::len);
1873                for row in &bound.values {
1874                    if row.len() != arity {
1875                        return Err(crate::bind::values_width_mismatch(Span::default()));
1876                    }
1877                }
1878                Ok((BoundInsertSource::Values(bound.values), arity))
1879            }
1880        }
1881    }
1882
1883    /// Works out where every table column's value comes from.
1884    ///
1885    /// A column the statement named takes its value from the source row; a
1886    /// column it did not takes its `DEFAULT`, and a column with no default
1887    /// takes NULL. The rowid is separated out here rather than in the
1888    /// compiler, because an `INTEGER PRIMARY KEY` column *is* the rowid and
1889    /// writing it into the record as well would store a duplicate that SQLite
1890    /// does not.
1891    fn column_sources(
1892        &mut self,
1893        table: &TableInfo,
1894        targets: &[u16],
1895    ) -> Result<(Vec<ColumnSource>, Option<ColumnSource>), ParseError> {
1896        let mut columns = Vec::with_capacity(table.columns.len());
1897        for position in 0..table.columns.len() as u16 {
1898            if let Some(expr) = self.generated_expr(table, position)? {
1899                columns.push(ColumnSource::Generated(expr));
1900                continue;
1901            }
1902            let named = if table.rowid_alias == Some(position) {
1903                targets.iter().rposition(|target| *target == position)
1904            } else {
1905                targets.iter().position(|target| *target == position)
1906            };
1907            let source = match named {
1908                Some(index) => ColumnSource::Row(index),
1909                // **A rowid alias takes no `DEFAULT`.** SQLite ignores the
1910                // default of an `INTEGER PRIMARY KEY` column and allocates a
1911                // rowid, so `DEFAULT 100` on the key is never used.
1912                None if table.rowid_alias == Some(position) => ColumnSource::Expr(BoundExpr::Null),
1913                None => ColumnSource::Expr(self.default_expr(table, position)?),
1914            };
1915            columns.push(source);
1916        }
1917        let rowid = match table.rowid_alias {
1918            Some(position) => columns.get(position as usize).cloned(),
1919            None => None,
1920        };
1921        Ok((columns, rowid))
1922    }
1923
1924    /// Binds a generated column's expression, when the column is one.
1925    fn generated_expr(
1926        &mut self,
1927        table: &TableInfo,
1928        position: u16,
1929    ) -> Result<Option<BoundExpr>, ParseError> {
1930        let Some(column) = table.column(position) else {
1931            return Ok(None);
1932        };
1933        if !column.generated {
1934            return Ok(None);
1935        }
1936        let Some(sql) = column.generated_sql.clone() else {
1937            return Ok(Some(BoundExpr::Null));
1938        };
1939        Ok(Some(self.bind_schema_expr(&sql)?))
1940    }
1941
1942    /// Binds the schema expressions an `UPDATE` evaluates for each row.
1943    ///
1944    /// The caller narrows the scope to the target first, so a name in the
1945    /// schema text cannot reach a `FROM` term.
1946    ///
1947    /// @param table - the table being written
1948    #[allow(clippy::type_complexity)]
1949    fn bind_update_schema(
1950        &mut self,
1951        table: &TableInfo,
1952    ) -> Result<
1953        (
1954            Vec<BoundAssignment>,
1955            Vec<BoundCheck>,
1956            Vec<BoundDefault>,
1957            Vec<BoundIndexExprs>,
1958            Vec<BoundVirtualColumn>,
1959        ),
1960        ParseError,
1961    > {
1962        let generated = self.bind_stored_generated(table)?;
1963        let checks = self.bind_checks(table)?;
1964        let not_null_defaults = self.bind_not_null_defaults(table)?;
1965        let index_exprs = self.bind_index_exprs(table)?;
1966        let virtual_columns = self.bind_virtual_columns(table)?;
1967        Ok((
1968            generated,
1969            checks,
1970            not_null_defaults,
1971            index_exprs,
1972            virtual_columns,
1973        ))
1974    }
1975
1976    /// Binds the virtual generated columns a write has to test.
1977    ///
1978    /// A column is included when it is `NOT NULL`, or when the table is
1979    /// `STRICT` and so checks every column's type. Each is bound as a read of
1980    /// the column, which is the expression converted by the column's affinity:
1981    /// SQLite tests that value, and not the bare expression.
1982    ///
1983    /// @param table - the table being written
1984    fn bind_virtual_columns(
1985        &mut self,
1986        table: &TableInfo,
1987    ) -> Result<Vec<BoundVirtualColumn>, ParseError> {
1988        let mut bound = Vec::new();
1989        for (position, column) in table.columns.iter().enumerate() {
1990            let virtual_column = column.generated && !column.stored;
1991            if !virtual_column || !(column.not_null || table.strict) {
1992                continue;
1993            }
1994            let expr = self.bind_schema_expr(&crate::catalog_view::quoted_name(&column.name))?;
1995            bound.push(BoundVirtualColumn {
1996                column: position as u16,
1997                expr,
1998            });
1999        }
2000        Ok(bound)
2001    }
2002
2003    /// Binds every `STORED` generated column's expression.
2004    ///
2005    /// Returns them as assignments, because that is what they are on the write
2006    /// path: a value the statement did not write and the row has to carry. See
2007    /// [`BoundUpdate::generated`] for why an `UPDATE` needs them and a
2008    /// `VIRTUAL` column does not.
2009    ///
2010    /// @param table - the table being written
2011    fn bind_stored_generated(
2012        &mut self,
2013        table: &TableInfo,
2014    ) -> Result<Vec<BoundAssignment>, ParseError> {
2015        let mut generated = Vec::new();
2016        for position in 0..table.columns.len() as u16 {
2017            let Some(column) = table.column(position) else {
2018                continue;
2019            };
2020            if !column.generated || !column.stored {
2021                continue;
2022            }
2023            let Some(expr) = self.generated_expr(table, position)? else {
2024                continue;
2025            };
2026            generated.push(BoundAssignment {
2027                column: position,
2028                rowid: false,
2029                value: expr,
2030            });
2031        }
2032        Ok(generated)
2033    }
2034
2035    /// Binds a column's `DEFAULT`, or NULL when it has none.
2036    fn default_expr(&mut self, table: &TableInfo, position: u16) -> Result<BoundExpr, ParseError> {
2037        let Some(column) = table.column(position) else {
2038            return Ok(BoundExpr::Null);
2039        };
2040        let Some(sql) = column.default_sql.as_ref() else {
2041            return Ok(BoundExpr::Null);
2042        };
2043        if sql.is_empty() {
2044            return Ok(BoundExpr::Null);
2045        }
2046        self.bind_default_sql(&sql.clone())
2047    }
2048
2049    /// Binds the text of a `DEFAULT`.
2050    ///
2051    /// **An unparenthesised word is a string**, as SQLite reads
2052    /// `DEFAULT hello`; the parser gives it that meaning, and the stored text
2053    /// is the word as written, so it is given the meaning again here. A default
2054    /// has no column in scope for a word to name.
2055    ///
2056    /// @param sql - the default as stored
2057    pub(crate) fn bind_default_sql(&mut self, sql: &[u8]) -> Result<BoundExpr, ParseError> {
2058        let limits = Limits::default();
2059        let (ast, expr) = parse_expression(sql, &limits)?;
2060        if let Some(ast::Expr::Column {
2061            database: None,
2062            table: None,
2063            column,
2064        }) = ast.expr(expr)
2065        {
2066            return Ok(BoundExpr::Text(ast.text(*column).to_vec()));
2067        }
2068        self.bind_schema_expr(sql)
2069    }
2070
2071    /// Binds the `DEFAULT` of every `NOT NULL` column that declares one.
2072    ///
2073    /// What `REPLACE` substitutes for a NULL in such a column - see
2074    /// [`BoundDefault`]. A column with no default is left out, which is what
2075    /// makes the write path's fallback to `ABORT` the absence of an entry
2076    /// rather than a second test.
2077    ///
2078    /// The rowid alias is left out too: the row image carries the key the
2079    /// statement is about to allocate, and the write path does not check it.
2080    ///
2081    /// @param table - the table being written
2082    fn bind_not_null_defaults(
2083        &mut self,
2084        table: &TableInfo,
2085    ) -> Result<Vec<BoundDefault>, ParseError> {
2086        let mut defaults = Vec::new();
2087        for (position, column) in table.columns.iter().enumerate() {
2088            if !column.not_null || Some(position as u16) == table.rowid_alias {
2089                continue;
2090            }
2091            let Some(sql) = column.default_sql.as_ref() else {
2092                continue;
2093            };
2094            if sql.is_empty() {
2095                continue;
2096            }
2097            let expr = self.bind_default_sql(&sql.clone())?;
2098            defaults.push(BoundDefault {
2099                column: position as u16,
2100                expr,
2101            });
2102        }
2103        Ok(defaults)
2104    }
2105
2106    /// Binds every `CHECK` the table declares.
2107    fn bind_checks(&mut self, table: &TableInfo) -> Result<Vec<BoundCheck>, ParseError> {
2108        let mut checks = Vec::with_capacity(table.checks.len());
2109        for check in &table.checks {
2110            checks.push(BoundCheck {
2111                name: check.name.clone(),
2112                expr: self.bind_schema_expr(&check.expr_sql)?,
2113            });
2114        }
2115        Ok(checks)
2116    }
2117
2118    /// Binds the expressions the table's indexes need per row.
2119    ///
2120    /// Only the indexes that need any: a partial one, and one with an
2121    /// expression key. Everything else is a slot of the row and needs nothing.
2122    ///
2123    /// @param table - the table being written
2124    fn bind_index_exprs(&mut self, table: &TableInfo) -> Result<Vec<BoundIndexExprs>, ParseError> {
2125        let mut bound = Vec::new();
2126        for (position, index) in table.indexes.iter().enumerate() {
2127            let needs = index.partial_sql.is_some()
2128                || index.columns.iter().any(|key| key.expr_sql.is_some());
2129            if !needs {
2130                continue;
2131            }
2132            let predicate = match index.partial_sql.as_ref() {
2133                Some(sql) => Some(self.bind_schema_expr(sql)?),
2134                None => None,
2135            };
2136            let mut keys = Vec::with_capacity(index.columns.len());
2137            for key in &index.columns {
2138                keys.push(match key.computed_text(table) {
2139                    Some(sql) => Some(self.bind_schema_expr(&sql)?),
2140                    None => None,
2141                });
2142            }
2143            bound.push(BoundIndexExprs {
2144                position,
2145                predicate,
2146                keys,
2147            });
2148        }
2149        Ok(bound)
2150    }
2151
2152    /// Parses and binds an expression that was written in the schema.
2153    ///
2154    /// It is parsed into its own arena and bound against the statement's
2155    /// current sources, so the result is an ordinary `BoundExpr` that refers to
2156    /// the target table by position and carries no reference to the schema
2157    /// text it came from.
2158    pub fn bind_schema_expr(&mut self, sql: &[u8]) -> Result<BoundExpr, ParseError> {
2159        let limits = Limits::default();
2160        let (ast, expr) = parse_expression(sql, &limits)?;
2161        let mut nested = Binder::new(self.catalog, &ast, self.authorizer);
2162        nested.trigger_depth = self.trigger_depth;
2163        // **This is where a `DEFAULT`, a `CHECK`, a generated column, an index
2164        // expression and a partial-index predicate all become a bound tree, so
2165        // it is where all five are told they are a schema (task-1972).** The
2166        // nested binder also inherits the connection's registrations and
2167        // collations, which it did not before: without the registrations
2168        // `bind_external_call` never sees the call at all, because the name
2169        // does not resolve to a registered function and the expression fails as
2170        // "no such function" - an error for the wrong reason, and one that
2171        // disappears the moment an application registers the same name at a
2172        // different arity.
2173        nested.externals = self.externals;
2174        nested.collations = self.collations;
2175        nested.trusted_schema = self.trusted_schema;
2176        nested.call_site = crate::function::CallSite::Schema;
2177        nested.sources = self.sources.clone();
2178        nested.scopes = self.scopes.clone();
2179        let bound = nested.bind_expr(expr)?;
2180        Ok(bound)
2181    }
2182
2183    /// Binds an `ON CONFLICT` clause.
2184    fn bind_upsert(
2185        &mut self,
2186        table: &TableInfo,
2187        insert: &ast::Insert,
2188    ) -> Result<Vec<BoundUpsert>, ParseError> {
2189        if insert.upserts.is_empty() {
2190            return Ok(Vec::new());
2191        }
2192        // A view has no constraint for a conflict to name, and SQLite says so before it
2193        // looks at the clause.
2194        if table.kind == TableKind::View {
2195            return Err(crate::bind::schema_refused(
2196                "cannot UPSERT a view",
2197                Span::default(),
2198            ));
2199        }
2200        // A module decides for itself what a clash is, so there is no
2201        // constraint for a conflict target to name. SQLite refuses the clause
2202        // on a virtual table outright, in these words.
2203        if table.kind == TableKind::Virtual {
2204            return Err(crate::bind::schema_refused(
2205                format!(
2206                    "UPSERT not implemented for virtual table \"{}\"",
2207                    String::from_utf8_lossy(&table.name)
2208                ),
2209                Span::default(),
2210            ));
2211        }
2212        // A view has no constraint a clash could be found on, whether or not an
2213        // `INSTEAD OF INSERT` trigger lets it be written.
2214        if table.kind == TableKind::View {
2215            return Err(crate::bind::schema_refused(
2216                "cannot UPSERT a view",
2217                Span::default(),
2218            ));
2219        }
2220        // **Every clause is bound, in written order.** A statement may carry
2221        // several - `ON CONFLICT(k) DO UPDATE ... ON CONFLICT(id) DO UPDATE ...`
2222        // - and which one runs is decided at *run time*, by which constraint
2223        // the row actually collided with. Binding only the first was the whole
2224        // of the old refusal.
2225        // A clause with no conflict target matches any constraint, so anything
2226        // written after it could never run. SQLite refuses that rather than
2227        // accepting a clause it will never reach.
2228        if let Some(position) = insert
2229            .upserts
2230            .iter()
2231            .position(|upsert| upsert.target.is_empty())
2232        {
2233            if position + 1 < insert.upserts.len() {
2234                return Err(crate::bind::schema_refused(
2235                    "ON CONFLICT clause with no conflict target must be last",
2236                    Span::default(),
2237                ));
2238            }
2239        }
2240        // `excluded` is in scope for the assignments and the WHERE, and only
2241        // there. Setting it around the binding rather than pushing a second
2242        // FROM term keeps unqualified names resolving to the target row, which
2243        // is what SQLite does and what a second source would have made
2244        // ambiguous - every column of the target is also a column of
2245        // `excluded`.
2246        self.excluded = Some(table.clone());
2247        let mut bound = Vec::with_capacity(insert.upserts.len());
2248        for upsert in &insert.upserts {
2249            match self.bind_upsert_body(table, upsert) {
2250                Ok(Some(one)) => bound.push(one),
2251                Ok(None) => {}
2252                Err(error) => {
2253                    self.excluded = None;
2254                    return Err(error);
2255                }
2256            }
2257        }
2258        self.excluded = None;
2259        Ok(bound)
2260    }
2261
2262    /// Binds an upsert's target, assignments and filter.
2263    fn bind_upsert_body(
2264        &mut self,
2265        table: &TableInfo,
2266        upsert: &ast::Upsert,
2267    ) -> Result<Option<BoundUpsert>, ParseError> {
2268        let constraint = self.upsert_constraint(table, upsert)?;
2269        let mut assignments = Vec::new();
2270        for (names, value) in &upsert.assignments {
2271            let values = self.assigned_values(names, *value)?;
2272            for (name, bound) in names.iter().zip(values) {
2273                let folded = self.ast.folded(*name).to_vec();
2274                let Some(position) = table.column_position(&folded) else {
2275                    return Err(no_such_column(self.ast.text(*name), Span::default()));
2276                };
2277                assignments.push(BoundAssignment {
2278                    column: position,
2279                    rowid: false,
2280                    value: bound,
2281                });
2282            }
2283        }
2284        assignments.sort_by_key(|assignment| assignment.column);
2285        let filter = match upsert.filter {
2286            Some(expr) => Some(self.bind_expr(expr)?),
2287            None => None,
2288        };
2289        let triggers = match upsert.do_update {
2290            true => self.bind_upsert_update_triggers(table, &assignments)?,
2291            false => Vec::new(),
2292        };
2293        Ok(Some(BoundUpsert {
2294            constraint,
2295            assignments,
2296            do_update: upsert.do_update,
2297            filter,
2298            triggers,
2299        }))
2300    }
2301
2302    /// Binds the triggers a `DO UPDATE` fires, which are `UPDATE` triggers.
2303    ///
2304    /// **A conflict resolved by `DO UPDATE` is an update of the row already
2305    /// there.** SQLite fires the table's `BEFORE UPDATE` and `AFTER UPDATE`
2306    /// triggers for it, with the columns the clause assigns as the columns that
2307    /// changed, and does not fire `AFTER INSERT`. The foreign keys that watch
2308    /// an update are checked the same way.
2309    ///
2310    /// @param table - the table being inserted into
2311    /// @param assignments - the clause's assignments
2312    fn bind_upsert_update_triggers(
2313        &mut self,
2314        table: &TableInfo,
2315        assignments: &[BoundAssignment],
2316    ) -> Result<Vec<BoundTrigger>, ParseError> {
2317        let changed: Vec<Vec<u8>> = assignments
2318            .iter()
2319            .filter_map(|assignment| table.column(assignment.column))
2320            .map(|column| column.folded.clone())
2321            .collect();
2322        self.bind_update_triggers(table, &changed)
2323    }
2324
2325    /// Binds the triggers and foreign key checks an update of some columns fires.
2326    ///
2327    /// The application's triggers see the columns the statement assigns. The
2328    /// foreign keys see those and every generated column that reads one, because
2329    /// SQLite checks a key on a generated column again when its inputs change.
2330    ///
2331    /// @param table - the table being updated
2332    /// @param changed - the folded names of the columns the statement assigns
2333    fn bind_update_triggers(
2334        &mut self,
2335        table: &TableInfo,
2336        changed: &[Vec<u8>],
2337    ) -> Result<Vec<BoundTrigger>, ParseError> {
2338        let mut triggers =
2339            self.bind_triggers(table, TriggerEventInfo::Update(Vec::new()), changed)?;
2340        let key_changes = self.changed_with_generated(table, changed)?;
2341        triggers.extend(self.bind_foreign_keys(
2342            table,
2343            TriggerEventInfo::Update(Vec::new()),
2344            &key_changes,
2345        )?);
2346        Ok(triggers)
2347    }
2348
2349    /// Adds to the assigned columns every generated column that reads one.
2350    ///
2351    /// SQLite treats a generated column as changed when an `UPDATE` assigns a
2352    /// column its expression reads, and that is what decides whether a foreign
2353    /// key on the generated column has to be checked again. A user trigger's
2354    /// `UPDATE OF` list is not widened this way: it fires only for the columns
2355    /// the `SET` clause names, which is why the foreign key triggers get this
2356    /// list and the application's triggers do not.
2357    ///
2358    /// @param table - the table being updated
2359    /// @param changed - the folded names of the columns the statement assigns
2360    fn changed_with_generated(
2361        &mut self,
2362        table: &TableInfo,
2363        changed: &[Vec<u8>],
2364    ) -> Result<Vec<Vec<u8>>, ParseError> {
2365        let mut all = changed.to_vec();
2366        let mut reads: Vec<(Vec<u8>, Vec<u16>)> = Vec::new();
2367        for (position, column) in table.columns.iter().enumerate() {
2368            if !column.generated {
2369                continue;
2370            }
2371            let Some(expr) = self.generated_expr(table, position as u16)? else {
2372                continue;
2373            };
2374            let mut used = Vec::new();
2375            expr.columns_used(&mut used);
2376            reads.push((column.folded.clone(), used));
2377        }
2378        loop {
2379            let mut grew = false;
2380            for (name, used) in &reads {
2381                let reads_changed = used
2382                    .iter()
2383                    .filter_map(|held| table.column(*held))
2384                    .any(|held| all.contains(&held.folded));
2385                if reads_changed && !all.contains(name) {
2386                    all.push(name.clone());
2387                    grew = true;
2388                }
2389            }
2390            if !grew {
2391                return Ok(all);
2392            }
2393        }
2394    }
2395
2396    /// Finds the constraint an `ON CONFLICT` clause's target names.
2397    ///
2398    /// SQLite (`sqlite3UpsertAnalyzeTarget`) accepts a target that is the
2399    /// rowid, the rowid alias column, or exactly the keys of a unique index in
2400    /// any order. A key may be a column or an expression, and an expression is
2401    /// compared with the index's by its bound form, so `lower(name)` and
2402    /// `LOWER( name )` are the same key. A partial index is named only by a
2403    /// target whose `WHERE` is the index's own predicate. A `WHERE` on a target
2404    /// that names a complete index is ignored. A target that names no
2405    /// constraint is refused, because no insert could clash on it and the
2406    /// clause would never run.
2407    ///
2408    /// @param table - the table being inserted into
2409    /// @param upsert - the clause
2410    fn upsert_constraint(
2411        &mut self,
2412        table: &TableInfo,
2413        upsert: &ast::Upsert,
2414    ) -> Result<UpsertConstraint, ParseError> {
2415        if upsert.target.is_empty() {
2416            return Ok(UpsertConstraint::Any);
2417        }
2418        let terms = self.bind_target_terms(table, &upsert.target)?;
2419        let target_where = match upsert.target_filter {
2420            Some(expr) => Some(self.bind_expr(expr)?),
2421            None => None,
2422        };
2423        if names_own_key(table, &terms) {
2424            return Ok(UpsertConstraint::OwnKey);
2425        }
2426        for (position, index) in table.indexes.iter().enumerate() {
2427            if !self.index_matches_target(index, &terms, target_where.as_ref())? {
2428                continue;
2429            }
2430            return Ok(if index.root == table.root {
2431                UpsertConstraint::OwnKey
2432            } else {
2433                UpsertConstraint::Index(position)
2434            });
2435        }
2436        Err(crate::bind::schema_refused(
2437            "ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint",
2438            Span::default(),
2439        ))
2440    }
2441
2442    /// Binds each term of a conflict target against the table being inserted into.
2443    ///
2444    /// @param table - the table being inserted into
2445    /// @param target - the written terms
2446    fn bind_target_terms(
2447        &mut self,
2448        table: &TableInfo,
2449        target: &[ast::IndexedColumn],
2450    ) -> Result<Vec<TargetTerm>, ParseError> {
2451        let mut terms = Vec::with_capacity(target.len());
2452        for column in target {
2453            let collation = target_collation(self.ast, column);
2454            let operand = target_operand(self.ast, column);
2455            if let Some(ast::Expr::Column {
2456                table: None,
2457                column: name,
2458                ..
2459            }) = self.ast.expr(operand)
2460            {
2461                let folded = self.ast.folded(*name).to_vec();
2462                if let Some(position) = table.column_position(&folded) {
2463                    terms.push(TargetTerm::Column(position, collation));
2464                    continue;
2465                }
2466                if table.is_rowid_name(&folded) {
2467                    terms.push(TargetTerm::Rowid);
2468                    continue;
2469                }
2470                return Err(no_such_column(&folded, Span::default()));
2471            }
2472            terms.push(match self.bind_expr(operand)? {
2473                BoundExpr::Column { column, .. } => TargetTerm::Column(column, collation),
2474                BoundExpr::Rowid { .. } => TargetTerm::Rowid,
2475                other => TargetTerm::Expr(other, collation),
2476            });
2477        }
2478        Ok(terms)
2479    }
2480
2481    /// Reports whether a conflict target names exactly one unique index.
2482    ///
2483    /// @param index - the candidate
2484    /// @param terms - the bound target
2485    /// @param target_where - the target's own `WHERE`, bound
2486    fn index_matches_target(
2487        &mut self,
2488        index: &IndexInfo,
2489        terms: &[TargetTerm],
2490        target_where: Option<&BoundExpr>,
2491    ) -> Result<bool, ParseError> {
2492        if !index.unique || index.columns.len() != terms.len() {
2493            return Ok(false);
2494        }
2495        if let Some(sql) = index.partial_sql.as_ref() {
2496            let Some(wanted) = target_where else {
2497                return Ok(false);
2498            };
2499            if self.bind_schema_expr(sql)? != *wanted {
2500                return Ok(false);
2501            }
2502        }
2503        for key in &index.columns {
2504            // A key on a virtual generated column names the column, and a target
2505            // that names the column is the same constraint even though the index
2506            // computes its entries (`column` is set on both kinds of key).
2507            let found = match (key.column, key.expr_sql.as_ref()) {
2508                (Some(position), _) => terms.iter().any(|term| {
2509                    matches!(term, TargetTerm::Column(held, named)
2510                        if *held == position && collation_fits(named, &key.collation))
2511                }),
2512                (None, Some(sql)) => {
2513                    let bound = self.bind_schema_expr(sql)?;
2514                    terms.iter().any(|term| {
2515                        matches!(term, TargetTerm::Expr(held, named)
2516                            if *held == bound && collation_fits(named, &key.collation))
2517                    })
2518                }
2519                (None, None) => false,
2520            };
2521            if !found {
2522                return Ok(false);
2523            }
2524        }
2525        Ok(true)
2526    }
2527
2528    /// Binds the value of one `SET` assignment, one bound value per column it
2529    /// names.
2530    ///
2531    /// **`SET (a, b) = (1, 2)` and `SET (a, b) = (SELECT x, y ...)` assign
2532    /// the parts in order**, which is what SQLite does. Both were refused as
2533    /// `unsupported`, and no capability row said so. A list of values is
2534    /// bound part by part; a query is bound once and read column by column,
2535    /// so both columns take the same row. A count that does not match is
2536    /// SQLite's own refusal, "2 columns assigned 3 values".
2537    ///
2538    /// @param names - the columns the assignment names
2539    /// @param value - the expression after `=`
2540    fn assigned_values(
2541        &mut self,
2542        names: &[ast::NameId],
2543        value: ast::ExprId,
2544    ) -> Result<Vec<BoundExpr>, ParseError> {
2545        if names.len() == 1 {
2546            return Ok(vec![self.bind_expr(value)?]);
2547        }
2548        let span = self.ast.expr_span(value);
2549        let values = match self.ast.expr(value) {
2550            Some(ast::Expr::RowValue(parts)) => {
2551                let parts = parts.clone();
2552                let mut bound = Vec::with_capacity(parts.len());
2553                for part in parts {
2554                    bound.push(self.bind_expr(part)?);
2555                }
2556                bound
2557            }
2558            Some(ast::Expr::Subquery(select)) => {
2559                let select = *select;
2560                self.bind_query_columns(select, span)?
2561            }
2562            _ => vec![self.bind_expr(value)?],
2563        };
2564        if values.len() != names.len() {
2565            // No position: SQLite's message for this carries no caret.
2566            return Err(refused(
2567                format!("{} columns assigned {} values", names.len(), values.len()),
2568                Span::default(),
2569            ));
2570        }
2571        Ok(values)
2572    }
2573
2574    /// Binds a `RETURNING` list, which is a result-column list over the row
2575    /// that was written.
2576    fn bind_returning(
2577        &mut self,
2578        columns: &[ast::ResultColumn],
2579    ) -> Result<Vec<BoundResultColumn>, ParseError> {
2580        if columns.is_empty() {
2581            return Ok(Vec::new());
2582        }
2583        // **`table.*` is refused, as SQLite refuses it.** A `RETURNING` list
2584        // may use a bare `*` and may not qualify it; SQLite answers
2585        // `RETURNING may not use "TABLE.*" wildcards` with code 1, and binding
2586        // it as a select list would have returned the rows.
2587        for column in columns {
2588            if let Some(ast::Expr::Star { table: Some(_) }) = self.ast.expr(column.expr) {
2589                return Err(refused(
2590                    "RETURNING may not use \"TABLE.*\" wildcards",
2591                    Span::default(),
2592                ));
2593            }
2594        }
2595        for column in columns {
2596            self.refuse_schema_qualified_column(column.expr)?;
2597        }
2598        self.bind_result_columns_public(columns)
2599    }
2600
2601    /// Refuses a column written with a schema name inside a `RETURNING` expression.
2602    ///
2603    /// SQLite resolves `RETURNING` names against the table being changed alone, so `main.users.id`
2604    /// there is `no such column: main.users.id` although the same name works in a `SELECT`.
2605    ///
2606    /// @param expr - the root of one `RETURNING` expression
2607    fn refuse_schema_qualified_column(&self, expr: ast::ExprId) -> Result<(), ParseError> {
2608        if let Some(ast::Expr::Column {
2609            database: Some(database),
2610            table,
2611            column,
2612        }) = self.ast.expr(expr)
2613        {
2614            let written = [Some(*database), *table, Some(*column)]
2615                .iter()
2616                .flatten()
2617                .map(|name| String::from_utf8_lossy(self.ast.text(*name)).into_owned())
2618                .collect::<Vec<_>>()
2619                .join(".");
2620            return Err(refused(
2621                format!("no such column: {written}"),
2622                Span::default(),
2623            ));
2624        }
2625        for child in crate::directive::expression_children(self.ast, expr) {
2626            self.refuse_schema_qualified_column(child)?;
2627        }
2628        Ok(())
2629    }
2630}
2631
2632/// Returns the collation a conflict target's column names, folded.
2633///
2634/// It may be written as the indexed column's own `COLLATE` or as a `COLLATE`
2635/// around the name; SQLite reads both as the same expression.
2636///
2637/// @param ast - the statement's arena
2638/// @param column - one column of the conflict target
2639fn target_collation(ast: &crate::Ast, column: &ast::IndexedColumn) -> Option<Vec<u8>> {
2640    if let Some(name) = column.collation {
2641        return Some(ast.folded(name).to_vec());
2642    }
2643    match ast.expr(column.expr) {
2644        Some(ast::Expr::Collate { collation, .. }) => Some(ast.folded(*collation).to_vec()),
2645        _ => None,
2646    }
2647}
2648
2649/// Returns the expression of a conflict target term with any `COLLATE` around
2650/// it removed.
2651///
2652/// A conflict target may name its collation by wrapping the term in `COLLATE`;
2653/// `target_collation` reads the name, and the term is what is compared with an
2654/// index key.
2655///
2656/// @param ast - the statement's arena
2657/// @param column - one term of the conflict target
2658fn target_operand(ast: &crate::Ast, column: &ast::IndexedColumn) -> ast::ExprId {
2659    match ast.expr(column.expr) {
2660        Some(ast::Expr::Collate { operand, .. }) => *operand,
2661        _ => column.expr,
2662    }
2663}
2664
2665/// Reports whether a bound conflict target names the table's own key.
2666///
2667/// That is `rowid` alone, or the rowid alias column alone with no collation. A
2668/// collation on the alias never matches it, which is how
2669/// `sqlite3UpsertAnalyzeTarget` compares them. A `WITHOUT ROWID` table has no
2670/// rowid, so its key is matched through its primary key index instead.
2671///
2672/// @param table - the table being inserted into
2673/// @param terms - the bound target
2674fn names_own_key(table: &TableInfo, terms: &[TargetTerm]) -> bool {
2675    if table.without_rowid {
2676        return false;
2677    }
2678    match terms {
2679        [TargetTerm::Rowid] => true,
2680        [TargetTerm::Column(column, None)] => table.rowid_alias == Some(*column),
2681        _ => false,
2682    }
2683}
2684
2685/// One term of a conflict target after it is bound.
2686enum TargetTerm {
2687    /// A column of the table, by declared position, with the collation it names.
2688    Column(u16, Option<Vec<u8>>),
2689    /// The rowid, written as `rowid`, `oid` or `_rowid_`.
2690    Rowid,
2691    /// Any other expression, with the collation it names.
2692    Expr(BoundExpr, Option<Vec<u8>>),
2693}
2694
2695/// Reports whether a collation a target term names fits an index key.
2696///
2697/// A term that names none fits any key.
2698///
2699/// @param named - the collation the term names, folded
2700/// @param key_collation - the collation the index key is ordered by, folded
2701fn collation_fits(named: &Option<Vec<u8>>, key_collation: &[u8]) -> bool {
2702    named
2703        .as_deref()
2704        .is_none_or(|name| name.eq_ignore_ascii_case(key_collation))
2705}
2706
2707/// The extended result codes a rejected write reports.
2708///
2709/// The numbers are SQLite's own extended codes. They are written out rather
2710/// than derived because an application matches on them, and a code that was
2711/// computed from an enum's discriminant would change the day the enum did.
2712///
2713/// They live here, beside the binder that decides which constraint a statement
2714/// can violate, because **both** engines report them: the virtual machine
2715/// compiles them into a `HaltError` and the vectorised executor returns them
2716/// from its write path. Two copies would agree until one of them was corrected.
2717pub mod codes {
2718    /// `SQLITE_CONSTRAINT_CHECK`.
2719    pub const CHECK: i32 = 275;
2720    /// `SQLITE_CONSTRAINT_DATATYPE`, which a STRICT table reports.
2721    pub const DATATYPE: i32 = 3091;
2722    /// `SQLITE_CONSTRAINT_NOTNULL`.
2723    pub const NOT_NULL: i32 = 1299;
2724    /// `SQLITE_CONSTRAINT_PRIMARYKEY`.
2725    pub const PRIMARY_KEY: i32 = 1555;
2726    /// `SQLITE_CONSTRAINT_UNIQUE`.
2727    pub const UNIQUE: i32 = 2067;
2728    /// `SQLITE_CONSTRAINT_ROWID`.
2729    pub const ROWID: i32 = 2579;
2730    /// `SQLITE_MISMATCH`, which an `INTEGER PRIMARY KEY` reports for a value
2731    /// that is not an integer.
2732    pub const MISMATCH: i32 = 20;
2733    /// `SQLITE_CONSTRAINT_TRIGGER`, which `RAISE()` reports.
2734    pub const TRIGGER: i32 = 1811;
2735    /// `SQLITE_CONSTRAINT_FOREIGNKEY`.
2736    pub const FOREIGN_KEY: i32 = 787;
2737}
2738
2739/// Returns the message a unique-index violation reports.
2740///
2741/// SQLite names every column of the index, comma separated, which is what an
2742/// application parses to find out which key collided.
2743///
2744/// @param table - the table the index belongs to
2745/// @param index - the index whose key collided
2746pub fn unique_message(table: &TableInfo, index: &IndexInfo) -> String {
2747    // **An index with an expression in its key names the index, not columns.**
2748    // SQLite has no column to print for `lower(a)`, so it says `UNIQUE constraint
2749    // failed: index 'i'`; the columns of a plain key come out as `t.a, t.b`. The
2750    // engine printed the empty list of the column keys, and for a mixed key left the
2751    // expression out of the list.
2752    if index.columns.iter().any(|key| key.column.is_none()) {
2753        return format!(
2754            "UNIQUE constraint failed: index '{}'",
2755            String::from_utf8_lossy(&index.name)
2756        );
2757    }
2758    let names: Vec<String> = index
2759        .columns
2760        .iter()
2761        .filter_map(|key| key.column)
2762        .filter_map(|column| table.column(column))
2763        .map(|column| {
2764            format!(
2765                "{}.{}",
2766                String::from_utf8_lossy(&table.name),
2767                String::from_utf8_lossy(&column.name)
2768            )
2769        })
2770        .collect();
2771    format!("UNIQUE constraint failed: {}", names.join(", "))
2772}
2773
2774/// Returns the message a duplicate rowid reports, and its extended code.
2775///
2776/// SQLite names the aliasing column when the table has an `INTEGER PRIMARY
2777/// KEY` - and reports `SQLITE_CONSTRAINT_PRIMARYKEY` for it - and names the
2778/// hidden `rowid` under `SQLITE_CONSTRAINT_ROWID` when it does not.
2779///
2780/// **A `WITHOUT ROWID` table has no rowid to name.** Its own key *is* its
2781/// primary key, held in the one index whose root is the table's, so a collision
2782/// reports every column of that key under `SQLITE_CONSTRAINT_PRIMARYKEY` -
2783/// `UNIQUE constraint failed: t.a, t.b`. It used to answer `t.rowid`, naming a
2784/// column the table does not have, on `INSERT` as well as `UPDATE`.
2785///
2786/// @param table - the table whose key collided
2787pub fn rowid_message(table: &TableInfo) -> (i32, String) {
2788    if table.without_rowid {
2789        if let Some(index) = table.indexes.iter().find(|index| index.root == table.root) {
2790            return (codes::PRIMARY_KEY, unique_message(table, index));
2791        }
2792    }
2793    match table.rowid_alias.and_then(|column| table.column(column)) {
2794        Some(column) => (
2795            codes::PRIMARY_KEY,
2796            format!(
2797                "UNIQUE constraint failed: {}.{}",
2798                String::from_utf8_lossy(&table.name),
2799                String::from_utf8_lossy(&column.name)
2800            ),
2801        ),
2802        None => (
2803            codes::ROWID,
2804            format!(
2805                "UNIQUE constraint failed: {}.rowid",
2806                String::from_utf8_lossy(&table.name)
2807            ),
2808        ),
2809    }
2810}
2811
2812/// Joins the `FROM` terms of an `UPDATE ... FROM` to the query that finds a
2813/// view's rows, and projects the assigned values after the view's columns.
2814///
2815/// **A view has no tree to read a joined row's values from later**, so the
2816/// values each assignment computes travel with the row, as they do for a table
2817/// in `keys_query_joined`: the row is the view's columns followed by one value
2818/// per assignment, in assignment order. SQLite fires the `INSTEAD OF UPDATE`
2819/// trigger once for every row of the join, so a view row matched twice fires
2820/// twice.
2821///
2822/// @param rows - the query over the view the binder built
2823/// @param joined - the `FROM` terms, empty for an ordinary `UPDATE`
2824/// @param assignments - the bound assignments, whose values are projected
2825fn join_view_rows(
2826    mut rows: Box<BoundSelect>,
2827    joined: &[crate::bind::BoundSource],
2828    assignments: &[BoundAssignment],
2829) -> Box<BoundSelect> {
2830    if joined.is_empty() {
2831        return rows;
2832    }
2833    rows.sources.extend(joined.iter().cloned());
2834    rows.columns
2835        .extend(assignments.iter().map(|assignment| BoundResultColumn {
2836            expr: assignment.value.clone(),
2837            name: b"value".to_vec(),
2838            origin: None,
2839            declared_type: Vec::new(),
2840            written: None,
2841        }));
2842    rows
2843}
2844
2845/// Puts a limited write's order, limit and offset on the query that finds a
2846/// view's rows.
2847///
2848/// A write through a view's `INSTEAD OF` trigger fires once per row the view
2849/// produces under the statement's `WHERE`, so a `LIMIT` on the write limits
2850/// that query. SQLite's `sqlite3MaterializeView` is handed the same three
2851/// clauses for the same reason.
2852///
2853/// @param rows - the query over the view the binder built
2854/// @param order_by - the statement's bound `ORDER BY`
2855/// @param limit - the statement's bound `LIMIT`
2856/// @param offset - the statement's bound `OFFSET`
2857fn limit_view_rows(
2858    mut rows: Box<BoundSelect>,
2859    order_by: &[BoundOrderTerm],
2860    limit: &Option<BoundExpr>,
2861    offset: &Option<BoundExpr>,
2862) -> Box<BoundSelect> {
2863    rows.order_by = order_by.to_vec();
2864    rows.limit = limit.clone();
2865    rows.offset = offset.clone();
2866    rows
2867}
2868
2869/// Returns the refusal a `DELETE` or `UPDATE` with `ORDER BY` and no `LIMIT`
2870/// earns, or `None` when the clause is allowed.
2871///
2872/// **`ORDER BY` and `LIMIT` on a write are run, not refused (task-2120).** They
2873/// were refused in the pinned reference's words, `near "ORDER": syntax error`,
2874/// because that build is not compiled with `SQLITE_ENABLE_UPDATE_DELETE_LIMIT`
2875/// and has no grammar for the clause. But the builds applications actually link
2876/// often are - Apple's is - and `DELETE FROM t WHERE ... LIMIT 1000` in a loop
2877/// is the ordinary way to trim a large table without one large transaction. A
2878/// consumer probing 0.1.8 against the macOS `sqlite3` reported the refusal as a
2879/// real gap, which it was.
2880///
2881/// What remains is the one rule a build compiled with the option enforces:
2882/// an order with nothing to limit is refused, in SQLite's own words, because
2883/// sorting the rows a statement changes all of changes nothing.
2884///
2885/// @param limited - which of the two words came first and where, from the parser
2886/// @param limit - the statement's `LIMIT`, when it wrote one
2887/// @param statement - `DELETE` or `UPDATE`, for the message
2888fn order_without_limit(
2889    limited: Option<(ast::Limited, Span)>,
2890    limit: Option<ast::ExprId>,
2891    statement: &str,
2892) -> Option<ParseError> {
2893    let (word, span) = limited?;
2894    if word != ast::Limited::OrderBy || limit.is_some() {
2895        return None;
2896    }
2897    Some(refused(
2898        format!("ORDER BY without LIMIT on {statement}"),
2899        span,
2900    ))
2901}
2902
2903/// Refuses `RETURNING` on an `UPDATE` or a `DELETE` of a virtual table.
2904///
2905/// SQLite refuses both when it prepares the statement, before it looks at
2906/// anything else in it, so a statement with a subquery in its `SET` gets this
2907/// message and not one about the subquery. An `INSERT` into a virtual table
2908/// may return rows, and is not refused here.
2909///
2910/// @param table - the table being written
2911/// @param returning - the statement's `RETURNING` list, empty when it has none
2912/// @param statement - `UPDATE` or `DELETE`, for the message
2913fn refuse_module_returning(
2914    table: &TableInfo,
2915    returning: &[ast::ResultColumn],
2916    statement: &str,
2917) -> Result<(), ParseError> {
2918    if table.kind != TableKind::Virtual || returning.is_empty() {
2919        return Ok(());
2920    }
2921    Err(crate::bind::schema_refused(
2922        format!("{statement} RETURNING is not available on virtual tables"),
2923        Span::default(),
2924    ))
2925}
2926
2927#[cfg(test)]
2928mod tests {
2929    use super::*;
2930    use crate::catalog_view::{
2931        ColumnInfo, IndexColumnInfo, IndexInfo, IndexOrigin, TableInfo, TableKind,
2932    };
2933    use inillucent_value::Affinity;
2934
2935    /// Returns one plain column.
2936    ///
2937    /// @param name - the column's name
2938    fn a_column(name: &str) -> ColumnInfo {
2939        ColumnInfo {
2940            name: name.as_bytes().to_vec(),
2941            folded: name.to_ascii_lowercase().into_bytes(),
2942            declared_type: b"INTEGER".to_vec(),
2943            affinity: Affinity::Integer,
2944            collation: b"binary".to_vec(),
2945            not_null: false,
2946            not_null_conflict: None,
2947            primary_key_conflict: None,
2948            default_sql: None,
2949            primary_key_position: None,
2950            hidden: false,
2951            generated: false,
2952            stored: false,
2953            generated_sql: None,
2954        }
2955    }
2956
2957    /// Returns a rowid table with the columns named.
2958    ///
2959    /// @param name - the table's name
2960    /// @param columns - the column names, in declaration order
2961    fn a_table(name: &str, columns: &[&str]) -> TableInfo {
2962        TableInfo {
2963            name: name.as_bytes().to_vec(),
2964            folded: name.to_ascii_lowercase().into_bytes(),
2965            database: 0,
2966            root: 2,
2967            columns: columns.iter().map(|held| a_column(held)).collect(),
2968            rowid_alias: None,
2969            without_rowid: false,
2970            strict: false,
2971            autoincrement: false,
2972            kind: TableKind::Table,
2973            create_sql: Vec::new(),
2974            indexes: Vec::new(),
2975            view: None,
2976            triggers: Vec::new(),
2977            analysed_rows: None,
2978            foreign_key_triggers: Vec::new(),
2979            foreign_keys: Vec::new(),
2980            checks: Vec::new(),
2981            module: None,
2982        }
2983    }
2984
2985    /// Returns an index over the table columns named.
2986    ///
2987    /// @param name - the index's name
2988    /// @param root - its own tree, or the table's for a `WITHOUT ROWID` key
2989    /// @param columns - the table columns it keys on
2990    fn an_index(name: &str, root: u32, columns: &[u16]) -> IndexInfo {
2991        IndexInfo {
2992            name: name.as_bytes().to_vec(),
2993            folded: name.to_ascii_lowercase().into_bytes(),
2994            root,
2995            unique: true,
2996            columns: columns
2997                .iter()
2998                .map(|held| IndexColumnInfo {
2999                    column: Some(*held),
3000                    expr_sql: None,
3001                    collation: b"binary".to_vec(),
3002                    descending: false,
3003                    declared_descending: false,
3004                })
3005                .collect(),
3006            partial_sql: None,
3007            origin: IndexOrigin::Unique,
3008            conflict: None,
3009            prefix_rows: Vec::new(),
3010            analysed_rows: None,
3011            metric: None,
3012        }
3013    }
3014
3015    /// The three spellings of the rowid are the three SQLite accepts.
3016    ///
3017    /// **A fourth would be a column name a table could not have (T3,
3018    /// task-1962).** `rowid`, `oid` and `_rowid_` all name the hidden key, and
3019    /// a table that declares a column called any of them shadows it - so the
3020    /// list decides which names a `SELECT rowid` can mean.
3021    #[test]
3022    fn the_rowid_has_three_names() {
3023        assert!(is_rowid_name(b"rowid"));
3024        assert!(is_rowid_name(b"oid"));
3025        assert!(is_rowid_name(b"_rowid_"));
3026        assert!(!is_rowid_name(b"row_id"));
3027        assert!(!is_rowid_name(b"id"));
3028        assert!(
3029            !is_rowid_name(b"ROWID"),
3030            "the argument is already folded, so an unfolded name is not one this asks about"
3031        );
3032    }
3033
3034    /// A unique violation names every column of the index, table-qualified.
3035    ///
3036    /// **The message is what an application matches on.** SQLite's wording is
3037    /// `UNIQUE constraint failed: t.a, t.b`, and a library that switched on it
3038    /// would stop recognising a collision if the columns were listed any other
3039    /// way.
3040    #[test]
3041    fn a_unique_violation_names_every_column_of_the_index() {
3042        let table = a_table("t", &["a", "b", "c"]);
3043        let one = an_index("by_a", 3, &[0]);
3044        assert_eq!(
3045            unique_message(&table, &one),
3046            "UNIQUE constraint failed: t.a"
3047        );
3048        let two = an_index("by_a_b", 4, &[0, 1]);
3049        assert_eq!(
3050            unique_message(&table, &two),
3051            "UNIQUE constraint failed: t.a, t.b",
3052            "both columns, in key order, separated the way the reference separates them"
3053        );
3054    }
3055
3056    /// A rowid collision names the aliasing column when there is one, and the
3057    /// hidden `rowid` when there is not.
3058    ///
3059    /// The extended code differs with it: `SQLITE_CONSTRAINT_PRIMARYKEY` for an
3060    /// `INTEGER PRIMARY KEY` and `SQLITE_CONSTRAINT_ROWID` for the hidden one.
3061    #[test]
3062    fn a_rowid_collision_names_the_column_that_aliases_it() {
3063        let hidden = a_table("t", &["a"]);
3064        assert_eq!(
3065            rowid_message(&hidden),
3066            (
3067                codes::ROWID,
3068                "UNIQUE constraint failed: t.rowid".to_string()
3069            )
3070        );
3071        let mut aliased = a_table("t", &["id", "a"]);
3072        aliased.rowid_alias = Some(0);
3073        assert_eq!(
3074            rowid_message(&aliased),
3075            (
3076                codes::PRIMARY_KEY,
3077                "UNIQUE constraint failed: t.id".to_string()
3078            )
3079        );
3080    }
3081
3082    /// A `WITHOUT ROWID` table has no rowid to name, so it names its key.
3083    ///
3084    /// **It used to answer `t.rowid`, naming a column the table does not
3085    /// have.** Its own key *is* its primary key, held in the one index whose
3086    /// root is the table's.
3087    #[test]
3088    fn a_without_rowid_collision_names_the_primary_key() {
3089        let mut table = a_table("t", &["a", "b"]);
3090        table.without_rowid = true;
3091        table.indexes = vec![an_index("sqlite_autoindex_t_1", table.root, &[0, 1])];
3092        assert_eq!(
3093            rowid_message(&table),
3094            (
3095                codes::PRIMARY_KEY,
3096                "UNIQUE constraint failed: t.a, t.b".to_string()
3097            )
3098        );
3099    }
3100
3101    /// A constraint's own `ON CONFLICT REPLACE` makes a statement able to
3102    /// replace, with no `OR REPLACE` written anywhere.
3103    #[test]
3104    fn a_constraint_can_make_a_plain_insert_replace() {
3105        let plain = a_table("t", &["a"]);
3106        assert!(!can_replace(&plain, None));
3107        assert!(can_replace(&plain, Some(ConflictAction::Replace)));
3108
3109        let mut on_the_index = a_table("t", &["a"]);
3110        let mut index = an_index("by_a", 3, &[0]);
3111        index.conflict = Some(ConflictAction::Replace);
3112        on_the_index.indexes = vec![index];
3113        assert!(
3114            can_replace(&on_the_index, None),
3115            "`a UNIQUE ON CONFLICT REPLACE` replaces without the statement saying so"
3116        );
3117
3118        let mut on_the_column = a_table("t", &["a"]);
3119        if let Some(column) = on_the_column.columns.first_mut() {
3120            column.not_null_conflict = Some(ConflictAction::Replace);
3121        }
3122        assert!(can_replace(&on_the_column, None));
3123    }
3124}