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, BoundResultColumn, BoundSelect,
25    BoundSource,
26};
27use crate::catalog_view::{IndexInfo, TableInfo, TableKind, TriggerEventInfo, TriggerInfo};
28use crate::diagnostic::{ParseError, ParseErrorKind};
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/// The expressions one index needs evaluated per row to be maintained.
125///
126/// **An index is usually just columns of the row, and then it needs none of
127/// this.** A partial index holds only the rows its predicate accepts, and an
128/// index on an expression holds a value no column carries - so for those two,
129/// maintaining the index means evaluating something per row rather than
130/// copying a slot. They travel on the bound statement for the same reason the
131/// table's `CHECK` predicates do: the binder is what can turn schema text into
132/// a `BoundExpr`, and the write path is what runs it.
133///
134/// The list holds only the indexes that need it, so a table with neither kind
135/// leaves it empty and the write path's loop runs zero times - which is every
136/// table the gate measures.
137#[derive(Clone, Debug, PartialEq)]
138pub struct BoundIndexExprs {
139    /// The index's position in the table's `indexes`.
140    pub position: usize,
141    /// The partial-index predicate, when it has one.
142    pub predicate: Option<BoundExpr>,
143    /// One per key column: the expression it indexes, or `None` for a column.
144    pub keys: Vec<Option<BoundExpr>>,
145}
146
147/// One statement of a trigger body, bound.
148///
149/// The four the grammar allows and no more. A trigger body is not a general
150/// statement list: it cannot create objects, cannot open transactions, and
151/// cannot return rows to the caller, so a variant for anything else would be a
152/// shape the binder is required to refuse.
153#[derive(Clone, Debug, PartialEq)]
154pub enum BoundTriggerStatement {
155    /// `INSERT`.
156    Insert(Box<BoundInsert>),
157    /// `UPDATE`.
158    Update(Box<BoundUpdate>),
159    /// `DELETE`.
160    Delete(Box<BoundDelete>),
161    /// `SELECT`, which a body runs for its side effects - in practice for the
162    /// `RAISE()` inside it.
163    Select(Box<BoundSelect>),
164}
165
166/// A trigger, bound against the write that fires it.
167///
168/// It is bound per statement rather than once per schema because the body's
169/// FROM terms take statement-wide source numbers, and those only exist relative
170/// to the statement they are inlined into.
171#[derive(Clone, Debug, PartialEq)]
172pub struct BoundTrigger {
173    /// The trigger's name, for the diagnostic when its body fails.
174    pub name: Vec<u8>,
175    /// The folded name of the table it is attached to.
176    ///
177    /// Read by the executor to decide whether a body statement is writing the
178    /// trigger's *own* table, which is what `PRAGMA recursive_triggers` is
179    /// about: with it on, such a write fires this trigger again.
180    pub table: Vec<u8>,
181    /// Whether it fires before or after the row is written.
182    pub time: ast::TriggerTime,
183    /// The `WHEN` guard, when one was written.
184    pub when: Option<BoundExpr>,
185    /// The body statements, in written order.
186    pub body: Vec<BoundTriggerStatement>,
187    /// Whether the binder synthesised this from a `REFERENCES` clause rather
188    /// than reading it from a `CREATE TRIGGER`.
189    ///
190    /// **Read by `DROP TABLE` (task-1979, F6).** Dropping a table with foreign
191    /// keys on runs an implicit `DELETE FROM` first, so the keys that reference
192    /// it are enforced - and SQLite's rule is that the implicit delete fires no
193    /// triggers of its own while still performing every foreign key action. A
194    /// delete bound for that purpose keeps the triggers this flag marks and
195    /// drops the rest.
196    pub foreign_key: bool,
197    /// Whether the foreign key this enforces has one table as both its child
198    /// and its parent.
199    ///
200    /// **Also read by `DROP TABLE` (task-1979, F6).** The implicit delete keeps
201    /// the foreign key triggers and drops this one, because emptying a table
202    /// cannot leave a row of that same table pointing at nothing - see
203    /// `ForeignKeyTrigger::self_referencing`, which is where the value comes
204    /// from. Always false on a trigger the schema wrote.
205    pub self_referencing: bool,
206}
207
208/// A bound `INSERT`.
209#[derive(Clone, Debug, PartialEq)]
210pub struct BoundInsert {
211    /// The table being written.
212    pub table: TableInfo,
213    /// The statement-wide number of the FROM term being written.
214    ///
215    /// It used to be implicitly zero, because a DML statement had exactly one
216    /// source. A trigger body is compiled into the statement that fires it, so
217    /// its target takes the next number after the firing statement's - and a
218    /// compiler that assumed zero read the wrong cursor for every fire after
219    /// the first.
220    pub target_source: usize,
221    /// Where each table column's value comes from, in column order.
222    pub columns: Vec<ColumnSource>,
223    /// Where the rowid comes from, when the statement supplies one.
224    pub rowid: Option<ColumnSource>,
225    /// Which value of the supplied row is the rowid, when the statement named
226    /// it outright.
227    ///
228    /// `INSERT INTO t(rowid, a) VALUES (7, 'x')` is legal on any rowid table,
229    /// including one with no `INTEGER PRIMARY KEY` to alias it and including a
230    /// virtual table. It is recorded separately from `rowid` because it is not
231    /// a column: nothing writes it into the record.
232    pub named_rowid: Option<usize>,
233    /// The rows.
234    pub source: BoundInsertSource,
235    /// How many values each source row supplies.
236    pub arity: usize,
237    /// The statement's conflict algorithm, when it wrote one.
238    pub on_conflict: Option<ConflictAction>,
239    /// The table's `CHECK` constraints.
240    pub checks: Vec<BoundCheck>,
241    /// The `DEFAULT`s a `REPLACE` may stand in for a NULL, by column.
242    pub not_null_defaults: Vec<BoundDefault>,
243    /// The expressions the table's partial and expression indexes need.
244    pub index_exprs: Vec<BoundIndexExprs>,
245    /// The `ON CONFLICT ... DO UPDATE` clause, when there is one.
246    pub upsert: Vec<BoundUpsert>,
247    /// `sqlite_sequence`'s root page, when the target is `AUTOINCREMENT`.
248    ///
249    /// Resolved here rather than in the compiler because it is a fact about the
250    /// catalog, and the catalog is what the binder holds. It is zero for every
251    /// other table, which is also what it reads as before the first
252    /// `AUTOINCREMENT` table in a database is created.
253    pub sequence_root: u32,
254    /// The `RETURNING` columns.
255    pub returning: Vec<BoundResultColumn>,
256    /// The triggers this write fires, in schema order.
257    pub triggers: Vec<BoundTrigger>,
258    /// The foreign-key actions a `REPLACE` fires for the row it removes.
259    ///
260    /// A `REPLACE` that deletes a row to make room for another is a delete,
261    /// and the keys pointing at that row have to be told. Written `DELETE`
262    /// triggers are *not* fired - that is SQLite's rule with its default
263    /// `recursive_triggers = off` - so these are only the ones a key implies.
264    pub replace_triggers: Vec<BoundTrigger>,
265}
266
267/// A bound `ON CONFLICT ... DO UPDATE` clause.
268#[derive(Clone, Debug, PartialEq)]
269pub struct BoundUpsert {
270    /// The conflict target columns, when written; empty means any constraint.
271    ///
272    /// Sorted, because a conflict target names a *set* of columns and
273    /// `ON CONFLICT(a,b)` and `ON CONFLICT(b,a)` name the same one. Matching
274    /// them against an index's columns is a set comparison, and sorting here
275    /// is what makes it one comparison rather than a search per column.
276    pub target: Vec<u16>,
277    /// The assignments, or empty for `DO NOTHING`.
278    pub assignments: Vec<BoundAssignment>,
279    /// Whether the action is `DO UPDATE`.
280    pub do_update: bool,
281    /// The `WHERE` on the `DO UPDATE`.
282    pub filter: Option<BoundExpr>,
283}
284
285/// One `SET` assignment.
286#[derive(Clone, Debug, PartialEq)]
287pub struct BoundAssignment {
288    /// The column being assigned, as a declared position.
289    pub column: u16,
290    /// Whether the assignment names the row's own rowid rather than a declared
291    /// column, in which case `column` says nothing.
292    ///
293    /// **`UPDATE t SET rowid = 100` was `no such column: rowid` (task-1979,
294    /// F9).** An assignment target was looked up with `column_position`, which
295    /// only knows the columns the table declares, and a table with no INTEGER
296    /// PRIMARY KEY declares none for its rowid. SQLite accepts all three
297    /// spellings of the rowid on either kind of table and moves the row to the
298    /// new key.
299    pub rowid: bool,
300    /// The new value.
301    pub value: BoundExpr,
302}
303
304/// A bound `UPDATE`.
305#[derive(Clone, Debug, PartialEq)]
306pub struct BoundUpdate {
307    /// The table being written.
308    pub table: TableInfo,
309    /// The statement-wide number of the FROM term being written.
310    ///
311    /// It used to be implicitly zero, because a DML statement had exactly one
312    /// source. A trigger body is compiled into the statement that fires it, so
313    /// its target takes the next number after the firing statement's - and a
314    /// compiler that assumed zero read the wrong cursor for every fire after
315    /// the first.
316    pub source: usize,
317    /// The extra FROM terms of an `UPDATE ... FROM`, in written order.
318    ///
319    /// **The rows being updated come from a join.** `UPDATE t SET v = s.v FROM s
320    /// WHERE s.a = t.a` is the shape a migration writes to copy a column across
321    /// tables, and the values it assigns are not expressions over the target
322    /// row: they read a *different* row, one the join found. So the query that
323    /// finds the keys carries these terms too, and projects the assigned values
324    /// beside the key; see [`BoundUpdate::from`], which is this field.
325    ///
326    /// Empty for every ordinary `UPDATE`, which is what keeps the wider row off
327    /// the path the gate's `txn.large` measures.
328    pub from: Vec<crate::bind::BoundSource>,
329    /// The assignments, in table column order with duplicates already refused.
330    pub assignments: Vec<BoundAssignment>,
331    /// The `STORED` generated columns, recomputed after the assignments.
332    ///
333    /// **A stored generated column is part of the row, so a row that is
334    /// rewritten rewrites it (task-1913).** It is never named in a `SET`, so
335    /// an `UPDATE` used to leave whatever was written when the row was
336    /// inserted: `c GENERATED ALWAYS AS (a + 1) STORED` still read 2 after
337    /// `UPDATE g SET a = 5`, where SQLite reads 6. The wrong value is on the
338    /// disk rather than in an answer, so a later read of the same file is
339    /// wrong too, and an index on the column indexes the stale value.
340    ///
341    /// A `VIRTUAL` column is not here: it has no slot in the record and is
342    /// computed when it is read, which is why only this half needed fixing.
343    ///
344    /// These are evaluated against the row *after* the assignments, which is
345    /// the one difference from [`BoundUpdate::assignments`] - those read the
346    /// before image so `SET a = b, b = a` swaps.
347    pub generated: Vec<BoundAssignment>,
348    /// The `WHERE` clause.
349    pub filter: Option<BoundExpr>,
350    /// The statement's conflict algorithm, when it wrote one.
351    pub on_conflict: Option<ConflictAction>,
352    /// The table's `CHECK` constraints.
353    pub checks: Vec<BoundCheck>,
354    /// The `DEFAULT`s a `REPLACE` may stand in for a NULL, by column.
355    pub not_null_defaults: Vec<BoundDefault>,
356    /// The expressions the table's partial and expression indexes need.
357    pub index_exprs: Vec<BoundIndexExprs>,
358    /// `INDEXED BY` or `NOT INDEXED` on the target, which the query that finds
359    /// the rows to change obeys; `inillucent_exec::dml::hint_target` puts it there.
360    pub index_hint: crate::bind::IndexChoice,
361    /// The `RETURNING` columns.
362    pub returning: Vec<BoundResultColumn>,
363    /// The `LIMIT`.
364    pub limit: Option<BoundExpr>,
365    /// The `OFFSET`.
366    pub offset: Option<BoundExpr>,
367    /// The triggers this write fires, in schema order.
368    pub triggers: Vec<BoundTrigger>,
369    /// The rows to fire an `INSTEAD OF` trigger for, when the target is a view.
370    ///
371    /// A view has no rows of its own, so `OLD` has to come from running the
372    /// view. This is that query, with the statement's `WHERE` on it and one
373    /// result column per view column.
374    pub view_rows: Option<Box<BoundSelect>>,
375}
376
377/// A bound `DELETE`.
378#[derive(Clone, Debug, PartialEq)]
379pub struct BoundDelete {
380    /// The table being written.
381    pub table: TableInfo,
382    /// The expressions the table's partial and expression indexes need.
383    ///
384    /// A delete needs them too: an entry only comes out of a partial index if
385    /// the row was in it, and a key the index computed has to be recomputed to
386    /// be found.
387    pub index_exprs: Vec<BoundIndexExprs>,
388    /// `INDEXED BY` or `NOT INDEXED` on the target, as on [`BoundUpdate`].
389    pub index_hint: crate::bind::IndexChoice,
390    /// The statement-wide number of the FROM term being written.
391    ///
392    /// It used to be implicitly zero, because a DML statement had exactly one
393    /// source. A trigger body is compiled into the statement that fires it, so
394    /// its target takes the next number after the firing statement's - and a
395    /// compiler that assumed zero read the wrong cursor for every fire after
396    /// the first.
397    pub source: usize,
398    /// The `WHERE` clause.
399    pub filter: Option<BoundExpr>,
400    /// The `RETURNING` columns.
401    pub returning: Vec<BoundResultColumn>,
402    /// The `LIMIT`.
403    pub limit: Option<BoundExpr>,
404    /// The `OFFSET`.
405    pub offset: Option<BoundExpr>,
406    /// The triggers this write fires, in schema order.
407    pub triggers: Vec<BoundTrigger>,
408    /// The rows to fire an `INSTEAD OF` trigger for, when the target is a view.
409    pub view_rows: Option<Box<BoundSelect>>,
410}
411
412/// Reports whether an `INSERT` can resolve a conflict by deleting a row.
413///
414/// Either the statement said so, or one of the table's own constraints did.
415/// It is asked before the delete's keys are bound, because binding them costs
416/// a parse and a bind each and the answer is no for almost every insert.
417fn can_replace(table: &TableInfo, statement: Option<ConflictAction>) -> bool {
418    if statement == Some(ConflictAction::Replace) {
419        return true;
420    }
421    table
422        .indexes
423        .iter()
424        .any(|index| index.conflict == Some(ConflictAction::Replace))
425        || table.columns.iter().any(|column| {
426            column.not_null_conflict == Some(ConflictAction::Replace)
427                || column.primary_key_conflict == Some(ConflictAction::Replace)
428        })
429}
430
431/// Reports whether an unusable key's fault is one this write has to report.
432///
433/// A child's write reports a missing parent; a parent's write reports a
434/// mismatch. A statement that touches neither side of the broken key does not
435/// have to care, which is why the fault is carried rather than raised when the
436/// schema was read.
437fn fault_applies(
438    planned: &crate::catalog_view::ForeignKeyTrigger,
439    event: &TriggerEventInfo,
440) -> bool {
441    match event {
442        TriggerEventInfo::Insert => planned.is_check,
443        TriggerEventInfo::Delete => !planned.is_check,
444        TriggerEventInfo::Update(_) => true,
445    }
446}
447
448/// Marks a synthesised body's aborts as the foreign key's rather than a
449/// trigger's.
450///
451/// The generated text says `RAISE(ABORT, ...)` because that is what a person
452/// would have written, and what a person writes reports
453/// `SQLITE_CONSTRAINT_TRIGGER`. A foreign key reports its own code, and the
454/// only difference between the two is which constraint asked - so it is set
455/// here, on the bodies this binder generated, and nowhere else.
456fn report_as_foreign_key(trigger: &mut BoundTrigger) {
457    trigger.foreign_key = true;
458    for statement in &mut trigger.body {
459        let BoundTriggerStatement::Select(select) = statement else {
460            continue;
461        };
462        for column in &mut select.columns {
463            if let BoundExpr::Raise { foreign_key, .. } = &mut column.expr {
464                *foreign_key = true;
465            }
466        }
467    }
468}
469
470/// Returns whether a view has an `INSTEAD OF` trigger for one event.
471fn has_instead_of(table: &TableInfo, event: &TriggerEventInfo) -> bool {
472    table
473        .triggers
474        .iter()
475        .any(|trigger| trigger.time == ast::TriggerTime::InsteadOf && trigger.fires_for(event, &[]))
476}
477
478/// The target position that stands for the rowid rather than a column.
479///
480/// A table cannot have this many columns - SQLite's limit is two thousand - so
481/// there is no position it can collide with, and one sentinel is cheaper than
482/// a parallel `Option` threaded through every target list.
483const ROWID_TARGET: u16 = u16::MAX;
484
485/// Returns whether a name is one of the rowid's three spellings.
486fn is_rowid_name(folded: &[u8]) -> bool {
487    matches!(folded, b"rowid" | b"oid" | b"_rowid_")
488}
489
490/// How deep one write may drive triggers firing other triggers.
491///
492/// SQLite's own limit is `SQLITE_MAX_TRIGGER_DEPTH`, enforced when the frame is
493/// pushed. Trigger bodies are inlined here rather than run as frames, so the
494/// same limit is enforced where the inlining happens - and it has to be, or a
495/// schema in which two triggers write each other's tables would compile until
496/// the compiler ran out of memory.
497///
498/// **This is one number now, and it is the one `.limit` reports.** There used
499/// to be two constants of this name: this one at 32, which was the number
500/// actually enforced, and `inillucent-exec`'s at 1000, checked at run time over
501/// a tree the binder had already capped at 32 - so that check could never fire.
502/// `crates/inillucent-base/manifests/limits.toml` advertised 1000 and
503/// `inillucent diagnose` printed 1000, and a chain of forty distinct triggers
504/// that the oracle ran was refused here (task-1946, H3). The binder reads
505/// `Limit::TriggerDepth` from the connection now, which `.limit trigger_depth`
506/// and the driver both set; this constant is what a binder built without limits
507/// falls back to, and it is the manifest's default.
508pub const MAX_TRIGGER_DEPTH: usize = 1000;
509
510/// How deep one chain of foreign-key actions may go.
511///
512/// A cascade reaches this only when the keys form a cycle, which in practice
513/// means a table whose parent column points at itself. SQLite's own limit is a
514/// run-time recursion depth; this one is a compile-time inlining depth, and it
515/// is smaller for that reason.
516pub const MAX_FOREIGN_KEY_DEPTH: usize = 64;
517
518/// How many foreign-key action bodies one statement may inline in total.
519///
520/// The depth limit alone is not enough: a table with three keys that all cycle
521/// would inline three bodies per level, so the limit that matters is the total.
522/// A chain, which is what a self-referencing tree produces, spends one per
523/// level and reaches the depth limit first.
524pub const MAX_FOREIGN_KEY_STATEMENTS: usize = 256;
525
526impl<'a> Binder<'a> {
527    /// Binds an `INSERT` or `REPLACE`.
528    pub fn bind_insert(&mut self, insert: &ast::Insert) -> Result<BoundInsert, ParseError> {
529        // **A `WITH` on a DML statement is the same `WITH` a `SELECT` has.** The
530        // CTEs are in scope for the whole statement - the source query of an
531        // `INSERT`, the `WHERE` of an `UPDATE` or `DELETE` - and the binder's
532        // CTE stack already handles nesting, so pushing them here is all it
533        // takes. They were refused rather than bound, which is what a migration
534        // script written for SQLite hits first.
535        let pushed = self.push_ctes(&insert.with)?;
536        let bound = self.bind_insert_body(insert);
537        if pushed {
538            self.pop_ctes();
539        }
540        bound
541    }
542
543    /// Binds an `INSERT` with its CTEs already in scope.
544    fn bind_insert_body(&mut self, insert: &ast::Insert) -> Result<BoundInsert, ParseError> {
545        let table = self.writable_target(
546            insert.database,
547            insert.table,
548            Span::default(),
549            &TriggerEventInfo::Insert,
550        )?;
551        let alias = match insert.alias {
552            Some(alias) => self.ast.text(alias).to_vec(),
553            None => table.name.clone(),
554        };
555        let target_source = self.push_write_source(table.clone(), alias);
556        // `DEFAULT VALUES` supplies nothing, so every column takes its default
557        // - which is what an empty target list means here. The grammar does
558        // not allow a column list with it, so there is none to honour.
559        let targets = match insert.source {
560            ast::InsertSource::DefaultValues => Vec::new(),
561            ast::InsertSource::Select(_) => self.insert_targets(&table, &insert.columns)?,
562        };
563        let (source, arity) = self.bind_insert_source(&insert.source, &table, &targets)?;
564        if arity != targets.len() {
565            return Err(refused(
566                format!("{} values for {} columns", arity, targets.len()),
567                Span::default(),
568            ));
569        }
570        let (columns, rowid) = self.column_sources(&table, &targets)?;
571        let named_rowid = targets.iter().position(|target| *target == ROWID_TARGET);
572        let checks = self.bind_checks(&table)?;
573        let not_null_defaults = self.bind_not_null_defaults(&table)?;
574        let index_exprs = self.bind_index_exprs(&table)?;
575        let upsert = self.bind_upsert(&table, insert)?;
576        let returning = self.bind_returning(&insert.returning)?;
577        let mut triggers = self.bind_triggers(&table, TriggerEventInfo::Insert, &[])?;
578        triggers.extend(self.bind_foreign_keys(&table, TriggerEventInfo::Insert, &[])?);
579        let replace_triggers = if can_replace(&table, insert.on_conflict) {
580            self.bind_foreign_keys(&table, TriggerEventInfo::Delete, &[])?
581        } else {
582            Vec::new()
583        };
584        let sequence_root = if table.autoincrement {
585            self.catalog
586                .find_table(None, b"sqlite_sequence")
587                .map_or(0, |sequence| sequence.root)
588        } else {
589            0
590        };
591        Ok(BoundInsert {
592            table,
593            index_exprs,
594            target_source,
595            columns,
596            rowid,
597            named_rowid,
598            source,
599            arity,
600            on_conflict: insert.on_conflict,
601            checks,
602            not_null_defaults,
603            upsert,
604            sequence_root,
605            returning,
606            triggers,
607            replace_triggers,
608        })
609    }
610
611    /// Binds an `UPDATE`.
612    pub fn bind_update(&mut self, update: &ast::Update) -> Result<BoundUpdate, ParseError> {
613        let pushed = self.push_ctes(&update.with)?;
614        let bound = self.bind_update_body(update);
615        if pushed {
616            self.pop_ctes();
617        }
618        bound
619    }
620
621    /// Binds an `UPDATE` with its CTEs already in scope.
622    fn bind_update_body(&mut self, update: &ast::Update) -> Result<BoundUpdate, ParseError> {
623        if let Some(refusal) = limited_dml_refusal(update.limited_at) {
624            return Err(refusal);
625        }
626        let (table, source) =
627            self.write_target_from_term(update.target, &TriggerEventInfo::Update(Vec::new()))?;
628        // **The `FROM` terms are bound after the target**, so the target keeps
629        // the lowest source number and every reference to an unqualified column
630        // resolves to it first - which is SQLite's rule and the reason
631        // `UPDATE t SET v = v + 1 FROM s` means the target's `v`.
632        let before = self.sources.len();
633        for term in &update.from {
634            self.bind_from_term(*term)?;
635        }
636        let joined: Vec<crate::bind::BoundSource> =
637            self.sources.get(before..).unwrap_or(&[]).to_vec();
638        let mut assignments = Vec::new();
639        for (names, value) in &update.assignments {
640            let bound = self.bind_expr(*value)?;
641            for name in names {
642                let folded = self.ast.folded(*name).to_vec();
643                // `rowid`, `oid` and `_rowid_` name the row's key rather than a
644                // declared column, unless the table declares a column by one of
645                // those names - which is what `is_rowid_name` decides.
646                if table.is_rowid_name(&folded) {
647                    if assignments.iter().any(|held: &BoundAssignment| held.rowid) {
648                        return Err(refused(
649                            format!(
650                                "column {} is assigned twice",
651                                String::from_utf8_lossy(self.ast.text(*name))
652                            ),
653                            Span::default(),
654                        ));
655                    }
656                    assignments.push(BoundAssignment {
657                        column: 0,
658                        rowid: true,
659                        value: bound.clone(),
660                    });
661                    continue;
662                }
663                let Some(position) = table.column_position(&folded) else {
664                    return Err(no_such_column(self.ast.text(*name), Span::default()));
665                };
666                // **An assignment to a generated column is refused, not
667                // ignored (task-1913).** SQLite answers `cannot UPDATE
668                // generated column "c"`; this accepted the statement, reported
669                // it as a success, and wrote nothing the caller asked for -
670                // either the record took the value and the column stopped
671                // agreeing with its own expression, or the recompute above put
672                // it back and the assignment was silently dropped. `INSERT`
673                // already refused the same thing.
674                self.refuse_generated(&table, position, "UPDATE", Span::default())?;
675                if assignments
676                    .iter()
677                    .any(|existing: &BoundAssignment| existing.column == position)
678                {
679                    return Err(refused(
680                        format!(
681                            "column {} is assigned twice",
682                            String::from_utf8_lossy(self.ast.text(*name))
683                        ),
684                        Span::default(),
685                    ));
686                }
687                assignments.push(BoundAssignment {
688                    column: position,
689                    rowid: false,
690                    value: bound.clone(),
691                });
692            }
693        }
694        // The rowid assignment sorts with the declared columns rather than
695        // ahead of them, because `column` says nothing for it and the order
696        // only has to be stable.
697        assignments.sort_by_key(|assignment| (assignment.rowid, assignment.column));
698        let filter = match update.filter {
699            Some(expr) => Some(self.bind_expr(expr)?),
700            None => None,
701        };
702        let generated = self.bind_stored_generated(&table)?;
703        let checks = self.bind_checks(&table)?;
704        let not_null_defaults = self.bind_not_null_defaults(&table)?;
705        let index_exprs = self.bind_index_exprs(&table)?;
706        let returning = self.bind_returning(&update.returning)?;
707        let limit = match update.limit {
708            Some(expr) => Some(self.bind_expr(expr)?),
709            None => None,
710        };
711        let offset = match update.offset {
712            Some(expr) => Some(self.bind_expr(expr)?),
713            None => None,
714        };
715        // The rowid is not a declared column, so no `UPDATE OF` trigger and no
716        // foreign key can be keyed on it and it contributes no name here.
717        let changed: Vec<Vec<u8>> = assignments
718            .iter()
719            .filter(|assignment| !assignment.rowid)
720            .filter_map(|assignment| table.column(assignment.column))
721            .map(|column| column.folded.clone())
722            .collect();
723        let mut triggers =
724            self.bind_triggers(&table, TriggerEventInfo::Update(Vec::new()), &changed)?;
725        triggers.extend(self.bind_foreign_keys(
726            &table,
727            TriggerEventInfo::Update(Vec::new()),
728            &changed,
729        )?);
730        let view_rows = self.view_rows(&table, filter.clone());
731        let index_hint = self.write_hint(source, &index_exprs, filter.as_ref(), &joined)?;
732        Ok(BoundUpdate {
733            table,
734            index_exprs,
735            index_hint,
736            source,
737            from: joined,
738            assignments,
739            generated,
740            filter,
741            on_conflict: update.on_conflict,
742            checks,
743            not_null_defaults,
744            returning,
745            limit,
746            offset,
747            triggers,
748            view_rows,
749        })
750    }
751
752    /// Binds a `DELETE`.
753    pub fn bind_delete(&mut self, delete: &ast::Delete) -> Result<BoundDelete, ParseError> {
754        let pushed = self.push_ctes(&delete.with)?;
755        let bound = self.bind_delete_body(delete);
756        if pushed {
757            self.pop_ctes();
758        }
759        bound
760    }
761
762    /// Binds a `DELETE` with its CTEs already in scope.
763    fn bind_delete_body(&mut self, delete: &ast::Delete) -> Result<BoundDelete, ParseError> {
764        if let Some(refusal) = limited_dml_refusal(delete.limited_at) {
765            return Err(refusal);
766        }
767        let (table, source) =
768            self.write_target_from_term(delete.target, &TriggerEventInfo::Delete)?;
769        let index_exprs = self.bind_index_exprs(&table)?;
770        let filter = match delete.filter {
771            Some(expr) => Some(self.bind_expr(expr)?),
772            None => None,
773        };
774        let returning = self.bind_returning(&delete.returning)?;
775        let limit = match delete.limit {
776            Some(expr) => Some(self.bind_expr(expr)?),
777            None => None,
778        };
779        let offset = match delete.offset {
780            Some(expr) => Some(self.bind_expr(expr)?),
781            None => None,
782        };
783        let mut triggers = self.bind_triggers(&table, TriggerEventInfo::Delete, &[])?;
784        triggers.extend(self.bind_foreign_keys(&table, TriggerEventInfo::Delete, &[])?);
785        let view_rows = self.view_rows(&table, filter.clone());
786        let index_hint = self.write_hint(source, &index_exprs, filter.as_ref(), &[])?;
787        Ok(BoundDelete {
788            table,
789            index_exprs,
790            index_hint,
791            source,
792            filter,
793            returning,
794            limit,
795            offset,
796            triggers,
797            view_rows,
798        })
799    }
800
801    /// Binds the triggers one write fires, bodies and all.
802    ///
803    /// The bodies are bound here, into the same binder, so their FROM terms take
804    /// statement-wide source numbers alongside the write's own. That is what
805    /// lets the compiler inline them: a trigger body is not a separate program
806    /// with a separate cursor space, it is more of this statement.
807    ///
808    /// A trigger already being bound is skipped rather than bound again, which
809    /// is SQLite's behaviour with its default `recursive_triggers = off` and is
810    /// also the only reason inlining terminates.
811    ///
812    /// **Walked newest first.** `live.triggers` is in the order
813    /// `inillucent_catalog::paged::tables_from_entries` appended them while
814    /// reading `sqlite_schema` - the order the triggers were created in - and
815    /// SQLite fires two triggers of the same timing and event in the opposite
816    /// order: it keeps each table's trigger list with the most recently
817    /// created one first, so that one fires first.
818    /// `dml_differential.rs`'s `row_triggers_match_sqlite` has two `AFTER
819    /// INSERT` triggers on one table - `t_ai`, created first, and `t_high`,
820    /// created after it - and the pinned reference fires `t_high` before
821    /// `t_ai` on every insert. Reversing the walk here, once, at the one place
822    /// that reads `live.triggers` into a statement's own trigger list, is
823    /// enough: nothing downstream reorders it again.
824    fn bind_triggers(
825        &mut self,
826        table: &TableInfo,
827        event: TriggerEventInfo,
828        changed: &[Vec<u8>],
829    ) -> Result<Vec<BoundTrigger>, ParseError> {
830        // The catalog reference is copied out of `self` first: the trigger's
831        // arena has to outlive the binder for the body to be bound in place,
832        // and a borrow taken through `&self` would end at the first `&mut self`.
833        let catalog = self.catalog;
834        let database = catalog.database_name(table.database).to_vec();
835        let Some(live) = catalog.find_table(Some(database.as_slice()), &table.folded) else {
836            return Ok(Vec::new());
837        };
838        let (old, new) = match event {
839            TriggerEventInfo::Insert => (false, true),
840            TriggerEventInfo::Delete => (true, false),
841            TriggerEventInfo::Update(_) => (true, true),
842        };
843        let mut bound = Vec::new();
844        for trigger in live.triggers.iter().rev() {
845            if !trigger.fires_for(&event, changed) {
846                continue;
847            }
848            if self.firing.contains(&trigger.folded) {
849                continue;
850            }
851            if self.firing.len() >= self.trigger_depth {
852                // The number is in the message because a settable limit that
853                // refuses without saying what it was leaves a reader guessing
854                // between the default and whatever `.limit` last set.
855                return Err(refused(
856                    format!(
857                        "too many levels of trigger recursion: the limit is {}",
858                        self.trigger_depth
859                    ),
860                    Span::default(),
861                ));
862            }
863            self.firing.push(trigger.folded.clone());
864            let saved_ast = self.ast;
865            let saved_scopes = core::mem::take(&mut self.scopes);
866            let saved_aliases = self.row_aliases.take();
867            let saved_target = self.view_target.take();
868            // A trigger body is schema text: the statements in it were written
869            // by whoever wrote the file, and they run because a write happened
870            // rather than because anybody submitted them.
871            let saved_site = self.call_site;
872            self.call_site = crate::function::CallSite::Schema;
873            self.ast = &trigger.ast;
874            self.row_aliases = Some(crate::bind::RowAliases {
875                table: table.clone(),
876                old,
877                new,
878            });
879            let result = self.bind_trigger_body(trigger, table);
880            self.call_site = saved_site;
881            self.ast = saved_ast;
882            self.scopes = saved_scopes;
883            self.row_aliases = saved_aliases;
884            self.view_target = saved_target;
885            self.firing.pop();
886            bound.push(result?);
887        }
888        Ok(bound)
889    }
890
891    /// Binds the triggers this write's foreign keys imply.
892    ///
893    /// The triggers themselves were generated when the schema was read - both
894    /// directions of every key, since nothing in the file records the reverse
895    /// one. What is decided here is which of them apply: whether keys are
896    /// enforced at all, whether a check waits for the commit, and whether this
897    /// particular write touches the columns a check is about.
898    fn bind_foreign_keys(
899        &mut self,
900        table: &TableInfo,
901        event: TriggerEventInfo,
902        changed: &[Vec<u8>],
903    ) -> Result<Vec<BoundTrigger>, ParseError> {
904        if !self.foreign_keys || table.kind != TableKind::Table {
905            return Ok(Vec::new());
906        }
907        let catalog = self.catalog;
908        let database = catalog.database_name(table.database).to_vec();
909        let Some(live) = catalog.find_table(Some(database.as_slice()), &table.folded) else {
910            return Ok(Vec::new());
911        };
912        let mut bound = Vec::new();
913        for planned in &live.foreign_key_triggers {
914            if planned.is_check && (planned.deferred || self.defer_foreign_keys) {
915                continue;
916            }
917            let Some(trigger) = planned.trigger.as_ref() else {
918                if fault_applies(planned, &event) {
919                    return Err(crate::bind::schema_refused(
920                        String::from_utf8_lossy(&planned.fault).into_owned(),
921                        Span::default(),
922                    ));
923                }
924                continue;
925            };
926            if !trigger.fires_for(&event, changed) {
927                continue;
928            }
929            if self.firing_foreign_keys.contains(&trigger.folded) {
930                continue;
931            }
932            let mut one = self.bind_foreign_key_trigger(table, trigger, &event)?;
933            one.self_referencing = planned.self_referencing;
934            bound.push(one);
935        }
936        Ok(bound)
937    }
938
939    /// Binds one synthesised trigger, inside the recursion budget.
940    ///
941    /// The budget is spent here rather than where the trigger was generated,
942    /// because what a cascade costs is the *bound* body: one copy per level it
943    /// can reach, and it can reach itself only when the keys form a cycle.
944    fn bind_foreign_key_trigger(
945        &mut self,
946        table: &TableInfo,
947        trigger: &'a TriggerInfo,
948        event: &TriggerEventInfo,
949    ) -> Result<BoundTrigger, ParseError> {
950        if self.foreign_key_depth >= MAX_FOREIGN_KEY_DEPTH || self.foreign_key_budget == 0 {
951            return Err(refused(
952                "too many levels of foreign key recursion",
953                Span::default(),
954            ));
955        }
956        self.foreign_key_depth = self.foreign_key_depth.saturating_add(1);
957        self.foreign_key_budget = self.foreign_key_budget.saturating_sub(1);
958        self.firing_foreign_keys.push(trigger.folded.clone());
959        let (old, new) = match event {
960            TriggerEventInfo::Insert => (false, true),
961            TriggerEventInfo::Delete => (true, false),
962            TriggerEventInfo::Update(_) => (true, true),
963        };
964        let saved_ast = self.ast;
965        let saved_scopes = core::mem::take(&mut self.scopes);
966        let saved_aliases = self.row_aliases.take();
967        let saved_target = self.view_target.take();
968        // A synthesised key action is generated from a `REFERENCES` clause the
969        // schema wrote, so it is schema too - the same site a written trigger
970        // gets, because the binder turns both into the same text.
971        let saved_site = self.call_site;
972        self.call_site = crate::function::CallSite::Schema;
973        self.ast = &trigger.ast;
974        self.row_aliases = Some(crate::bind::RowAliases {
975            table: table.clone(),
976            old,
977            new,
978        });
979        let result = self.bind_trigger_body(trigger, table);
980        self.call_site = saved_site;
981        self.ast = saved_ast;
982        self.scopes = saved_scopes;
983        self.row_aliases = saved_aliases;
984        self.view_target = saved_target;
985        self.foreign_key_depth = self.foreign_key_depth.saturating_sub(1);
986        self.firing_foreign_keys.pop();
987        let mut bound = result?;
988        report_as_foreign_key(&mut bound);
989        Ok(bound)
990    }
991
992    /// Binds one trigger's guard and body statements.
993    fn bind_trigger_body(
994        &mut self,
995        trigger: &TriggerInfo,
996        table: &TableInfo,
997    ) -> Result<BoundTrigger, ParseError> {
998        let when = match trigger.when {
999            Some(expr) => Some(self.bind_expr(expr)?),
1000            None => None,
1001        };
1002        let mut body = Vec::new();
1003        for statement in &trigger.body {
1004            // Each statement gets a fresh scope stack. A body statement's names
1005            // resolve against its own tables and against OLD and NEW, never
1006            // outward into the statement that fired it.
1007            let saved = core::mem::take(&mut self.scopes);
1008            let one = self.bind_trigger_statement(statement);
1009            self.scopes = saved;
1010            body.push(one?);
1011        }
1012        Ok(BoundTrigger {
1013            name: trigger.name.clone(),
1014            table: table.folded.clone(),
1015            time: trigger.time,
1016            when,
1017            body,
1018            foreign_key: false,
1019            self_referencing: false,
1020        })
1021    }
1022
1023    /// Binds one statement of a trigger body.
1024    pub(crate) fn bind_trigger_statement(
1025        &mut self,
1026        statement: &ast::Statement,
1027    ) -> Result<BoundTriggerStatement, ParseError> {
1028        match statement {
1029            ast::Statement::Insert(insert) => {
1030                if !insert.returning.is_empty() {
1031                    return Err(refused(
1032                        "RETURNING is not allowed on a trigger body statement",
1033                        Span::default(),
1034                    ));
1035                }
1036                Ok(BoundTriggerStatement::Insert(Box::new(
1037                    self.bind_insert(insert)?,
1038                )))
1039            }
1040            ast::Statement::Update(update) => {
1041                if !update.returning.is_empty() {
1042                    return Err(refused(
1043                        "RETURNING is not allowed on a trigger body statement",
1044                        Span::default(),
1045                    ));
1046                }
1047                Ok(BoundTriggerStatement::Update(Box::new(
1048                    self.bind_update(update)?,
1049                )))
1050            }
1051            ast::Statement::Delete(delete) => {
1052                if !delete.returning.is_empty() {
1053                    return Err(refused(
1054                        "RETURNING is not allowed on a trigger body statement",
1055                        Span::default(),
1056                    ));
1057                }
1058                Ok(BoundTriggerStatement::Delete(Box::new(
1059                    self.bind_delete(delete)?,
1060                )))
1061            }
1062            ast::Statement::Select(select) => Ok(BoundTriggerStatement::Select(Box::new(
1063                self.bind_select(*select)?,
1064            ))),
1065            _ => Err(unsupported(
1066                "that statement in a trigger body",
1067                Span::default(),
1068            )),
1069        }
1070    }
1071
1072    /// Resolves a write target and refuses the things that cannot be written.
1073    fn writable_target(
1074        &mut self,
1075        database: Option<ast::NameId>,
1076        name: ast::NameId,
1077        span: Span,
1078        event: &TriggerEventInfo,
1079    ) -> Result<TableInfo, ParseError> {
1080        let qualifier = database.map(|id| self.ast.folded(id).to_vec());
1081        let folded = self.ast.folded(name).to_vec();
1082        let Some(table) = self
1083            .catalog
1084            .find_table(qualifier.as_deref(), &folded)
1085            .cloned()
1086        else {
1087            return Err(crate::bind::no_such_table(self.ast.text(name), span));
1088        };
1089        match table.kind {
1090            TableKind::View => {
1091                // A view is writable exactly when it has an `INSTEAD OF`
1092                // trigger for this event: the trigger *is* the write, and the
1093                // view itself is never touched.
1094                if !has_instead_of(&table, event) {
1095                    return Err(unsupported("writing to a view", span));
1096                }
1097                let expanded = self.expanded_view(&table, span)?;
1098                self.record_write_dependency(table.database);
1099                return Ok(expanded);
1100            }
1101            TableKind::Virtual => {
1102                // A module decides whether it can be written; a module that
1103                // cannot refuses the call rather than the statement, because
1104                // "this table is read-only" is the module's fact and not the
1105                // binder's. What the binder still checks is that the table has
1106                // a module at all - a virtual table this build has no module
1107                // for has no columns either, and nothing can be written to it.
1108                if table.columns.is_empty() {
1109                    return Err(unsupported("that virtual table's module", span));
1110                }
1111                self.record_write_dependency(table.database);
1112                return Ok(table);
1113            }
1114            TableKind::Subquery => return Err(unsupported("writing to a subquery", span)),
1115            TableKind::Table => {}
1116        }
1117        if table.folded.starts_with(b"sqlite_")
1118            && !WRITABLE_INTERNAL.contains(&table.folded.as_slice())
1119        {
1120            return Err(unsupported(
1121                "writing to a table whose name begins with sqlite_",
1122                span,
1123            ));
1124        }
1125        self.record_write_dependency(table.database);
1126        Ok(table)
1127    }
1128
1129    /// Resolves the target of an UPDATE or DELETE, which is a FROM term.
1130    fn write_target_from_term(
1131        &mut self,
1132        id: ast::FromTermId,
1133        event: &TriggerEventInfo,
1134    ) -> Result<(TableInfo, usize), ParseError> {
1135        let Some(term) = self.ast.from_term(id) else {
1136            return Err(unsupported("missing target", Span::default()));
1137        };
1138        let ast::FromSource::Table {
1139            database,
1140            name,
1141            indexed_by,
1142            ..
1143        } = term.source
1144        else {
1145            return Err(unsupported("a target that is not a table", term.span));
1146        };
1147        let table = self.writable_target(database, name, term.span, event)?;
1148        // The same rule as a SELECT's: an `INDEXED BY` that names no index of
1149        // the table is refused rather than ignored (task-1979, F7). This path
1150        // has the table in hand rather than a bound source, so it asks the
1151        // table directly.
1152        if let ast::IndexHint::IndexedBy(index) = indexed_by {
1153            let folded = self.ast.folded(index).to_vec();
1154            if !table.indexes.iter().any(|held| held.folded == folded) {
1155                return Err(crate::bind::no_such_index(self.ast.text(index), term.span));
1156            }
1157        }
1158        let alias = match term.alias {
1159            Some(alias) => self.ast.text(alias).to_vec(),
1160            None => table.name.clone(),
1161        };
1162        if table.kind == TableKind::View {
1163            // The view goes in as an ordinary nested query, so the statement's
1164            // WHERE and SET bind against the view's own columns and against the
1165            // term the block producing OLD will iterate. Binding first and
1166            // re-pointing afterwards would be two chances to disagree.
1167            let inner = self.view_query(&table, term.span)?;
1168            let source = BoundSource {
1169                index_hint: crate::bind::IndexChoice::Any,
1170                id: self.sources.len(),
1171                rows: crate::bind::SourceRows::Subquery(Box::new(inner)),
1172                table: std::rc::Rc::new(table.clone()),
1173                alias,
1174                join: ast::JoinKind::Comma,
1175                constraint: None,
1176                suppressed: Vec::new(),
1177                index_exprs: Vec::new(),
1178            };
1179            self.view_target = Some(source.id);
1180            let scope = source.id;
1181            self.sources.push(source);
1182            self.scopes.push(vec![scope]);
1183            return Ok((table, scope));
1184        }
1185        let scope = self.push_write_source(table.clone(), alias);
1186        let choice = self.index_choice(indexed_by);
1187        if let Some(source) = self.sources.get_mut(scope) {
1188            source.index_hint = choice;
1189        }
1190        Ok((table, scope))
1191    }
1192
1193    /// Returns a view's `TableInfo` with the columns its body produces.
1194    ///
1195    /// A view's catalog entry carries no column list - its columns are whatever
1196    /// binding its `SELECT` says they are - so a statement that writes one needs
1197    /// the body bound before `new.column` can resolve to anything at all.
1198    pub(crate) fn expanded_view(
1199        &mut self,
1200        table: &TableInfo,
1201        span: Span,
1202    ) -> Result<TableInfo, ParseError> {
1203        let bound = self.view_query(table, span)?;
1204        let mut expanded = table.clone();
1205        expanded.columns = crate::bind::subquery_columns(&bound, &[]);
1206        Ok(expanded)
1207    }
1208
1209    /// Binds a view's body, out of the arena the catalog snapshot holds.
1210    fn view_query(&mut self, table: &TableInfo, span: Span) -> Result<BoundSelect, ParseError> {
1211        let catalog = self.catalog;
1212        let database = catalog.database_name(table.database).to_vec();
1213        let Some(live) = catalog.find_table(Some(database.as_slice()), &table.folded) else {
1214            return Err(crate::bind::no_such_table(&table.name, span));
1215        };
1216        let Some(body) = live.view.as_ref() else {
1217            return Err(unsupported(
1218                "a view whose definition could not be parsed",
1219                span,
1220            ));
1221        };
1222        let names = body.columns.clone();
1223        let saved_ast = self.ast;
1224        let saved_scopes = core::mem::take(&mut self.scopes);
1225        self.ast = &body.ast;
1226        let bound = self.bind_select(body.select);
1227        self.ast = saved_ast;
1228        self.scopes = saved_scopes;
1229        let mut bound = bound?;
1230        // `CREATE VIEW v (a, b)` renames the body's columns, and those are the
1231        // names `new.a` resolves against.
1232        for (position, name) in names.iter().enumerate() {
1233            if let Some(column) = bound.columns.get_mut(position) {
1234                column.name = name.clone();
1235            }
1236        }
1237        Ok(bound)
1238    }
1239
1240    /// Builds the block whose rows an `INSTEAD OF UPDATE` or `DELETE` fires for.
1241    ///
1242    /// It reads the term `write_target_from_term` already pushed, so the filter
1243    /// handed in here - bound against that same term - needs no adjustment.
1244    fn view_rows(
1245        &mut self,
1246        table: &TableInfo,
1247        filter: Option<BoundExpr>,
1248    ) -> Option<Box<BoundSelect>> {
1249        // The kind is checked before the target is taken. A trigger body's own
1250        // UPDATE binds through here too, and taking first meant the body's
1251        // statement - whose target is an ordinary table - consumed the view
1252        // target belonging to the statement that fired it, which then compiled
1253        // as a write to a view's root page of zero.
1254        if table.kind != TableKind::View {
1255            return None;
1256        }
1257        let id = self.view_target.take()?;
1258        let source = self.sources.get(id)?.clone();
1259        let columns = table
1260            .columns
1261            .iter()
1262            .enumerate()
1263            .map(|(position, column)| BoundResultColumn {
1264                expr: BoundExpr::Column {
1265                    source: id,
1266                    column: position as u16,
1267                    slot: position as u16,
1268                    affinity: column.affinity,
1269                    collation: Collation::from_name(
1270                        core::str::from_utf8(&column.collation).unwrap_or("BINARY"),
1271                    )
1272                    .unwrap_or(Collation::Binary),
1273                },
1274                name: column.name.clone(),
1275                origin: None,
1276                declared_type: column.declared_type.clone(),
1277            })
1278            .collect();
1279        Some(Box::new(crate::bind::block_over(source, filter, columns)))
1280    }
1281
1282    /// Returns the target's index hint, or refuses a write whose `INDEXED BY`
1283    /// index cannot find its rows.
1284    ///
1285    /// The same rule and the same test a `SELECT` gets from
1286    /// `crate::bind::refuse_unanswerable_hints`, asked of the query the write
1287    /// will run to find its rows: the target, any `UPDATE ... FROM` terms, and
1288    /// the statement's `WHERE`. The pinned 3.53.4 shell refuses
1289    /// `DELETE FROM h INDEXED BY h_part WHERE a = 1`, where `h_part` is declared
1290    /// `WHERE c > 3`, with `no query solution`.
1291    /// @param source - the target's statement-wide number
1292    /// @param index_exprs - the target's bound index expressions
1293    /// @param filter - the statement's `WHERE`
1294    /// @param joined - the `UPDATE ... FROM` terms, empty for a `DELETE`
1295    fn write_hint(
1296        &self,
1297        source: usize,
1298        index_exprs: &[BoundIndexExprs],
1299        filter: Option<&BoundExpr>,
1300        joined: &[BoundSource],
1301    ) -> Result<crate::bind::IndexChoice, ParseError> {
1302        let Some(target) = self.sources.get(source) else {
1303            return Ok(crate::bind::IndexChoice::Any);
1304        };
1305        if target.index_hint == crate::bind::IndexChoice::Any {
1306            return Ok(crate::bind::IndexChoice::Any);
1307        }
1308        let mut probe = target.clone();
1309        probe.index_exprs = index_exprs.to_vec();
1310        let mut block = crate::bind::block_over(probe, filter.cloned(), Vec::new());
1311        block.sources.extend(joined.iter().cloned());
1312        if crate::plan::unanswerable_index_hint(&block).is_some() {
1313            return Err(crate::bind::no_query_solution(Span::default()));
1314        }
1315        Ok(target.index_hint.clone())
1316    }
1317
1318    /// Makes the target table the statement's one visible source.
1319    ///
1320    /// It opens a scope holding just the target, so every name in the
1321    /// statement's `SET`, `WHERE` and `RETURNING` resolves against the table
1322    /// being written and nothing else.
1323    fn push_write_source(&mut self, table: TableInfo, alias: Vec<u8>) -> usize {
1324        let id = self.sources.len();
1325        self.sources.push(BoundSource {
1326            index_hint: crate::bind::IndexChoice::Any,
1327            id,
1328            rows: crate::bind::SourceRows::Table,
1329            table: std::rc::Rc::new(table),
1330            alias,
1331            join: ast::JoinKind::Comma,
1332            constraint: None,
1333            suppressed: Vec::new(),
1334            index_exprs: Vec::new(),
1335        });
1336        self.scopes.push(vec![id]);
1337        id
1338    }
1339
1340    /// Refuses an attempt to write a generated column.
1341    ///
1342    /// SQLite's message names the column, because the usual cause is a script
1343    /// that inserts every column of a table one of whose columns has since been
1344    /// made generated. It names the statement too - `INSERT` or `UPDATE` - and
1345    /// so does this.
1346    ///
1347    /// @param table - the table being written
1348    /// @param position - the column the statement named
1349    /// @param verb - `INSERT into` or `UPDATE`, as SQLite writes it
1350    /// @param span - where the name was written
1351    fn refuse_generated(
1352        &self,
1353        table: &TableInfo,
1354        position: u16,
1355        verb: &str,
1356        span: Span,
1357    ) -> Result<(), ParseError> {
1358        let Some(column) = table.column(position) else {
1359            return Ok(());
1360        };
1361        if !column.generated {
1362            return Ok(());
1363        }
1364        Err(refused(
1365            format!(
1366                "cannot {verb} generated column \"{}\"",
1367                String::from_utf8_lossy(&column.name)
1368            ),
1369            span,
1370        ))
1371    }
1372
1373    /// Returns the target column positions an INSERT writes, in source order.
1374    ///
1375    /// With no column list the targets are every column in declaration order,
1376    /// which is why adding a column to a table changes what a positional
1377    /// INSERT means - SQLite's behaviour, and the reason the column list is
1378    /// worth writing.
1379    fn insert_targets(
1380        &self,
1381        table: &TableInfo,
1382        columns: &[ast::NameId],
1383    ) -> Result<Vec<u16>, ParseError> {
1384        if columns.is_empty() {
1385            // A bare `INSERT INTO t VALUES (...)` supplies the columns a person
1386            // can write, which is every column that is not generated - so a
1387            // table with a generated column takes fewer values than it has
1388            // columns, exactly as SQLite counts them.
1389            // A hidden column is not one of them either: a module's arguments
1390            // and its `rank` are named by an application that wants them, and
1391            // an `INSERT INTO fts VALUES ('a', 'b')` supplies the two indexed
1392            // columns and nothing else.
1393            return Ok((0..table.columns.len() as u16)
1394                .filter(|position| {
1395                    table
1396                        .column(*position)
1397                        .is_some_and(|column| !column.generated && !column.hidden)
1398                })
1399                .collect());
1400        }
1401        let mut targets = Vec::with_capacity(columns.len());
1402        for name in columns {
1403            let folded = self.ast.folded(*name).to_vec();
1404            let position = match table.column_position(&folded) {
1405                Some(position) => position,
1406                // A rowid table lets the statement name its rowid, under any
1407                // of its three spellings, and that is not a column: it is the
1408                // key. A declared column of the same name wins, which is why
1409                // this is the fallback rather than the first thing tried.
1410                None if table.has_rowid() && is_rowid_name(&folded) => ROWID_TARGET,
1411                None => return Err(no_such_column(self.ast.text(*name), Span::default())),
1412            };
1413            if targets.contains(&position) {
1414                return Err(refused(
1415                    format!(
1416                        "column {} is named twice",
1417                        String::from_utf8_lossy(self.ast.text(*name))
1418                    ),
1419                    Span::default(),
1420                ));
1421            }
1422            if position != ROWID_TARGET {
1423                self.refuse_generated(table, position, "INSERT into", Span::default())?;
1424            }
1425            targets.push(position);
1426        }
1427        Ok(targets)
1428    }
1429
1430    /// Binds the rows an INSERT supplies.
1431    fn bind_insert_source(
1432        &mut self,
1433        source: &ast::InsertSource,
1434        table: &TableInfo,
1435        targets: &[u16],
1436    ) -> Result<(BoundInsertSource, usize), ParseError> {
1437        match source {
1438            ast::InsertSource::DefaultValues => {
1439                let _ = (table, targets);
1440                Ok((BoundInsertSource::Values(vec![Vec::new()]), 0))
1441            }
1442            ast::InsertSource::Select(id) => {
1443                // The target table is source zero while the rows are bound, so
1444                // that `INSERT INTO t SELECT ... FROM u` resolves `u`'s columns
1445                // and not `t`'s. Binding a SELECT replaces the source list, and
1446                // the target is pushed back afterwards.
1447                // The scope stack is emptied rather than pushed to, because a
1448                // pushed scope would still be searched *outward* into the
1449                // target's, and `INSERT INTO t SELECT a FROM u` would then
1450                // resolve `a` against `t` when `u` has no such column.
1451                let saved = core::mem::take(&mut self.scopes);
1452                let select = self.bind_select(*id);
1453                let bound = match select {
1454                    Ok(bound) => bound,
1455                    Err(error) => {
1456                        self.scopes = saved;
1457                        return Err(error);
1458                    }
1459                };
1460                self.scopes = saved;
1461                if bound.values.is_empty() {
1462                    let arity = bound.columns.len();
1463                    return Ok((BoundInsertSource::Select(Box::new(bound)), arity));
1464                }
1465                let arity = bound.values.first().map_or(0, Vec::len);
1466                for row in &bound.values {
1467                    if row.len() != arity {
1468                        return Err(unsupported(
1469                            "all VALUES rows must have the same number of columns",
1470                            Span::default(),
1471                        ));
1472                    }
1473                }
1474                Ok((BoundInsertSource::Values(bound.values), arity))
1475            }
1476        }
1477    }
1478
1479    /// Works out where every table column's value comes from.
1480    ///
1481    /// A column the statement named takes its value from the source row; a
1482    /// column it did not takes its `DEFAULT`, and a column with no default
1483    /// takes NULL. The rowid is separated out here rather than in the
1484    /// compiler, because an `INTEGER PRIMARY KEY` column *is* the rowid and
1485    /// writing it into the record as well would store a duplicate that SQLite
1486    /// does not.
1487    fn column_sources(
1488        &mut self,
1489        table: &TableInfo,
1490        targets: &[u16],
1491    ) -> Result<(Vec<ColumnSource>, Option<ColumnSource>), ParseError> {
1492        let mut columns = Vec::with_capacity(table.columns.len());
1493        for position in 0..table.columns.len() as u16 {
1494            if let Some(expr) = self.generated_expr(table, position)? {
1495                columns.push(ColumnSource::Generated(expr));
1496                continue;
1497            }
1498            let source = match targets.iter().position(|target| *target == position) {
1499                Some(index) => ColumnSource::Row(index),
1500                None => ColumnSource::Expr(self.default_expr(table, position)?),
1501            };
1502            columns.push(source);
1503        }
1504        let rowid = match table.rowid_alias {
1505            Some(position) => columns.get(position as usize).cloned(),
1506            None => None,
1507        };
1508        Ok((columns, rowid))
1509    }
1510
1511    /// Binds a generated column's expression, when the column is one.
1512    fn generated_expr(
1513        &mut self,
1514        table: &TableInfo,
1515        position: u16,
1516    ) -> Result<Option<BoundExpr>, ParseError> {
1517        let Some(column) = table.column(position) else {
1518            return Ok(None);
1519        };
1520        if !column.generated {
1521            return Ok(None);
1522        }
1523        let Some(sql) = column.generated_sql.clone() else {
1524            return Ok(Some(BoundExpr::Null));
1525        };
1526        Ok(Some(self.bind_schema_expr(&sql)?))
1527    }
1528
1529    /// Binds every `STORED` generated column's expression.
1530    ///
1531    /// Returns them as assignments, because that is what they are on the write
1532    /// path: a value the statement did not write and the row has to carry. See
1533    /// [`BoundUpdate::generated`] for why an `UPDATE` needs them and a
1534    /// `VIRTUAL` column does not.
1535    ///
1536    /// @param table - the table being written
1537    fn bind_stored_generated(
1538        &mut self,
1539        table: &TableInfo,
1540    ) -> Result<Vec<BoundAssignment>, ParseError> {
1541        let mut generated = Vec::new();
1542        for position in 0..table.columns.len() as u16 {
1543            let Some(column) = table.column(position) else {
1544                continue;
1545            };
1546            if !column.generated || !column.stored {
1547                continue;
1548            }
1549            let Some(expr) = self.generated_expr(table, position)? else {
1550                continue;
1551            };
1552            generated.push(BoundAssignment {
1553                column: position,
1554                rowid: false,
1555                value: expr,
1556            });
1557        }
1558        Ok(generated)
1559    }
1560
1561    /// Binds a column's `DEFAULT`, or NULL when it has none.
1562    fn default_expr(&mut self, table: &TableInfo, position: u16) -> Result<BoundExpr, ParseError> {
1563        let Some(column) = table.column(position) else {
1564            return Ok(BoundExpr::Null);
1565        };
1566        let Some(sql) = column.default_sql.as_ref() else {
1567            return Ok(BoundExpr::Null);
1568        };
1569        if sql.is_empty() {
1570            return Ok(BoundExpr::Null);
1571        }
1572        self.bind_schema_expr(sql)
1573    }
1574
1575    /// Binds the `DEFAULT` of every `NOT NULL` column that declares one.
1576    ///
1577    /// What `REPLACE` substitutes for a NULL in such a column - see
1578    /// [`BoundDefault`]. A column with no default is left out, which is what
1579    /// makes the write path's fallback to `ABORT` the absence of an entry
1580    /// rather than a second test.
1581    ///
1582    /// The rowid alias is left out too: the row image carries the key the
1583    /// statement is about to allocate, and the write path does not check it.
1584    ///
1585    /// @param table - the table being written
1586    fn bind_not_null_defaults(
1587        &mut self,
1588        table: &TableInfo,
1589    ) -> Result<Vec<BoundDefault>, ParseError> {
1590        let mut defaults = Vec::new();
1591        for (position, column) in table.columns.iter().enumerate() {
1592            if !column.not_null || Some(position as u16) == table.rowid_alias {
1593                continue;
1594            }
1595            let Some(sql) = column.default_sql.as_ref() else {
1596                continue;
1597            };
1598            if sql.is_empty() {
1599                continue;
1600            }
1601            let expr = self.bind_schema_expr(&sql.clone())?;
1602            defaults.push(BoundDefault {
1603                column: position as u16,
1604                expr,
1605            });
1606        }
1607        Ok(defaults)
1608    }
1609
1610    /// Binds every `CHECK` the table declares.
1611    fn bind_checks(&mut self, table: &TableInfo) -> Result<Vec<BoundCheck>, ParseError> {
1612        let mut checks = Vec::with_capacity(table.checks.len());
1613        for check in &table.checks {
1614            checks.push(BoundCheck {
1615                name: check.name.clone(),
1616                expr: self.bind_schema_expr(&check.expr_sql)?,
1617            });
1618        }
1619        Ok(checks)
1620    }
1621
1622    /// Binds the expressions the table's indexes need per row.
1623    ///
1624    /// Only the indexes that need any: a partial one, and one with an
1625    /// expression key. Everything else is a slot of the row and needs nothing.
1626    ///
1627    /// @param table - the table being written
1628    fn bind_index_exprs(&mut self, table: &TableInfo) -> Result<Vec<BoundIndexExprs>, ParseError> {
1629        let mut bound = Vec::new();
1630        for (position, index) in table.indexes.iter().enumerate() {
1631            let needs = index.partial_sql.is_some()
1632                || index.columns.iter().any(|key| key.expr_sql.is_some());
1633            if !needs {
1634                continue;
1635            }
1636            let predicate = match index.partial_sql.as_ref() {
1637                Some(sql) => Some(self.bind_schema_expr(sql)?),
1638                None => None,
1639            };
1640            let mut keys = Vec::with_capacity(index.columns.len());
1641            for key in &index.columns {
1642                keys.push(match key.expr_sql.as_ref() {
1643                    Some(sql) => Some(self.bind_schema_expr(sql)?),
1644                    None => None,
1645                });
1646            }
1647            bound.push(BoundIndexExprs {
1648                position,
1649                predicate,
1650                keys,
1651            });
1652        }
1653        Ok(bound)
1654    }
1655
1656    /// Parses and binds an expression that was written in the schema.
1657    ///
1658    /// It is parsed into its own arena and bound against the statement's
1659    /// current sources, so the result is an ordinary `BoundExpr` that refers to
1660    /// the target table by position and carries no reference to the schema
1661    /// text it came from.
1662    pub fn bind_schema_expr(&mut self, sql: &[u8]) -> Result<BoundExpr, ParseError> {
1663        let limits = Limits::default();
1664        let (ast, expr) = parse_expression(sql, &limits)?;
1665        let mut nested = Binder::new(self.catalog, &ast, self.authorizer);
1666        nested.trigger_depth = self.trigger_depth;
1667        // **This is where a `DEFAULT`, a `CHECK`, a generated column, an index
1668        // expression and a partial-index predicate all become a bound tree, so
1669        // it is where all five are told they are a schema (task-1972).** The
1670        // nested binder also inherits the connection's registrations and
1671        // collations, which it did not before: without the registrations
1672        // `bind_external_call` never sees the call at all, because the name
1673        // does not resolve to a registered function and the expression fails as
1674        // "no such function" - an error for the wrong reason, and one that
1675        // disappears the moment an application registers the same name at a
1676        // different arity.
1677        nested.externals = self.externals;
1678        nested.collations = self.collations;
1679        nested.trusted_schema = self.trusted_schema;
1680        nested.call_site = crate::function::CallSite::Schema;
1681        nested.sources = self.sources.clone();
1682        nested.scopes = self.scopes.clone();
1683        let bound = nested.bind_expr(expr)?;
1684        Ok(bound)
1685    }
1686
1687    /// Binds an `ON CONFLICT` clause.
1688    fn bind_upsert(
1689        &mut self,
1690        table: &TableInfo,
1691        insert: &ast::Insert,
1692    ) -> Result<Vec<BoundUpsert>, ParseError> {
1693        if insert.upserts.is_empty() {
1694            return Ok(Vec::new());
1695        }
1696        // **Every clause is bound, in written order.** A statement may carry
1697        // several - `ON CONFLICT(k) DO UPDATE ... ON CONFLICT(id) DO UPDATE ...`
1698        // - and which one runs is decided at *run time*, by which constraint
1699        // the row actually collided with. Binding only the first was the whole
1700        // of the old refusal.
1701        for upsert in &insert.upserts {
1702            if upsert.target_filter.is_some() {
1703                return Err(unsupported(
1704                    "a partial-index conflict target",
1705                    Span::default(),
1706                ));
1707            }
1708        }
1709        // A clause with no conflict target matches any constraint, so anything
1710        // written after it could never run. SQLite refuses that rather than
1711        // accepting a clause it will never reach.
1712        if let Some(position) = insert
1713            .upserts
1714            .iter()
1715            .position(|upsert| upsert.target.is_empty())
1716        {
1717            if position + 1 < insert.upserts.len() {
1718                return Err(crate::bind::schema_refused(
1719                    "ON CONFLICT clause with no conflict target must be last",
1720                    Span::default(),
1721                ));
1722            }
1723        }
1724        // `excluded` is in scope for the assignments and the WHERE, and only
1725        // there. Setting it around the binding rather than pushing a second
1726        // FROM term keeps unqualified names resolving to the target row, which
1727        // is what SQLite does and what a second source would have made
1728        // ambiguous - every column of the target is also a column of
1729        // `excluded`.
1730        self.excluded = Some(table.clone());
1731        let mut bound = Vec::with_capacity(insert.upserts.len());
1732        for upsert in &insert.upserts {
1733            match self.bind_upsert_body(table, upsert) {
1734                Ok(Some(one)) => bound.push(one),
1735                Ok(None) => {}
1736                Err(error) => {
1737                    self.excluded = None;
1738                    return Err(error);
1739                }
1740            }
1741        }
1742        self.excluded = None;
1743        Ok(bound)
1744    }
1745
1746    /// Binds an upsert's target, assignments and filter.
1747    fn bind_upsert_body(
1748        &mut self,
1749        table: &TableInfo,
1750        upsert: &ast::Upsert,
1751    ) -> Result<Option<BoundUpsert>, ParseError> {
1752        let mut target = Vec::new();
1753        for column in &upsert.target {
1754            let Some(name) = bare_indexed_column(self.ast, column) else {
1755                return Err(unsupported(
1756                    "an expression in a conflict target",
1757                    Span::default(),
1758                ));
1759            };
1760            let Some(position) = table.column_position(&name) else {
1761                return Err(no_such_column(&name, Span::default()));
1762            };
1763            target.push(position);
1764        }
1765        target.sort_unstable();
1766        let mut assignments = Vec::new();
1767        for (names, value) in &upsert.assignments {
1768            let bound = self.bind_expr(*value)?;
1769            for name in names {
1770                let folded = self.ast.folded(*name).to_vec();
1771                let Some(position) = table.column_position(&folded) else {
1772                    return Err(no_such_column(self.ast.text(*name), Span::default()));
1773                };
1774                assignments.push(BoundAssignment {
1775                    column: position,
1776                    rowid: false,
1777                    value: bound.clone(),
1778                });
1779            }
1780        }
1781        assignments.sort_by_key(|assignment| assignment.column);
1782        let filter = match upsert.filter {
1783            Some(expr) => Some(self.bind_expr(expr)?),
1784            None => None,
1785        };
1786        Ok(Some(BoundUpsert {
1787            target,
1788            assignments,
1789            do_update: upsert.do_update,
1790            filter,
1791        }))
1792    }
1793
1794    /// Binds a `RETURNING` list, which is a result-column list over the row
1795    /// that was written.
1796    fn bind_returning(
1797        &mut self,
1798        columns: &[ast::ResultColumn],
1799    ) -> Result<Vec<BoundResultColumn>, ParseError> {
1800        if columns.is_empty() {
1801            return Ok(Vec::new());
1802        }
1803        self.bind_result_columns_public(columns)
1804    }
1805}
1806
1807/// Returns an indexed column's bare folded name, when it names a column.
1808fn bare_indexed_column(ast: &crate::Ast, column: &ast::IndexedColumn) -> Option<Vec<u8>> {
1809    match ast.expr(column.expr) {
1810        Some(ast::Expr::Column {
1811            table: None,
1812            column: name,
1813            ..
1814        }) => Some(ast.folded(*name).to_vec()),
1815        _ => None,
1816    }
1817}
1818
1819/// The extended result codes a rejected write reports.
1820///
1821/// The numbers are SQLite's own extended codes. They are written out rather
1822/// than derived because an application matches on them, and a code that was
1823/// computed from an enum's discriminant would change the day the enum did.
1824///
1825/// They live here, beside the binder that decides which constraint a statement
1826/// can violate, because **both** engines report them: the virtual machine
1827/// compiles them into a `HaltError` and the vectorised executor returns them
1828/// from its write path. Two copies would agree until one of them was corrected.
1829pub mod codes {
1830    /// `SQLITE_CONSTRAINT_CHECK`.
1831    pub const CHECK: i32 = 275;
1832    /// `SQLITE_CONSTRAINT_DATATYPE`, which a STRICT table reports.
1833    pub const DATATYPE: i32 = 3091;
1834    /// `SQLITE_CONSTRAINT_NOTNULL`.
1835    pub const NOT_NULL: i32 = 1299;
1836    /// `SQLITE_CONSTRAINT_PRIMARYKEY`.
1837    pub const PRIMARY_KEY: i32 = 1555;
1838    /// `SQLITE_CONSTRAINT_UNIQUE`.
1839    pub const UNIQUE: i32 = 2067;
1840    /// `SQLITE_CONSTRAINT_ROWID`.
1841    pub const ROWID: i32 = 2579;
1842    /// `SQLITE_MISMATCH`, which an `INTEGER PRIMARY KEY` reports for a value
1843    /// that is not an integer.
1844    pub const MISMATCH: i32 = 20;
1845    /// `SQLITE_CONSTRAINT_TRIGGER`, which `RAISE()` reports.
1846    pub const TRIGGER: i32 = 1811;
1847    /// `SQLITE_CONSTRAINT_FOREIGNKEY`.
1848    pub const FOREIGN_KEY: i32 = 787;
1849}
1850
1851/// Returns the message a unique-index violation reports.
1852///
1853/// SQLite names every column of the index, comma separated, which is what an
1854/// application parses to find out which key collided.
1855///
1856/// @param table - the table the index belongs to
1857/// @param index - the index whose key collided
1858pub fn unique_message(table: &TableInfo, index: &IndexInfo) -> String {
1859    let names: Vec<String> = index
1860        .columns
1861        .iter()
1862        .filter_map(|key| key.column)
1863        .filter_map(|column| table.column(column))
1864        .map(|column| {
1865            format!(
1866                "{}.{}",
1867                String::from_utf8_lossy(&table.name),
1868                String::from_utf8_lossy(&column.name)
1869            )
1870        })
1871        .collect();
1872    format!("UNIQUE constraint failed: {}", names.join(", "))
1873}
1874
1875/// Returns the message a duplicate rowid reports, and its extended code.
1876///
1877/// SQLite names the aliasing column when the table has an `INTEGER PRIMARY
1878/// KEY` - and reports `SQLITE_CONSTRAINT_PRIMARYKEY` for it - and names the
1879/// hidden `rowid` under `SQLITE_CONSTRAINT_ROWID` when it does not.
1880///
1881/// **A `WITHOUT ROWID` table has no rowid to name.** Its own key *is* its
1882/// primary key, held in the one index whose root is the table's, so a collision
1883/// reports every column of that key under `SQLITE_CONSTRAINT_PRIMARYKEY` -
1884/// `UNIQUE constraint failed: t.a, t.b`. It used to answer `t.rowid`, naming a
1885/// column the table does not have, on `INSERT` as well as `UPDATE`.
1886///
1887/// @param table - the table whose key collided
1888pub fn rowid_message(table: &TableInfo) -> (i32, String) {
1889    if table.without_rowid {
1890        if let Some(index) = table.indexes.iter().find(|index| index.root == table.root) {
1891            return (codes::PRIMARY_KEY, unique_message(table, index));
1892        }
1893    }
1894    match table.rowid_alias.and_then(|column| table.column(column)) {
1895        Some(column) => (
1896            codes::PRIMARY_KEY,
1897            format!(
1898                "UNIQUE constraint failed: {}.{}",
1899                String::from_utf8_lossy(&table.name),
1900                String::from_utf8_lossy(&column.name)
1901            ),
1902        ),
1903        None => (
1904            codes::ROWID,
1905            format!(
1906                "UNIQUE constraint failed: {}.rowid",
1907                String::from_utf8_lossy(&table.name)
1908            ),
1909        ),
1910    }
1911}
1912
1913/// Returns the refusal a `DELETE` or `UPDATE` with `ORDER BY`/`LIMIT` earns.
1914///
1915/// The pinned reference is not compiled with `SQLITE_ENABLE_UPDATE_DELETE_LIMIT`,
1916/// so it has no grammar for the clause at all and answers `near "ORDER": syntax
1917/// error` with its caret under the word. The syntax register requires the form
1918/// to *parse* here - it is a published production - so the refusal is made here
1919/// instead, in the reference's words and at the reference's position.
1920///
1921/// **It is an `Unexpected`, not a `Refused`, and the distinction is the whole
1922/// message.** This is the one refusal whose text really is `near "X": syntax
1923/// error`, because the reference's parser genuinely has no production for the
1924/// word - unlike the sentence-shaped refusals that were moved off that variant,
1925/// which are a schema saying no to a statement that parsed. Routing it through
1926/// `bind::refused` with them made it answer a bare `ORDER`, which the
1927/// 416-case probe caught as `both-refuse-differently` on `DELETE ... ORDER BY
1928/// ... LIMIT` and `UPDATE ... ORDER BY ... LIMIT`.
1929///
1930/// @param limited - the word and where it was written, from the parser
1931fn limited_dml_refusal(limited: Option<(ast::Limited, Span)>) -> Option<ParseError> {
1932    let (word, span) = limited?;
1933    Some(ParseError::new(
1934        ParseErrorKind::Unexpected {
1935            found: word.word().to_string(),
1936            expected: Vec::new(),
1937        },
1938        span,
1939    ))
1940}
1941
1942#[cfg(test)]
1943mod tests {
1944    use super::*;
1945    use crate::catalog_view::{
1946        ColumnInfo, IndexColumnInfo, IndexInfo, IndexOrigin, TableInfo, TableKind,
1947    };
1948    use inillucent_value::Affinity;
1949
1950    /// Returns one plain column.
1951    ///
1952    /// @param name - the column's name
1953    fn a_column(name: &str) -> ColumnInfo {
1954        ColumnInfo {
1955            name: name.as_bytes().to_vec(),
1956            folded: name.to_ascii_lowercase().into_bytes(),
1957            declared_type: b"INTEGER".to_vec(),
1958            affinity: Affinity::Integer,
1959            collation: b"binary".to_vec(),
1960            not_null: false,
1961            not_null_conflict: None,
1962            primary_key_conflict: None,
1963            default_sql: None,
1964            primary_key_position: None,
1965            hidden: false,
1966            generated: false,
1967            stored: false,
1968            generated_sql: None,
1969        }
1970    }
1971
1972    /// Returns a rowid table with the columns named.
1973    ///
1974    /// @param name - the table's name
1975    /// @param columns - the column names, in declaration order
1976    fn a_table(name: &str, columns: &[&str]) -> TableInfo {
1977        TableInfo {
1978            name: name.as_bytes().to_vec(),
1979            folded: name.to_ascii_lowercase().into_bytes(),
1980            database: 0,
1981            root: 2,
1982            columns: columns.iter().map(|held| a_column(held)).collect(),
1983            rowid_alias: None,
1984            without_rowid: false,
1985            strict: false,
1986            autoincrement: false,
1987            kind: TableKind::Table,
1988            create_sql: Vec::new(),
1989            indexes: Vec::new(),
1990            view: None,
1991            triggers: Vec::new(),
1992            analysed_rows: None,
1993            foreign_key_triggers: Vec::new(),
1994            foreign_keys: Vec::new(),
1995            checks: Vec::new(),
1996            module: None,
1997        }
1998    }
1999
2000    /// Returns an index over the table columns named.
2001    ///
2002    /// @param name - the index's name
2003    /// @param root - its own tree, or the table's for a `WITHOUT ROWID` key
2004    /// @param columns - the table columns it keys on
2005    fn an_index(name: &str, root: u32, columns: &[u16]) -> IndexInfo {
2006        IndexInfo {
2007            name: name.as_bytes().to_vec(),
2008            folded: name.to_ascii_lowercase().into_bytes(),
2009            root,
2010            unique: true,
2011            columns: columns
2012                .iter()
2013                .map(|held| IndexColumnInfo {
2014                    column: Some(*held),
2015                    expr_sql: None,
2016                    collation: b"binary".to_vec(),
2017                    descending: false,
2018                    declared_descending: false,
2019                })
2020                .collect(),
2021            partial_sql: None,
2022            origin: IndexOrigin::Unique,
2023            conflict: None,
2024            prefix_rows: Vec::new(),
2025            analysed_rows: None,
2026            metric: None,
2027        }
2028    }
2029
2030    /// The three spellings of the rowid are the three SQLite accepts.
2031    ///
2032    /// **A fourth would be a column name a table could not have (T3,
2033    /// task-1962).** `rowid`, `oid` and `_rowid_` all name the hidden key, and
2034    /// a table that declares a column called any of them shadows it - so the
2035    /// list decides which names a `SELECT rowid` can mean.
2036    #[test]
2037    fn the_rowid_has_three_names() {
2038        assert!(is_rowid_name(b"rowid"));
2039        assert!(is_rowid_name(b"oid"));
2040        assert!(is_rowid_name(b"_rowid_"));
2041        assert!(!is_rowid_name(b"row_id"));
2042        assert!(!is_rowid_name(b"id"));
2043        assert!(
2044            !is_rowid_name(b"ROWID"),
2045            "the argument is already folded, so an unfolded name is not one this asks about"
2046        );
2047    }
2048
2049    /// A unique violation names every column of the index, table-qualified.
2050    ///
2051    /// **The message is what an application matches on.** SQLite's wording is
2052    /// `UNIQUE constraint failed: t.a, t.b`, and a library that switched on it
2053    /// would stop recognising a collision if the columns were listed any other
2054    /// way.
2055    #[test]
2056    fn a_unique_violation_names_every_column_of_the_index() {
2057        let table = a_table("t", &["a", "b", "c"]);
2058        let one = an_index("by_a", 3, &[0]);
2059        assert_eq!(
2060            unique_message(&table, &one),
2061            "UNIQUE constraint failed: t.a"
2062        );
2063        let two = an_index("by_a_b", 4, &[0, 1]);
2064        assert_eq!(
2065            unique_message(&table, &two),
2066            "UNIQUE constraint failed: t.a, t.b",
2067            "both columns, in key order, separated the way the reference separates them"
2068        );
2069    }
2070
2071    /// A rowid collision names the aliasing column when there is one, and the
2072    /// hidden `rowid` when there is not.
2073    ///
2074    /// The extended code differs with it: `SQLITE_CONSTRAINT_PRIMARYKEY` for an
2075    /// `INTEGER PRIMARY KEY` and `SQLITE_CONSTRAINT_ROWID` for the hidden one.
2076    #[test]
2077    fn a_rowid_collision_names_the_column_that_aliases_it() {
2078        let hidden = a_table("t", &["a"]);
2079        assert_eq!(
2080            rowid_message(&hidden),
2081            (
2082                codes::ROWID,
2083                "UNIQUE constraint failed: t.rowid".to_string()
2084            )
2085        );
2086        let mut aliased = a_table("t", &["id", "a"]);
2087        aliased.rowid_alias = Some(0);
2088        assert_eq!(
2089            rowid_message(&aliased),
2090            (
2091                codes::PRIMARY_KEY,
2092                "UNIQUE constraint failed: t.id".to_string()
2093            )
2094        );
2095    }
2096
2097    /// A `WITHOUT ROWID` table has no rowid to name, so it names its key.
2098    ///
2099    /// **It used to answer `t.rowid`, naming a column the table does not
2100    /// have.** Its own key *is* its primary key, held in the one index whose
2101    /// root is the table's.
2102    #[test]
2103    fn a_without_rowid_collision_names_the_primary_key() {
2104        let mut table = a_table("t", &["a", "b"]);
2105        table.without_rowid = true;
2106        table.indexes = vec![an_index("sqlite_autoindex_t_1", table.root, &[0, 1])];
2107        assert_eq!(
2108            rowid_message(&table),
2109            (
2110                codes::PRIMARY_KEY,
2111                "UNIQUE constraint failed: t.a, t.b".to_string()
2112            )
2113        );
2114    }
2115
2116    /// A constraint's own `ON CONFLICT REPLACE` makes a statement able to
2117    /// replace, with no `OR REPLACE` written anywhere.
2118    #[test]
2119    fn a_constraint_can_make_a_plain_insert_replace() {
2120        let plain = a_table("t", &["a"]);
2121        assert!(!can_replace(&plain, None));
2122        assert!(can_replace(&plain, Some(ConflictAction::Replace)));
2123
2124        let mut on_the_index = a_table("t", &["a"]);
2125        let mut index = an_index("by_a", 3, &[0]);
2126        index.conflict = Some(ConflictAction::Replace);
2127        on_the_index.indexes = vec![index];
2128        assert!(
2129            can_replace(&on_the_index, None),
2130            "`a UNIQUE ON CONFLICT REPLACE` replaces without the statement saying so"
2131        );
2132
2133        let mut on_the_column = a_table("t", &["a"]);
2134        if let Some(column) = on_the_column.columns.first_mut() {
2135            column.not_null_conflict = Some(ConflictAction::Replace);
2136        }
2137        assert!(can_replace(&on_the_column, None));
2138    }
2139}