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