Skip to main content

rudb_bind/
statement.rs

1//! From an `Ast` to a `Bound`, which is a statement rather than a query.
2//!
3//! A `SELECT` binds to a [`Plan`] and nothing else, and that is why [`bind`](crate::bind) can hand
4//! one back. `CREATE TABLE`, `DROP TABLE` and `INSERT` are not plans and are deliberately not being
5//! made into plans. A `Node::CreateTable` would be a node with no columns, no rows, no cost and no
6//! reason to be pushed past anything, which is to say a node the optimizer has to be told to leave
7//! alone and the executor has to special case at the root. `spec/09-optimizer.md` section 9.1 says
8//! every node in a plan produces rows, and a DDL statement does not, so it goes beside the plan and
9//! not inside it.
10//!
11//! What each variant carries is the statement with every name and type already resolved, so the
12//! thing that runs it does catalog calls and nothing else. An `INSERT` in particular arrives with
13//! a plan whose output is exactly the target's columns in the target's order and the target's
14//! types, with the casts and the nulls for unmentioned columns already in it, so appending is a
15//! loop over chunks.
16
17use rudb_catalog::{Catalog, Entry, QualifiedName, duplicate_check, same_name};
18use rudb_common::bounds::End;
19use rudb_common::{
20    Bound as ColumnBound, Clustering, Error, Field, LogicalType, Result, Session, Stat, Value,
21    Width,
22};
23use rudb_parse::ast::{self, Ast};
24use rudb_parse::{NONE, deparse, parse_ast};
25use rudb_plan::{Arm, Expr, ExprRef, Node, Plan, SortKey};
26
27use crate::binder::Binder;
28use crate::parameters::Parameters;
29
30/// One statement, bound.
31///
32/// Not `#[non_exhaustive]`. A new variant here is a new kind of statement, and the compiler
33/// pointing at every place that has to decide what to do with it is the whole value of the enum.
34#[derive(Debug)]
35pub enum Bound {
36    /// A query, which is the only one of these that produces rows.
37    Query(Plan),
38    /// `CREATE TABLE`.
39    CreateTable(CreateTable),
40    /// `CREATE VIEW`.
41    CreateView(CreateView),
42    /// `DROP TABLE` or `DROP VIEW`.
43    DropTable(DropTable),
44    /// `CREATE SCHEMA` or `DROP SCHEMA`.
45    Schema(SchemaChange),
46    /// `CREATE SEQUENCE` or `DROP SEQUENCE`.
47    Sequence(SequenceChange),
48    /// `ALTER TABLE` or `ALTER VIEW`.
49    Alter(Alter),
50    /// `CREATE INDEX` or `DROP INDEX`.
51    Index(IndexChange),
52    /// `INSERT INTO`.
53    Insert(Insert),
54    /// `SET name = value`, or `RESET name`, which is the same thing with no value.
55    Setting(Setting),
56    /// Flushes a persistent database snapshot.
57    Checkpoint,
58    /// `BEGIN`, `COMMIT` or `ROLLBACK`, which have nothing to bind and are carried as written.
59    Transaction(ast::Transaction),
60    /// `EXPLAIN` over a query, holding the plan of the query rather than the query.
61    ///
62    /// The same `Plan` a [`Bound::Query`] would have carried, bound the same way and by the same
63    /// code. What makes it an explain is that the layer above optimizes it and prints it instead
64    /// of running it, which is the point: a plan that was built differently because somebody asked
65    /// to see it is not the plan that runs.
66    ///
67    /// With `analyze` set the layer above runs it as well and prints what happened on it. Still the
68    /// same plan, for the same reason.
69    ///
70    /// With `statistics` set it prints what the planner knew as well, which is the use and the class
71    /// behind every number in the plan. That one changes nothing about the plan or the run either.
72    Explain { plan: Plan, analyze: bool, statistics: bool },
73}
74
75/// A bound `SET` or `RESET`.
76///
77/// The value is a [`Value`] rather than an expression, because every setting there is takes a
78/// string or a number and nothing that runs one wants a plan. What a setting does with the value it
79/// gets is the setting's own business and is decided a layer up, since the binder has no idea what
80/// settings exist.
81///
82/// The narrow part of that is that the value has to already be a constant. `SET threads = 2 + 2` is
83/// four in DuckDB and is refused here, because folding it needs the expression rewriter and the
84/// rewriter is two layers above the binder. Nothing writes arithmetic in a `SET` and the refusal
85/// says what it is, so this waits for a reason to move.
86#[derive(Debug)]
87pub struct Setting {
88    /// The setting name, as written.
89    pub name: String,
90    /// The scope word, if one was written.
91    pub scope: ast::Scope,
92    /// The value, or `None` for a `RESET`.
93    pub value: Option<Value>,
94    /// Whether the statement was written as a bare `PRAGMA name`, which carries its value in it.
95    pub pragma: bool,
96}
97
98/// A bound `CREATE TABLE`.
99#[derive(Debug)]
100pub struct CreateTable {
101    /// The full name the table gets.
102    pub name: QualifiedName,
103    /// The columns, in order, with the types already resolved. For a `CREATE TABLE AS` these are
104    /// the query's output types under whatever names the statement or the query gave them.
105    pub columns: Vec<Field>,
106    /// The query to fill it from, for a `CREATE TABLE AS`.
107    pub source: Option<Plan>,
108    /// Whether an existing table of that name is left alone rather than being an error.
109    pub if_not_exists: bool,
110    /// Whether an existing table of that name is dropped first.
111    pub or_replace: bool,
112    /// The primary key and the unique constraints, over the columns by place.
113    pub keys: Vec<rudb_catalog::Key>,
114    /// Each column's `DEFAULT` as the SQL of its expression, or `None` for a column with none.
115    pub defaults: Vec<Option<String>>,
116    /// The sequences the defaults use, which the table depends on.
117    pub sequences: Vec<QualifiedName>,
118    /// The SQL of each `CHECK`, in the order written.
119    pub checks: Vec<String>,
120    /// The foreign keys, in the order written.
121    pub foreign: Vec<rudb_catalog::ForeignKey>,
122}
123
124/// A bound `CREATE VIEW`.
125///
126/// The body is the text that was written rather than the plan it bound to. It was bound once on the
127/// way through here, which is what refuses a view over a table that is not there, and the plan that
128/// came out of that is then thrown away, because a view follows the tables underneath it and a plan
129/// cannot. See [`rudb_catalog::View`].
130#[derive(Debug)]
131pub struct CreateView {
132    /// The full name the view gets.
133    pub name: QualifiedName,
134    /// The body, as written.
135    pub sql: String,
136    /// The whole statement written back out, which is what `duckdb_views()` reports as `sql`.
137    ///
138    /// Written here because this is the last place the tree is in reach. See
139    /// [`rudb_catalog::View::statement`] for what the column is and why it is not the text.
140    pub statement: String,
141    /// The column names the statement gave, which rename a prefix of what the body produces.
142    pub aliases: Vec<String>,
143    /// Whether an existing entry of that name is left alone rather than being an error.
144    pub if_not_exists: bool,
145    /// Whether an existing entry of that name is dropped first.
146    pub or_replace: bool,
147    /// The columns binding the body produced, after the alias list was applied.
148    ///
149    /// Worked out here because this is where the body is bound, and carried to the catalog because
150    /// that is where `duckdb_columns()` and `duckdb_views()` read it from. See the doc on
151    /// `rudb_catalog::View` for why the catalog keeps a list it will have to refresh later.
152    pub columns: Vec<Field>,
153}
154
155/// A bound `CREATE SCHEMA` or `DROP SCHEMA`.
156///
157/// Only the name is resolved here. Whether the schema is there is a question for the catalog the
158/// statement runs against, which is where `IF NOT EXISTS`, `IF EXISTS` and `OR REPLACE` are
159/// answered.
160#[derive(Debug, Clone, PartialEq, Eq)]
161pub struct SchemaChange {
162    /// The database the schema is in.
163    pub catalog: String,
164    /// The schema's own name.
165    pub name: String,
166    /// Whether this is a `DROP` rather than a `CREATE`.
167    pub drop: bool,
168    /// Whether a create over a schema that is there, or a drop of one that is not, does nothing.
169    pub quiet: bool,
170    /// Whether a create drops a schema that is there first, which a schema that holds anything
171    /// refuses.
172    pub or_replace: bool,
173    /// Whether a drop takes everything in the schema with it.
174    pub cascade: bool,
175}
176
177/// A bound `CREATE SEQUENCE` or `DROP SEQUENCE`.
178#[derive(Debug, Clone, PartialEq, Eq)]
179pub struct SequenceChange {
180    /// The full name. `None` for a `DROP SEQUENCE IF EXISTS` of one that is not there.
181    pub name: Option<QualifiedName>,
182    /// Whether this is a `DROP` rather than a `CREATE`.
183    pub drop: bool,
184    /// Whether a create over a sequence that is there does nothing.
185    pub if_not_exists: bool,
186    /// Whether a create replaces a sequence that is there.
187    pub or_replace: bool,
188    /// Whether a drop takes the tables whose defaults use the sequence with it.
189    pub cascade: bool,
190    /// What a create settled.
191    pub options: rudb_common::sequence::Options,
192    /// The table or view an `ALTER SEQUENCE ... OWNED BY` gives the sequence to, which makes this
193    /// an alter rather than a create.
194    pub owner: Option<QualifiedName>,
195}
196
197/// A bound `ALTER TABLE` or `ALTER VIEW`.
198#[derive(Debug)]
199pub struct Alter {
200    /// The table or view, or `None` when `IF EXISTS` found nothing to change.
201    pub name: Option<QualifiedName>,
202    /// The change, or `None` when an `IF EXISTS` or an `IF NOT EXISTS` on a column made it one.
203    pub alteration: Option<rudb_catalog::Alteration>,
204    /// Every row of the table as it reads after the change, for the changes that move data.
205    pub rewrite: Option<Plan>,
206}
207
208/// A bound `CREATE INDEX` or `DROP INDEX`.
209#[derive(Debug)]
210pub struct IndexChange {
211    /// The table a create is over, and `None` on a drop.
212    pub table: Option<QualifiedName>,
213    /// The index a create makes, stamped by the catalog when it goes in, and `None` on a drop.
214    pub index: Option<rudb_catalog::Index>,
215    /// The name a drop removes, as written, and empty on a create.
216    pub name: Vec<String>,
217    /// Whether `IF NOT EXISTS` or `IF EXISTS` was written.
218    pub quiet: bool,
219}
220
221/// A bound `DROP TABLE` or `DROP VIEW`.
222#[derive(Debug)]
223pub struct DropTable {
224    /// The tables or views to drop, already resolved. With `IF EXISTS` a name that does not resolve
225    /// is not in here at all, which is what makes running this a sequence of drops that cannot
226    /// fail for being missing. Dropping one of these as the wrong type still can, because `DROP
227    /// TABLE IF EXISTS v` where `v` is a view is an error in DuckDB and was measured to be one.
228    pub names: Vec<QualifiedName>,
229    /// Which of the two the statement said it was dropping.
230    pub kind: Entry,
231}
232
233/// A bound `INSERT`.
234#[derive(Debug)]
235pub struct Insert {
236    /// The table to append to.
237    pub name: QualifiedName,
238    /// The rows to append. The output is the table's columns, in the table's order, with the
239    /// table's types, so nothing between here and the append has a decision left to make.
240    pub source: Plan,
241    /// Which of the three writes the source is for.
242    pub write: Write,
243    /// The `RETURNING` list, bound as a query over the table and run over the rows the statement
244    /// wrote in place of the table's own.
245    pub returning: Option<Box<Plan>>,
246    /// What an append does with a row whose key the table already holds.
247    pub conflict: Option<Conflict>,
248    /// The table's `CHECK` constraints, for the rows an append or an update writes.
249    pub checks: Option<Checks>,
250}
251
252/// The `CHECK` constraints of a table, bound as one query over it.
253///
254/// The query answers, for each row the table holds, whether each constraint fails on it. The write
255/// runs it with the table standing in for the rows it wrote, so a failed constraint is found before
256/// anything the statement wrote is kept.
257#[derive(Debug)]
258pub struct Checks {
259    /// One boolean column per constraint, true where the row fails it. A null is a pass.
260    pub plan: Box<Plan>,
261    /// The pin's message for each constraint, in the same order as the columns.
262    pub messages: Vec<String>,
263}
264
265/// A bound `ON CONFLICT`, `INSERT OR REPLACE` or `INSERT OR IGNORE`.
266#[derive(Debug)]
267pub struct Conflict {
268    /// Which of the table's keys a clash is on, or `None` for any of them.
269    pub key: Option<usize>,
270    /// What happens to a row that clashes.
271    pub action: ConflictAction,
272}
273
274/// What happens to a row whose key the table already holds.
275#[derive(Debug)]
276pub enum ConflictAction {
277    /// The row is dropped.
278    Nothing,
279    /// The held row takes the new row's values in these columns.
280    Replace(Vec<usize>),
281    /// The held row takes the values the plan works out in these columns. The plan reads the held
282    /// rows as the table and the new rows as [`QualifiedName::excluded`], one of each per row it
283    /// answers, and after a value for each column answers whether the row is updated at all.
284    Update {
285        /// The columns that are set, by place in the table.
286        columns: Vec<usize>,
287        /// The query that works the values out.
288        plan: Box<Plan>,
289    },
290}
291
292/// What an [`Insert`]'s source means for the table.
293#[derive(Debug, Clone, Copy, PartialEq, Eq)]
294pub enum Write {
295    /// The rows are added to the table.
296    Append,
297    /// The rows are the whole table afterwards, and one more column after the table's says which
298    /// of them the statement changed, so it can count them and return them.
299    Update,
300    /// The rows are the table as it was, and the column after the table's says which of them
301    /// the statement deletes. The table keeps the rest.
302    Delete,
303}
304
305/// The `RETURNING` query of a writing statement, bound over the table it writes.
306fn returning(
307    ast: &Ast,
308    catalog: &Catalog,
309    parameters: &Parameters,
310    session: &Session,
311    query: Option<ast::QueryRef>,
312) -> Result<Option<Box<Plan>>> {
313    let Some(query) = query else { return Ok(None) };
314    let mut binder = Binder::with(catalog, parameters, session);
315    let (root, _) = binder.bind_query(ast, query)?;
316    Ok(Some(Box::new(finish(binder, root)?)))
317}
318
319/// Binds one parsed statement against a catalog.
320///
321/// # Errors
322///
323/// If the script does not hold exactly one statement, if a name does not resolve, if a type does
324/// not work out, or if the statement uses something that is not bound yet.
325pub fn bind_statement(ast: &Ast, catalog: &Catalog) -> Result<Bound> {
326    bind_statement_with(ast, catalog, &Parameters::new(), &Session::new())
327}
328
329/// Binds one parsed statement against a catalog, with values for its parameters and its settings.
330///
331/// This is the prepared statement path. The statement is parsed once and bound once per set of
332/// values, so a parameter is a constant by the time the plan exists and everything after the binder
333/// sees an ordinary query. That is why there is no parameter in `rudb_plan::Expr`.
334///
335/// # Errors
336///
337/// Everything [`bind_statement`] reports, plus an error for a parameter that was given no value.
338pub fn bind_statement_with(
339    ast: &Ast,
340    catalog: &Catalog,
341    parameters: &Parameters,
342    session: &Session,
343) -> Result<Bound> {
344    bind_one(ast, catalog, parameters, session, false)
345}
346
347/// Binds one statement the way [`bind_statement_with`] does, except that a query reads a Parquet
348/// file that could go through a native mirror from its columns and row count alone.
349///
350/// For the first bind of a query that will be bound again once its mirrors are in. A query that
351/// comes back with [`rudb_plan::Plan::wanted_mirrors`] empty was bound in full and can run. One that
352/// comes back with any must be bound again with [`bind_statement_with`] before it runs, because the
353/// reads that asked for a mirror were bound without the bounds and the distinct counts the
354/// optimizer would have used.
355///
356/// # Errors
357///
358/// Everything [`bind_statement_with`] reports.
359pub fn bind_statement_outlined(
360    ast: &Ast,
361    catalog: &Catalog,
362    parameters: &Parameters,
363    session: &Session,
364) -> Result<Bound> {
365    bind_one(ast, catalog, parameters, session, true)
366}
367
368fn bind_one(
369    ast: &Ast,
370    catalog: &Catalog,
371    parameters: &Parameters,
372    session: &Session,
373    outlined: bool,
374) -> Result<Bound> {
375    let statement = match ast.statements.as_slice() {
376        [statement] => *statement,
377        [] => return Err(Error::binder("no statement to bind")),
378        _ => return Err(Error::not_implemented("a script of more than one statement")),
379    };
380    match statement {
381        ast::Statement::Query(query) => {
382            let mut binder = Binder::with(catalog, parameters, session);
383            binder.outlined = outlined;
384            let (root, _) = binder.bind_query(ast, query)?;
385            Ok(Bound::Query(finish(binder, root)?))
386        }
387        ast::Statement::CreateTable(index) => {
388            create_table(ast, catalog, parameters, session, index)
389        }
390        ast::Statement::CreateView(index) => create_view(ast, catalog, parameters, session, index),
391        ast::Statement::DropTable(index) => drop_table(ast, catalog, index),
392        ast::Statement::Schema(index) => {
393            let written = ast.schema(index);
394            if written.temporary {
395                return Err(Error::binder("Temporary schemas are not supported"));
396            }
397            let parts: Vec<&str> = ast.name(written.name).collect();
398            let (catalog, name) = catalog.schema_name(&parts)?;
399            Ok(Bound::Schema(SchemaChange {
400                catalog,
401                name,
402                drop: written.drop,
403                quiet: written.quiet,
404                or_replace: written.or_replace,
405                cascade: written.cascade,
406            }))
407        }
408        ast::Statement::Sequence(index) => {
409            let written = ast.sequence(index);
410            let parts: Vec<&str> = ast.name(written.name).collect();
411            let alter = !written.owner.is_empty();
412            let mut owner = None;
413            let name = if written.drop || alter {
414                match catalog.resolve_sequence(&parts) {
415                    Ok(name) => Some(name),
416                    Err(_) if written.quiet => None,
417                    Err(error) => return Err(error),
418                }
419            } else if written.temporary {
420                Some(catalog.resolve_for_create_temporary(&parts)?)
421            } else {
422                Some(catalog.resolve_for_create(&parts)?)
423            };
424            if alter && name.is_some() {
425                let parts: Vec<&str> = ast.name(written.owner).collect();
426                owner = Some(catalog.resolve_owner(&parts)?);
427            }
428            Ok(Bound::Sequence(SequenceChange {
429                name,
430                drop: written.drop,
431                if_not_exists: written.quiet,
432                or_replace: written.or_replace,
433                cascade: written.cascade,
434                options: written.options,
435                owner,
436            }))
437        }
438        ast::Statement::Alter(index) => alter(ast, catalog, parameters, session, index),
439        ast::Statement::Index(index) => create_index(ast, catalog, parameters, session, index),
440        ast::Statement::Insert(index) => insert(ast, catalog, parameters, session, index),
441        ast::Statement::Update(index) => change(ast, catalog, parameters, session, index, false),
442        ast::Statement::Delete(index) => change(ast, catalog, parameters, session, index, true),
443        ast::Statement::Set(index) | ast::Statement::Reset(index) => {
444            setting(ast, catalog, parameters, session, index)
445        }
446        ast::Statement::Checkpoint => Ok(Bound::Checkpoint),
447        ast::Statement::Transaction(kind) => Ok(Bound::Transaction(kind)),
448        ast::Statement::Explain { query, analyze, statistics } => {
449            let mut binder = Binder::with(catalog, parameters, session);
450            let (root, _) = binder.bind_query(ast, query)?;
451            Ok(Bound::Explain { plan: finish(binder, root)?, analyze, statistics })
452        }
453    }
454}
455
456/// Parses and binds one statement, which is the whole front end in one call.
457///
458/// # Errors
459///
460/// Anything the parser or the binder reports.
461pub fn bind_statement_sql(sql: &str, catalog: &Catalog) -> Result<Bound> {
462    let ast = parse_ast(sql)?;
463    bind_statement(&ast, catalog)
464}
465
466/// Roots a binder's plan and checks it.
467fn finish(binder: Binder<'_>, root: rudb_plan::NodeRef) -> Result<Plan> {
468    let mut plan = binder.into_plan();
469    plan.set_root(root);
470    plan.validate()?;
471    Ok(plan)
472}
473
474fn create_table(
475    ast: &Ast,
476    catalog: &Catalog,
477    parameters: &Parameters,
478    session: &Session,
479    index: ast::CreateTableRef,
480) -> Result<Bound> {
481    let written = ast.create_table(index);
482    let parts: Vec<&str> = ast.name(written.name).collect();
483    let name = if written.temporary {
484        catalog.resolve_for_create_temporary(&parts)?
485    } else {
486        catalog.resolve_for_create(&parts)?
487    };
488    let defs = ast.column_defs(written.columns);
489    let (mut columns, source) = if written.query == NONE {
490        let mut columns = Vec::with_capacity(defs.len());
491        for def in defs {
492            let text = ast.string(def.ty);
493            if text.is_empty() {
494                return Err(Error::binder(format!(
495                    "Column \"{}\" was declared without a type",
496                    ast.string(def.name)
497                )));
498            }
499            let ty = LogicalType::parse(text)?;
500            let column = ast.string(def.name);
501            columns.push(if def.not_null {
502                Field::required(column, ty)
503            } else {
504                Field::new(column, ty)
505            });
506        }
507        (columns, None)
508    } else {
509        let mut binder = Binder::with(catalog, parameters, session);
510        let (root, scope) = binder.bind_query(ast, written.query)?;
511        if defs.len() > scope.len() {
512            // DuckDB's sentence, typo and all. A column list shorter than the query is fine and
513            // renames a prefix, so only this direction is an error.
514            return Err(Error::binder("Target table has more colum names than query result."));
515        }
516        let mut columns = Vec::with_capacity(scope.columns.len());
517        for (at, column) in scope.columns.iter().enumerate() {
518            let named = match defs.get(at) {
519                Some(def) => ast.string(def.name).to_string(),
520                None => column.name.clone(),
521            };
522            columns.push(Field::new(named, column.ty.clone()));
523        }
524        if defs.is_empty() {
525            deduplicate(&mut columns);
526        }
527        (columns, Some(finish(binder, root)?))
528    };
529    duplicate_check(&columns)?;
530    let mut defaults = Vec::with_capacity(defs.len());
531    let mut sequences = Vec::new();
532    for def in defs {
533        defaults.push(if def.default == NONE {
534            None
535        } else {
536            let (text, used) = default_text(ast, def.default, catalog, parameters, session)?;
537            for name in used {
538                if !sequences.contains(&name) {
539                    sequences.push(name);
540                }
541            }
542            Some(text)
543        });
544    }
545    let mut checks = Vec::new();
546    for &expr in ast.expr_list(written.checks) {
547        checks.push(check_text(ast, expr, &columns, catalog, parameters, session)?);
548    }
549    let mut keys = Vec::new();
550    for (at, &names) in ast.name_list(written.keys).iter().enumerate() {
551        let mut places = Vec::new();
552        for wanted in ast.name(names) {
553            let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted))
554            else {
555                return Err(Error::catalog(format!(
556                    "table \"{}\" does not have a column named \"{wanted}\"",
557                    name.table
558                )));
559            };
560            places.push(place);
561        }
562        let primary = at as u32 == written.primary;
563        if primary {
564            for &place in &places {
565                columns[place].not_null = true;
566            }
567        }
568        keys.push(rudb_catalog::Key { columns: places, primary });
569    }
570    let mut foreign = Vec::new();
571    let lists = ast.name_list(written.foreign).iter();
572    let tables = ast.name_list(written.foreign_tables).iter();
573    let referenced = ast.name_list(written.foreign_referenced).iter();
574    for ((&names, &table), &wanted) in lists.zip(tables).zip(referenced) {
575        let names: Vec<&str> = ast.name(names).collect();
576        let parts: Vec<&str> = ast.name(table).collect();
577        let wanted: Vec<&str> = ast.name(wanted).collect();
578        let key = (names.as_slice(), parts.as_slice(), wanted.as_slice());
579        foreign.push(foreign_key(catalog, &name, (&columns, &keys), key)?);
580    }
581    Ok(Bound::CreateTable(CreateTable {
582        name,
583        columns,
584        source,
585        if_not_exists: written.if_not_exists,
586        or_replace: written.or_replace,
587        keys,
588        defaults,
589        checks,
590        foreign,
591        sequences,
592    }))
593}
594
595/// One `FOREIGN KEY` of a table being made, refused the way the pin refuses one that names no key
596/// of the referenced table or pairs columns of different types.
597///
598/// The referenced table is the one being made when the name is its own, and then its columns and
599/// keys are the ones this statement declares.
600fn foreign_key(
601    catalog: &Catalog,
602    made: &QualifiedName,
603    (columns, keys): (&[Field], &[rudb_catalog::Key]),
604    (names, parts, wanted): (&[&str], &[&str], &[&str]),
605) -> Result<rudb_catalog::ForeignKey> {
606    let mut places = Vec::with_capacity(names.len());
607    for &wanted in names {
608        let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted)) else {
609            return Err(Error::binder(format!(
610                "Failed to create foreign key: referencing column \"{wanted}\" does not exist"
611            )));
612        };
613        places.push(place);
614    }
615    let own = parts.last().is_some_and(|last| same_name(last, &made.table))
616        && catalog.resolve(parts).map_or(true, |resolved| resolved == *made);
617    let (table, fields, held): (QualifiedName, Vec<Field>, Vec<rudb_catalog::Key>) = if own {
618        (made.clone(), columns.to_vec(), keys.to_vec())
619    } else {
620        let resolved = catalog.resolve(parts)?;
621        if catalog.view(&resolved).is_ok() {
622            return Err(Error::binder("cannot reference a VIEW with a FOREIGN KEY"));
623        }
624        let table = catalog.table(&resolved)?;
625        (resolved, table.columns().to_vec(), table.keys().to_vec())
626    };
627    let referenced = if wanted.is_empty() {
628        let Some(primary) = held.iter().find(|key| key.primary) else {
629            return Err(Error::binder(format!(
630                "Failed to create foreign key: there is no primary key for referenced table \"{}\"",
631                table.table
632            )));
633        };
634        if primary.columns.len() != places.len() {
635            return Err(Error::parser(
636                "The number of referencing and referenced columns for foreign keys must be the same",
637            ));
638        }
639        primary.columns.clone()
640    } else {
641        let mut referenced = Vec::with_capacity(wanted.len());
642        for &column in wanted {
643            let Some(place) = fields.iter().position(|field| same_name(&field.name, column)) else {
644                return Err(Error::binder(format!(
645                    "Failed to create foreign key: referenced table \"{}\" does not have a column \
646                     named \"{column}\"",
647                    table.table
648                )));
649            };
650            referenced.push(place);
651        }
652        let mut sorted = referenced.clone();
653        sorted.sort_unstable();
654        let matched = held.iter().any(|key| {
655            let mut columns = key.columns.clone();
656            columns.sort_unstable();
657            columns == sorted
658        });
659        if !matched && held.is_empty() {
660            return Err(Error::binder(format!(
661                "Failed to create foreign key: there is no primary key or unique constraint for \
662                 referenced table \"{}\"",
663                table.table
664            )));
665        }
666        if !matched {
667            return Err(Error::binder(format!(
668                "Failed to create foreign key: referenced table \"{}\" does not have a primary key \
669                 or unique constraint on the columns {}",
670                table.table,
671                wanted.join(", ")
672            )));
673        }
674        referenced
675    };
676    for (&from, &to) in places.iter().zip(&referenced) {
677        if columns[from].ty != fields[to].ty {
678            return Err(Error::binder(format!(
679                "Failed to create foreign key: incompatible types between column \"{}\" (\"{}\") \
680                 and column \"{}\" (\"{}\")",
681                fields[to].name, fields[to].ty, columns[from].name, columns[from].ty
682            )));
683        }
684    }
685    Ok(rudb_catalog::ForeignKey { columns: places, table, referenced })
686}
687
688/// The SQL a `CHECK` is kept as, refused the way the pin refuses one when the table is made.
689fn check_text(
690    ast: &Ast,
691    expr: ast::ExprRef,
692    columns: &[Field],
693    catalog: &Catalog,
694    parameters: &Parameters,
695    session: &Session,
696) -> Result<String> {
697    if crate::expr::has_aggregate(ast, expr) {
698        return Err(Error::binder("aggregate functions are not allowed in check constraints"));
699    }
700    let mut binder = Binder::with(catalog, parameters, session);
701    let index = binder.fresh_index();
702    let mut scope = crate::scope::Scope::empty();
703    for (at, field) in columns.iter().enumerate() {
704        scope.push(crate::scope::Visible {
705            table: String::new(),
706            name: field.name.clone(),
707            binding: rudb_plan::ColumnBinding::new(index, at as u32),
708            ty: field.ty.clone(),
709            not_null: false,
710            key: None,
711            default: None,
712            qualified: false,
713            also: None,
714        });
715    }
716    match binder.bind_expr(ast, expr, &scope) {
717        Err(error) if error.message().starts_with("Referenced column \"") => {
718            let column = error.message().split('"').nth(1).unwrap_or_default();
719            Err(Error::binder(format!(
720                "Table does not contain column \"{column}\" referenced in check constraint!"
721            )))
722        }
723        Err(error) => Err(error),
724        Ok(_) if !binder.windows.is_empty() => {
725            Err(Error::binder("window functions are not allowed in check constraints"))
726        }
727        Ok(_) => Ok(deparse::expression(ast, expr)),
728    }
729}
730
731/// The `CHECK` constraints of a table as the query a write runs over the rows it wrote, or `None`
732/// for a table with none.
733fn bind_checks(
734    catalog: &Catalog,
735    parameters: &Parameters,
736    session: &Session,
737    name: &QualifiedName,
738) -> Result<Option<Checks>> {
739    let table = catalog.table(name)?;
740    if table.checks().is_empty() {
741        return Ok(None);
742    }
743    let failed: Vec<String> =
744        table.checks().iter().map(|text| format!("NOT CAST(({text}) AS BOOLEAN)")).collect();
745    let ast = parse_ast(&format!("SELECT {}", failed.join(", ")))?;
746    let ast::Statement::Query(query) = ast.statements[0] else {
747        return Err(Error::internal("a check that is not an expression"));
748    };
749    let ast::QueryBody::Select(select) = ast.query(query).body else {
750        return Err(Error::internal("a check that is not an expression"));
751    };
752    let mut binder = Binder::with(catalog, parameters, session);
753    let (root, scope) =
754        binder.bind_catalog_table(&ast, name, name.table.clone(), ast::Slice::default())?;
755    let mut exprs = Vec::with_capacity(failed.len());
756    let mut names = Vec::with_capacity(failed.len());
757    for target in ast.target_list(ast.select(select).targets) {
758        exprs.push(binder.bind_expr(&ast, target.expr, &scope)?);
759        names.push(binder.plan_mut().intern("failed"));
760    }
761    let exprs = binder.plan_mut().add_expr_list(&exprs);
762    let names = binder.plan_mut().add_name_list(&names);
763    let index = binder.fresh_index();
764    let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
765    let messages = table
766        .checks()
767        .iter()
768        .map(|text| {
769            format!(
770                "CHECK constraint failed on table \"{}\" with expression CHECK({text})",
771                name.table
772            )
773        })
774        .collect();
775    Ok(Some(Checks { plan: Box::new(finish(binder, root)?), messages }))
776}
777
778/// The SQL a column's `DEFAULT` is kept as, refused the way the pin refuses one when the table is
779/// made. The expression is bound once here to find out, and bound again by every insert that needs
780/// it, because a default like `random()` is worked out per row.
781fn default_text(
782    ast: &Ast,
783    expr: ast::ExprRef,
784    catalog: &Catalog,
785    parameters: &Parameters,
786    session: &Session,
787) -> Result<(String, Vec<QualifiedName>)> {
788    if crate::expr::has_aggregate(ast, expr) {
789        return Err(Error::binder("DEFAULT value cannot contain aggregates!"));
790    }
791    let mut binder = Binder::with(catalog, parameters, session);
792    let before = binder.plan_mut().node_count();
793    match binder.bind_expr(ast, expr, &crate::scope::Scope::empty()) {
794        Err(error) if error.message().starts_with("Referenced ") => {
795            Err(Error::binder("DEFAULT value cannot contain column names"))
796        }
797        Err(error) => Err(error),
798        // Nothing but a subquery adds a node to the plan while an expression over no rows binds.
799        Ok(_) if binder.plan_mut().node_count() > before => {
800            Err(Error::binder("DEFAULT value cannot contain subqueries"))
801        }
802        Ok(_) if !binder.windows.is_empty() => {
803            Err(Error::binder("DEFAULT value cannot contain window functions!"))
804        }
805        Ok(_) => Ok((deparse::expression(ast, expr), binder.sequences)),
806    }
807}
808
809/// `ALTER TABLE` and `ALTER VIEW`, refused the way the pin refuses each change before the catalog
810/// sees it: a missing column is the binder's sentence, and so is changing the type of a column a
811/// constraint is over.
812fn alter(
813    ast: &Ast,
814    catalog: &Catalog,
815    parameters: &Parameters,
816    session: &Session,
817    index: ast::AlterRef,
818) -> Result<Bound> {
819    let written = ast.alter(index);
820    let nothing = |name| Ok(Bound::Alter(Alter { name, alteration: None, rewrite: None }));
821    let parts: Vec<&str> = ast.name(written.name).collect();
822    let wanted = if written.view { Entry::View } else { Entry::Table };
823    let name = match catalog.resolve_as(&parts, wanted) {
824        Ok(name) => name,
825        Err(_) if written.quiet => return nothing(None),
826        Err(error) => return Err(error),
827    };
828    let kind = catalog.entry(&name)?;
829    if written.view && kind == Entry::Table {
830        return Err(Error::catalog("Can only modify table with ALTER TABLE statement"));
831    }
832    if let ast::AlterAction::Rename { to } = written.action {
833        let alteration = rudb_catalog::Alteration::Rename(ast.string(to).to_string());
834        return Ok(Bound::Alter(Alter {
835            name: Some(name),
836            alteration: Some(alteration),
837            rewrite: None,
838        }));
839    }
840    if kind == Entry::View {
841        return Err(Error::catalog("Can only modify view with ALTER VIEW statement"));
842    }
843    let table = catalog.table(&name)?;
844    let fields = table.columns();
845    let place = |column: ast::StrRef| {
846        fields.iter().position(|field| same_name(&field.name, ast.string(column)))
847    };
848    let missing = |column: ast::StrRef| {
849        let names: Vec<String> = fields.iter().map(|field| format!("\"{}\"", field.name)).collect();
850        Error::binder(format!(
851            "Table \"{}\" does not have a column with name \"{}\"\n\nDid you mean: {}",
852            name.table,
853            ast.string(column),
854            names.join(", ")
855        ))
856    };
857    let found = |column: ast::StrRef| place(column).ok_or_else(|| missing(column));
858    let checks = table.checks();
859    let mut rewrite = None;
860    let alteration = match written.action {
861        ast::AlterAction::Rename { .. } => unreachable!("a rename is handled above"),
862        ast::AlterAction::RenameColumn { column, to } => {
863            let at = found(column)?;
864            let (old, to) = (fields[at].name.as_str(), ast.string(to));
865            if in_foreign_key(catalog, &name, table, at) {
866                // The doubled quotes are the pin's, which quotes a name that is already quoted.
867                return Err(Error::catalog(format!(
868                    "Cannot rename column \"\"{old}\"\" because this is involved in the foreign key \
869                     constraint"
870                )));
871            }
872            let checks =
873                checks.iter().map(|text| rename_in(text, old, to)).collect::<Result<Vec<_>>>()?;
874            rudb_catalog::Alteration::RenameColumn { column: at, to: to.to_string(), checks }
875        }
876        ast::AlterAction::AddColumn { column, quiet } => {
877            if quiet && place(column.name).is_some() {
878                return nothing(Some(name));
879            }
880            let ty = LogicalType::parse(ast.string(column.ty))?;
881            let field = Field {
882                not_null: column.not_null,
883                ..Field::new(ast.string(column.name), ty.clone())
884            };
885            let (default, sequences) = if column.default == NONE {
886                (None, Vec::new())
887            } else {
888                let (text, used) = default_text(ast, column.default, catalog, parameters, session)?;
889                (Some(text), used)
890            };
891            rewrite = Some(table_rewrite(
892                ast,
893                (catalog, parameters, session),
894                &name,
895                |binder, _, out| {
896                    let value = if column.default == NONE {
897                        let null = binder.add_constant(Value::Null);
898                        binder.cast_to(null, &ty)
899                    } else {
900                        let value =
901                            binder.bind_expr(ast, column.default, &crate::scope::Scope::empty())?;
902                        binder.checked_cast_to(value, &ty, false)?
903                    };
904                    out.push((value, field.name.clone()));
905                    Ok(())
906                },
907            )?);
908            rudb_catalog::Alteration::AddColumn { field, default, sequences }
909        }
910        ast::AlterAction::DropColumn { column, quiet } => {
911            let Some(at) = place(column) else {
912                return if quiet { nothing(Some(name)) } else { Err(missing(column)) };
913            };
914            let dropped = fields[at].name.as_str();
915            let mut kept = Vec::with_capacity(checks.len());
916            for text in checks {
917                let used = columns_in(text)?;
918                if !used.iter().any(|used| same_name(used, dropped)) {
919                    kept.push(text.clone());
920                } else if used.iter().any(|used| !same_name(used, dropped)) {
921                    return Err(Error::catalog(format!(
922                        "Cannot drop column \"{dropped}\" because there is a CHECK constraint that \
923                         depends on it"
924                    )));
925                }
926            }
927            rewrite =
928                Some(table_rewrite(ast, (catalog, parameters, session), &name, |_, _, out| {
929                    out.remove(at);
930                    Ok(())
931                })?);
932            rudb_catalog::Alteration::DropColumn { column: at, checks: kept }
933        }
934        ast::AlterAction::Default { column, default } => {
935            let at = found(column)?;
936            let (default, sequences) = if default == NONE {
937                (None, Vec::new())
938            } else {
939                let (text, used) = default_text(ast, default, catalog, parameters, session)?;
940                (Some(text), used)
941            };
942            rudb_catalog::Alteration::Default { column: at, default, sequences }
943        }
944        ast::AlterAction::NotNull { column, set } => {
945            rudb_catalog::Alteration::NotNull { column: found(column)?, set }
946        }
947        ast::AlterAction::Type { column, ty, using } => {
948            let at = found(column)?;
949            let changed = fields[at].name.as_str();
950            if table.keys().iter().any(|key| key.columns.contains(&at)) {
951                return Err(Error::binder(
952                    "Cannot change the type of a column that has a UNIQUE or PRIMARY KEY \
953                     constraint specified",
954                ));
955            }
956            for text in checks {
957                if columns_in(text)?.iter().any(|used| same_name(used, changed)) {
958                    return Err(Error::binder(
959                        "Cannot change the type of a column that has a CHECK constraint specified",
960                    ));
961                }
962            }
963            if in_foreign_key(catalog, &name, table, at) {
964                return Err(Error::binder(
965                    "Cannot change the type of a column that has a FOREIGN KEY constraint specified",
966                ));
967            }
968            let mut target =
969                if ty == NONE { None } else { Some(LogicalType::parse(ast.string(ty))?) };
970            rewrite = Some(table_rewrite(
971                ast,
972                (catalog, parameters, session),
973                &name,
974                |binder, scope, out| {
975                    let value = if using == NONE {
976                        out[at].0
977                    } else {
978                        binder.bind_expr(ast, using, scope)?
979                    };
980                    let ty = target
981                        .get_or_insert_with(|| binder.plan_mut().expr_type(value).clone())
982                        .clone();
983                    out[at].0 = binder.checked_cast_to(value, &ty, false)?;
984                    Ok(())
985                },
986            )?);
987            let ty = target.ok_or_else(|| Error::internal("an ALTER TYPE that settled no type"))?;
988            rudb_catalog::Alteration::Type { column: at, ty }
989        }
990    };
991    Ok(Bound::Alter(Alter { name: Some(name), alteration: Some(alteration), rewrite }))
992}
993
994/// `CREATE INDEX` and `DROP INDEX`, with every refusal the pin makes before its catalog sees the
995/// index. A drop is only its name here, since which index it is depends on the catalog it runs
996/// against.
997///
998/// Each element is bound over the table to find its type and the columns it reads. A bare column
999/// is written back by its name and anything else inside parentheses, so `ON t(b, (a+1))` keeps
1000/// `b` and `((a + 1))`, which is what the pin's `sql` and `expressions` show.
1001fn create_index(
1002    ast: &Ast,
1003    catalog: &Catalog,
1004    parameters: &Parameters,
1005    session: &Session,
1006    at: ast::IndexRef,
1007) -> Result<Bound> {
1008    let written = ast.index(at);
1009    let parts: Vec<String> = ast.name(written.name).map(str::to_string).collect();
1010    if written.drop {
1011        return Ok(Bound::Index(IndexChange {
1012            table: None,
1013            index: None,
1014            name: parts,
1015            quiet: written.quiet,
1016        }));
1017    }
1018    let written_table: Vec<&str> = ast.name(written.table).collect();
1019    let name = catalog.resolve_as(&written_table, Entry::Table)?;
1020    if catalog.entry(&name)? == Entry::View {
1021        return Err(Error::binder("can only create an index on a base table"));
1022    }
1023    if written.using != NONE && !same_name(ast.string(written.using), "art") {
1024        return Err(Error::binder(format!("Unknown index type: {}", ast.string(written.using))));
1025    }
1026    let fields = catalog.table(&name)?.columns();
1027    let mut binder = Binder::with(catalog, parameters, session);
1028    let (_, scope) =
1029        binder.bind_catalog_table(ast, &name, name.table.clone(), ast::Slice::default())?;
1030    let mut columns = Vec::new();
1031    let mut plain = true;
1032    let mut texts = Vec::new();
1033    for &expr in ast.expr_list(written.elements) {
1034        if let ast::Expr::Column { name: column } = ast.exprs[expr as usize] {
1035            let column: Vec<&str> = ast.name(column).collect();
1036            if let [only] = column[..] {
1037                if !fields.iter().any(|field| same_name(&field.name, only)) {
1038                    let names: Vec<String> =
1039                        fields.iter().map(|field| format!("\"{}\"", field.name)).collect();
1040                    // The stray colon is the pin's.
1041                    return Err(Error::binder(format!(
1042                        "Table \"{}\" does not have a column named \"{only}\"\n\nCandidate bindings: \
1043                         : {}",
1044                        name.table,
1045                        names.join(", ")
1046                    )));
1047                }
1048            }
1049        }
1050        if crate::expr::has_aggregate(ast, expr) {
1051            return Err(Error::binder("aggregate functions are not allowed in index expressions"));
1052        }
1053        let before = binder.plan_mut().node_count();
1054        let value = binder.bind_expr(ast, expr, &scope)?;
1055        if binder.plan_mut().node_count() > before {
1056            return Err(Error::binder("cannot use subquery in index expressions"));
1057        }
1058        if !binder.windows.is_empty() {
1059            return Err(Error::binder("window functions are not allowed in index expressions"));
1060        }
1061        let ty = binder.plan_mut().expr_type(value).clone();
1062        if ty.is_nested() {
1063            return Err(Error::invalid_type(format!(
1064                "Invalid Type [{ty}]: Invalid type for index key."
1065            )));
1066        }
1067        let bare = match binder.plan_mut().expr(value) {
1068            Expr::Column(binding) => scope.columns.iter().position(|held| held.binding == *binding),
1069            _ => None,
1070        };
1071        if let Some(at) = bare {
1072            columns.push(at);
1073            texts.push(rudb_parse::quoted(&fields[at].name));
1074            continue;
1075        }
1076        plain = false;
1077        let text = deparse::expression(ast, expr);
1078        let used = columns_in(&text)?;
1079        if used.is_empty() {
1080            return Err(Error::binder(
1081                "CREATE INDEX does not refer to any columns in the base table!",
1082            ));
1083        }
1084        for used in used {
1085            if let Some(at) = fields.iter().position(|field| same_name(&field.name, &used)) {
1086                columns.push(at);
1087            }
1088        }
1089        texts.push(format!("({text})"));
1090    }
1091    if written.unique && !plain {
1092        return Err(Error::not_implemented("A UNIQUE index over an expression is not supported"));
1093    }
1094    let expressions = Value::List {
1095        element: LogicalType::Varchar,
1096        values: texts.iter().map(|text| Value::Varchar(text.clone())).collect(),
1097    };
1098    let unique = if written.unique { "UNIQUE " } else { "" };
1099    let table: Vec<String> = written_table.iter().map(|part| rudb_parse::quoted(part)).collect();
1100    let using = if written.using == NONE {
1101        String::new()
1102    } else {
1103        format!(" USING {} ", ast.string(written.using))
1104    };
1105    let index_name = parts.last().cloned().unwrap_or_default();
1106    let sql = format!(
1107        "CREATE {unique}INDEX {} ON {}{using}({});",
1108        rudb_parse::quoted(&index_name),
1109        table.join("."),
1110        texts.join(", ")
1111    );
1112    if !plain {
1113        columns.sort_unstable();
1114        columns.dedup();
1115    }
1116    let index = rudb_catalog::Index {
1117        name: index_name,
1118        unique: written.unique,
1119        columns,
1120        plain,
1121        expressions: expressions.to_string(),
1122        sql,
1123        oid: 0,
1124    };
1125    Ok(Bound::Index(IndexChange {
1126        table: Some(name),
1127        index: Some(index),
1128        name: Vec::new(),
1129        quiet: written.quiet,
1130    }))
1131}
1132
1133/// Whether a column is in one of its table's foreign keys, or is a column another table's foreign
1134/// key points at.
1135fn in_foreign_key(
1136    catalog: &Catalog,
1137    name: &QualifiedName,
1138    table: &rudb_catalog::Table,
1139    at: usize,
1140) -> bool {
1141    table.foreign().iter().any(|key| key.columns.contains(&at))
1142        || catalog.tables().any(|held| {
1143            held.foreign().iter().any(|key| key.table == *name && key.referenced.contains(&at))
1144        })
1145}
1146
1147/// A plan over every row of a table giving each of its columns, as changed by `change`, which gets
1148/// the column expressions and their names in order and can add, drop or replace any of them.
1149fn table_rewrite(
1150    ast: &Ast,
1151    (catalog, parameters, session): (&Catalog, &Parameters, &Session),
1152    name: &QualifiedName,
1153    change: impl FnOnce(
1154        &mut Binder<'_>,
1155        &crate::scope::Scope,
1156        &mut Vec<(ExprRef, String)>,
1157    ) -> Result<()>,
1158) -> Result<Plan> {
1159    let mut binder = Binder::with(catalog, parameters, session);
1160    let (root, scope) =
1161        binder.bind_catalog_table(ast, name, name.table.clone(), ast::Slice::default())?;
1162    let mut out = Vec::with_capacity(scope.columns.len() + 1);
1163    for column in &scope.columns {
1164        let expr = binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1165        out.push((expr, column.name.clone()));
1166    }
1167    change(&mut binder, &scope, &mut out)?;
1168    let exprs: Vec<ExprRef> = out.iter().map(|(expr, _)| *expr).collect();
1169    let names: Vec<_> = out.iter().map(|(_, name)| binder.plan_mut().intern(name)).collect();
1170    let exprs = binder.plan_mut().add_expr_list(&exprs);
1171    let names = binder.plan_mut().add_name_list(&names);
1172    let index = binder.fresh_index();
1173    let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1174    finish(binder, root)
1175}
1176
1177/// A kept `CHECK`, parsed back into an expression.
1178fn check_ast(text: &str) -> Result<(Ast, ast::ExprRef)> {
1179    let ast = parse_ast(&format!("SELECT {text}"))?;
1180    let found = match ast.statements.first() {
1181        Some(&ast::Statement::Query(query)) => match ast.query(query).body {
1182            ast::QueryBody::Select(select) => {
1183                ast.target_list(ast.select(select).targets).first().map(|target| target.expr)
1184            }
1185            _ => None,
1186        },
1187        _ => None,
1188    };
1189    let expr = found.ok_or_else(|| Error::internal("a check that is not an expression"))?;
1190    Ok((ast, expr))
1191}
1192
1193/// The columns a kept `CHECK` reads, by the last part of each name.
1194fn columns_in(text: &str) -> Result<Vec<String>> {
1195    let (ast, _) = check_ast(text)?;
1196    let mut out = Vec::new();
1197    for expr in &ast.exprs {
1198        if let ast::Expr::Column { name } = *expr {
1199            if let Some(last) = ast.name(name).last() {
1200                out.push(last.to_string());
1201            }
1202        }
1203    }
1204    Ok(out)
1205}
1206
1207/// A kept `CHECK` with every column named `old` renamed to `to`, which is what the pin does to one
1208/// over a column that `RENAME COLUMN` renames.
1209fn rename_in(text: &str, old: &str, to: &str) -> Result<String> {
1210    let (mut ast, expr) = check_ast(text)?;
1211    let mut renamed = false;
1212    for at in 0..ast.exprs.len() {
1213        let ast::Expr::Column { name } = ast.exprs[at] else { continue };
1214        if name.len == 0 {
1215            continue;
1216        }
1217        let last = (name.start + name.len - 1) as usize;
1218        if same_name(ast.string(ast.parts[last]), old) {
1219            let index = ast.strings.len() as u32;
1220            ast.strings.push(to.to_string());
1221            ast.parts[last] = index;
1222            renamed = true;
1223        }
1224    }
1225    Ok(if renamed { deparse::expression(&ast, expr) } else { text.to_string() })
1226}
1227
1228/// Renames the columns a query repeated, which is what makes `CREATE TABLE t AS SELECT 1 AS a, 2 AS
1229/// a` a table rather than an error.
1230///
1231/// A query is allowed to produce two columns of one name and `SELECT 1 AS a, 2 AS a` prints two
1232/// columns called `a`, so a statement that turns a query into a table has to decide what to do with
1233/// that, and DuckDB renames rather than refusing. The suffix is `_1`, then `_2`, counting up until
1234/// the name is free, so a query that already has an `a_1` in it pushes the renamed column to `a_2`
1235/// rather than colliding with it.
1236///
1237/// This only runs when the statement wrote no column list. With a list, even a short one, duckdb
1238/// v1.4.1 takes the names as they come and a repeat is an error, so `CREATE TABLE t (z) AS SELECT 1
1239/// AS a, 2 AS a` is a table of `z` and `a` and adding a third `a` to that query is a refusal.
1240fn deduplicate(columns: &mut [Field]) {
1241    for at in 0..columns.len() {
1242        let taken = |name: &str, upto: usize, columns: &[Field]| {
1243            columns[..upto].iter().any(|held| same_name(&held.name, name))
1244        };
1245        if !taken(&columns[at].name, at, columns) {
1246            continue;
1247        }
1248        let mut suffix = 1;
1249        let mut candidate = format!("{}_{suffix}", columns[at].name);
1250        while taken(&candidate, at, columns) {
1251            suffix += 1;
1252            candidate = format!("{}_{suffix}", columns[at].name);
1253        }
1254        columns[at].name = candidate;
1255    }
1256}
1257
1258/// Binds a `CREATE VIEW`, which means binding the body and then throwing the plan away.
1259///
1260/// Throwing it away is the point. The body is bound here so that a view over a table that is not
1261/// there is refused now rather than at the first select, and so that the column list can be checked
1262/// against what the body actually produces. What the catalog keeps is the text, because a view
1263/// follows the tables underneath it and a plan is a photograph of the day it was built.
1264fn create_view(
1265    ast: &Ast,
1266    catalog: &Catalog,
1267    parameters: &Parameters,
1268    session: &Session,
1269    index: ast::CreateViewRef,
1270) -> Result<Bound> {
1271    let written = ast.create_view(index);
1272    let parts: Vec<&str> = ast.name(written.name).collect();
1273    let name = if written.temporary {
1274        catalog.resolve_for_create_temporary(&parts)?
1275    } else {
1276        catalog.resolve_for_create(&parts)?
1277    };
1278    let aliases: Vec<String> = ast.name(written.columns).map(str::to_string).collect();
1279
1280    let mut binder = Binder::with(catalog, parameters, session);
1281    // The plan is thrown away and the columns are all that is kept, so a file is read for its
1282    // columns and nothing else.
1283    binder.outlined = true;
1284    let (_, mut scope) = binder.bind_query(ast, written.query)?;
1285    if aliases.len() > scope.len() {
1286        return Err(Error::binder("More VIEW aliases than columns in query result"));
1287    }
1288    if !aliases.is_empty() {
1289        let written: Vec<&str> = aliases.iter().map(String::as_str).collect();
1290        scope.rename(&written, "unnamed_subquery")?;
1291    }
1292
1293    Ok(Bound::CreateView(CreateView {
1294        name,
1295        sql: ast.string(written.sql).to_string(),
1296        statement: deparse::create_view(ast, index),
1297        aliases,
1298        if_not_exists: written.if_not_exists,
1299        or_replace: written.or_replace,
1300        columns: scope.fields(),
1301    }))
1302}
1303
1304fn drop_table(ast: &Ast, catalog: &Catalog, index: ast::DropTableRef) -> Result<Bound> {
1305    let written = ast.drop_table(index);
1306    let kind = if written.view { Entry::View } else { Entry::Table };
1307    let mut names = Vec::new();
1308    for &name in ast.name_list(written.names) {
1309        let parts: Vec<&str> = ast.name(name).collect();
1310        // The statement said which of the two it meant, so a name that is not there is a missing
1311        // one of those and not a missing table.
1312        match catalog.resolve_as(&parts, kind) {
1313            Ok(resolved) => names.push(resolved),
1314            Err(error) if written.if_exists => drop(error),
1315            Err(error) => return Err(error),
1316        }
1317    }
1318    Ok(Bound::DropTable(DropTable { names, kind }))
1319}
1320
1321/// Binds a `SET` or a `RESET`, which is resolving its value and nothing else.
1322///
1323/// The name is not checked here. The binder knows what tables exist and has no idea what settings
1324/// exist, since a setting is a knob on the engine rather than an entry in a catalog, and a version
1325/// of this that held the list would be the binder holding a copy of something it cannot enforce.
1326fn setting(
1327    ast: &Ast,
1328    catalog: &Catalog,
1329    parameters: &Parameters,
1330    session: &Session,
1331    index: ast::SettingRef,
1332) -> Result<Bound> {
1333    let written = ast.setting(index);
1334    let name = ast.string(written.name).to_string();
1335    let value = if written.value == NONE {
1336        None
1337    } else {
1338        let mut binder = Binder::with(catalog, parameters, session);
1339        let bound = binder.bind_setting_value(ast, written.value)?;
1340        let Expr::Constant(value) = *binder.plan().expr(bound) else {
1341            return Err(Error::not_implemented(format!(
1342                "a value for {name} that is not a constant"
1343            )));
1344        };
1345        Some(binder.plan().value(value).clone())
1346    };
1347    Ok(Bound::Setting(Setting { name, scope: written.scope, value, pragma: written.pragma }))
1348}
1349
1350/// Sorts an insert's rows into the order the target table declared.
1351///
1352/// Returns the input unchanged when the statement supplies none of the declared columns, because
1353/// every one of them is then a constant null and sorting on a constant is a sort that buys nothing
1354/// and costs a pass. A statement that supplies some of them sorts on those: the declaration is
1355/// about the order the rows are written in, and the columns that are there still order them.
1356///
1357/// The leading key carries the width. `date_trunc('month', d)` and `d` sort the same rows into the
1358/// same fragments for any predicate a month wide or wider, and the difference is what happens
1359/// inside a month: bucketed, the second key orders the whole month, which is the key locality the
1360/// joins want and the reason the width is part of the declaration at all.
1361fn clustered(
1362    binder: &mut Binder<'_>,
1363    input: rudb_plan::NodeRef,
1364    scope: &crate::scope::Scope,
1365    clustering: &Clustering,
1366    targets: &[usize],
1367    fields: &[Field],
1368) -> Result<rudb_plan::NodeRef> {
1369    let mut keys: Vec<SortKey> = Vec::with_capacity(clustering.columns().len());
1370    for (at, &column) in clustering.columns().iter().enumerate() {
1371        let Some(from) = targets.iter().position(|&target| target == column as usize) else {
1372            continue;
1373        };
1374        let source = &scope.columns[from];
1375        let expr = binder.plan_mut().add_expr(Expr::Column(source.binding), source.ty.clone());
1376        // Cast to the column's own type before bucketing, since the source of a load is a file
1377        // whose date column can arrive as a timestamp and `date_trunc` gives back the type it was
1378        // handed. Sorting on a different type than the column stores would still be an order, but
1379        // it would not be the order the declaration names.
1380        let expr = binder.checked_cast_to(expr, &fields[column as usize].ty, false)?;
1381        let expr =
1382            if at == 0 { bucketed(binder, expr, clustering.width(), fields, column) } else { expr };
1383        keys.push(SortKey { expr, descending: false, nulls_first: false });
1384    }
1385    if keys.is_empty() {
1386        return Ok(input);
1387    }
1388    let keys = binder.plan_mut().add_sort_keys(&keys);
1389    Ok(binder.plan_mut().add_node(Node::Sort { input, keys }))
1390}
1391
1392/// The declaration with an automatic width turned into the bucket the incoming rows ask for.
1393///
1394/// A declaration that named no width says the bucket should come from how many rows a partition
1395/// would hold, and this is the only place that number is in reach. The rows are the source's, not
1396/// the target's: a load into an empty table has a target with nothing to count, and the whole case
1397/// the rule exists for is the first load of a big table. So the count and the range come off the
1398/// source's own zones, which is the Parquet footer for a file and the directory for a table, and
1399/// both are already on the plan because the estimator wanted them.
1400///
1401/// Everything about this is best effort and that is by design. The three widths hold the same rows
1402/// and answer the same queries, so guessing wrong costs some pruning or some key locality and
1403/// cannot cost an answer. A source that is a join, a group by or a values list has no zones to read
1404/// and gets [`Width::DEFAULT`], which is what the fixed default was before the rule existed.
1405fn fitted(
1406    binder: &Binder<'_>,
1407    scope: &crate::scope::Scope,
1408    clustering: &Clustering,
1409    targets: &[usize],
1410) -> Clustering {
1411    if clustering.width() != Width::Auto {
1412        return clustering.clone();
1413    }
1414    let Some(from) = targets.iter().position(|&target| target == clustering.partition() as usize)
1415    else {
1416        return clustering.fitted(0, 0);
1417    };
1418    let source = &scope.columns[from];
1419    let Some(zones) = binder.plan().sole_zones() else {
1420        return clustering.fitted(0, 0);
1421    };
1422    // By name, and off whichever store the plan reads rather than off the one this column is bound
1423    // to. The binding points at the projection over the scan, since a load is a projection into the
1424    // target's types, and following a binding back through a projection is the optimizer's job. A
1425    // load reads one table or one file, so the store with bounds on it is the store the name is in.
1426    let Some(at) = zones.column(&source.name) else {
1427        return clustering.fitted(0, 0);
1428    };
1429    let rows = zones.surviving(&[]).unwrap_or(0);
1430    let days = span(&zones.extreme(at, End::Low), &zones.extreme(at, End::High)).unwrap_or(0);
1431    clustering.fitted(rows, days)
1432}
1433
1434/// How many days a column covers, from the smallest and largest values in it.
1435///
1436/// `None` wherever the two do not make a span, which is a column that is entirely null, a store
1437/// that could not fold its parts into one answer, and a pair of bounds that are not the same shape.
1438/// All of them mean the same thing here, which is that there is nothing to divide the row count by.
1439fn span(low: &Stat<ColumnBound>, high: &Stat<ColumnBound>) -> Option<u64> {
1440    let (Stat::Known { value: low, .. }, Stat::Known { value: high, .. }) = (low, high) else {
1441        return None;
1442    };
1443    let days = match (low, high) {
1444        // A date is a day count already, which is the common case and the only exact one.
1445        (ColumnBound::Int(low), ColumnBound::Int(high)) => high.checked_sub(*low)?,
1446        // A timestamp is a count of seconds at whichever unit the column keeps, so the span is that
1447        // difference divided by a day's worth of them. A scale wide enough to overflow the divisor
1448        // is a column no calendar covers and falls out as no span at all.
1449        (
1450            ColumnBound::Scaled { unscaled: low, scale: at },
1451            ColumnBound::Scaled { unscaled: high, scale: to },
1452        ) if at == to => {
1453            let day = 86_400_i128.checked_mul(10_i128.checked_pow(u32::from(*at))?)?;
1454            high.checked_sub(*low)? / day
1455        }
1456        _ => return None,
1457    };
1458    u64::try_from(days).ok()
1459}
1460
1461/// Wraps a sort key in the calendar bucket its declaration asked for.
1462fn bucketed(
1463    binder: &mut Binder<'_>,
1464    expr: ExprRef,
1465    width: Width,
1466    fields: &[Field],
1467    column: u32,
1468) -> ExprRef {
1469    if width == Width::Exact {
1470        return expr;
1471    }
1472    let unit = binder.plan_mut().add_value(Value::Varchar(width.to_string().to_lowercase()));
1473    let unit = binder.plan_mut().add_expr(Expr::Constant(unit), LogicalType::Varchar);
1474    let args = binder.plan_mut().add_expr_list(&[unit, expr]);
1475    let name = binder.plan_mut().intern("date_trunc");
1476    let ty = fields[column as usize].ty.clone();
1477    binder.plan_mut().add_expr(Expr::Function { name, args }, ty)
1478}
1479
1480fn insert(
1481    ast: &Ast,
1482    catalog: &Catalog,
1483    parameters: &Parameters,
1484    session: &Session,
1485    index: ast::InsertRef,
1486) -> Result<Bound> {
1487    let written = ast.insert(index);
1488    let parts: Vec<&str> = ast.name(written.name).collect();
1489    let name = catalog.resolve(&parts)?;
1490    if catalog.entry(&name)? == Entry::View {
1491        // The binary's sentence, article and all. A view has no rows of its own to append to, and
1492        // an updatable view is a rule about rewriting the insert that neither database has.
1493        return Err(Error::catalog(format!("{} is not an table", name.table)));
1494    }
1495    let target = catalog.table(&name)?;
1496    let fields: Vec<Field> = target.columns().to_vec();
1497    let clustering = target.clustering().cloned();
1498
1499    // Which table column each source column lands in. Without a column list that is the first n
1500    // columns in order, and with one it is whatever the list says, which is also the check that
1501    // the list names columns the table has and names none of them twice.
1502    let targets: Vec<usize> = if written.columns.is_empty() {
1503        (0..fields.len()).collect()
1504    } else {
1505        let mut targets = Vec::new();
1506        for column in ast.name(written.columns) {
1507            let at = fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(
1508                || {
1509                    Error::binder(format!(
1510                        "Table \"{}\" does not have a column named \"{column}\"",
1511                        name.table
1512                    ))
1513                },
1514            )?;
1515            if targets.contains(&at) {
1516                return Err(Error::binder(format!(
1517                    "Column \"{column}\" is named twice in the same INSERT"
1518                )));
1519            }
1520            targets.push(at);
1521        }
1522        targets
1523    };
1524
1525    let defaults: Vec<(LogicalType, Option<String>)> = (0..fields.len())
1526        .map(|at| (fields[at].ty.clone(), target.default(at).map(str::to_owned)))
1527        .collect();
1528    let mut binder = Binder::with(catalog, parameters, session);
1529    let (root, scope) = if written.source == NONE {
1530        // `DEFAULT VALUES` is one row with nothing in it, and the projection below fills every
1531        // column with its default.
1532        (binder.plan_mut().add_node(Node::Dummy), crate::scope::Scope::empty())
1533    } else {
1534        // A `DEFAULT` item of a `VALUES` row is the default of the column it lands in, which only
1535        // this statement knows, so the `VALUES` right under it is told.
1536        if matches!(ast.query(written.source).body, ast::QueryBody::Values(_)) {
1537            binder.insert_defaults = Some(targets.iter().map(|&at| defaults[at].clone()).collect());
1538        }
1539        binder.bind_query(ast, written.source)?
1540    };
1541    let targets = if written.source == NONE { Vec::new() } else { targets };
1542    if scope.len() != targets.len() {
1543        return Err(Error::binder(format!(
1544            "Table \"{}\" has {} columns but {} values were supplied",
1545            name.table,
1546            targets.len(),
1547            scope.len()
1548        )));
1549    }
1550
1551    // A table that declared what order its rows go in gets the sort here, under the projection
1552    // rather than over it, because a projection does not reorder rows and the bindings the sort
1553    // keys need are the ones the query just produced. This is the whole of the loader honouring
1554    // the declaration: the rows arrive at the writer in order and the per fragment ranges, which
1555    // are built from whatever order arrives, come out narrow instead of each covering the table.
1556    let root = match &clustering {
1557        None => root,
1558        Some(clustering) => {
1559            // The width is settled here and not on the table. A declaration that left the bucket to
1560            // the data is a standing instruction, so it stays on the table as one and every load
1561            // answers it with the rows that load is carrying. What the sort needs is an answer, and
1562            // that is what this is.
1563            let fitted = fitted(&binder, &scope, clustering, &targets);
1564            clustered(&mut binder, root, &scope, &fitted, &targets, &fields)?
1565        }
1566    };
1567
1568    // The projection that makes the source look exactly like the table. Every column the statement
1569    // did not name becomes a null of the column's own type, so the append never has to know that a
1570    // column list was written at all.
1571    let mut exprs: Vec<ExprRef> = Vec::with_capacity(fields.len());
1572    let mut names = Vec::with_capacity(fields.len());
1573    for (at, field) in fields.iter().enumerate() {
1574        let expr = match targets.iter().position(|&target| target == at) {
1575            Some(from) => {
1576                let column = &scope.columns[from];
1577                let expr =
1578                    binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1579                binder.checked_cast_to(expr, &field.ty, false)?
1580            }
1581            // The column's default, or a null of the column's own type when it has none.
1582            None => binder.bind_default(defaults[at].1.as_deref(), &field.ty)?,
1583        };
1584        exprs.push(expr);
1585        let interned = binder.plan_mut().intern(&field.name);
1586        names.push(interned);
1587    }
1588    let exprs = binder.plan_mut().add_expr_list(&exprs);
1589    let names = binder.plan_mut().add_name_list(&names);
1590    let index = binder.fresh_index();
1591    let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1592    let source = finish(binder, root)?;
1593    let returning = returning(ast, catalog, parameters, session, written.returning)?;
1594    let conflict = match written.conflict {
1595        Some(conflict) => {
1596            Some(bind_conflict(ast, catalog, parameters, session, &name, &targets, conflict)?)
1597        }
1598        None => None,
1599    };
1600    let checks = bind_checks(catalog, parameters, session, &name)?;
1601    Ok(Bound::Insert(Insert { name, source, write: Write::Append, returning, conflict, checks }))
1602}
1603
1604/// Which key an `ON CONFLICT` is about and what it does, refused the way the pin refuses one that
1605/// names no key or leaves which key open when that matters.
1606fn bind_conflict(
1607    ast: &Ast,
1608    catalog: &Catalog,
1609    parameters: &Parameters,
1610    session: &Session,
1611    name: &QualifiedName,
1612    targets: &[usize],
1613    conflict: ast::Conflict,
1614) -> Result<Conflict> {
1615    let table = catalog.table(name)?;
1616    let fields = table.columns();
1617    let keys = table.keys();
1618    let key = if conflict.target.is_empty() {
1619        if keys.is_empty() {
1620            return Err(Error::binder(
1621                "There are no UNIQUE/PRIMARY KEY constraints that refer to this table, specify ON \
1622                 CONFLICT columns manually",
1623            ));
1624        }
1625        match conflict.action {
1626            ast::ConflictAction::Nothing => None,
1627            _ if keys.len() > 1 => {
1628                return Err(Error::binder(
1629                    "Conflict target has to be provided for a DO UPDATE operation when the table \
1630                     has multiple UNIQUE/PRIMARY KEY constraints",
1631                ));
1632            }
1633            _ => Some(0),
1634        }
1635    } else {
1636        let mut wanted = Vec::new();
1637        for column in ast.name(conflict.target) {
1638            let Some(at) = fields.iter().position(|field| same_name(&field.name, column)) else {
1639                return Err(Error::binder(format!(
1640                    "Table \"{}\" does not have a column with name \"{column}\"",
1641                    name.table
1642                )));
1643            };
1644            wanted.push(at);
1645        }
1646        wanted.sort_unstable();
1647        wanted.dedup();
1648        let found = keys.iter().position(|key| {
1649            let mut held = key.columns.clone();
1650            held.sort_unstable();
1651            held == wanted
1652        });
1653        let Some(found) = found else {
1654            return Err(Error::binder(
1655                "The specified columns as conflict target are not referenced by a UNIQUE/PRIMARY \
1656                 KEY CONSTRAINT or INDEX",
1657            ));
1658        };
1659        Some(found)
1660    };
1661    let action = match conflict.action {
1662        ast::ConflictAction::Nothing => ConflictAction::Nothing,
1663        ast::ConflictAction::Replace => ConflictAction::Replace(targets.to_vec()),
1664        ast::ConflictAction::Update { columns: written, query } => {
1665            let mut columns = Vec::new();
1666            for column in ast.name(written) {
1667                let Some(at) = fields.iter().position(|field| same_name(&field.name, column))
1668                else {
1669                    return Err(Error::binder(format!(
1670                        "Referenced update column {column} not found in table!"
1671                    )));
1672                };
1673                if columns.contains(&at) {
1674                    return Err(Error::binder(format!(
1675                        "Multiple assignments to same column \"\"{column}\"\""
1676                    )));
1677                }
1678                columns.push(at);
1679            }
1680            let mut binder = Binder::with(catalog, parameters, session);
1681            binder.upsert = true;
1682            let (root, scope) = binder.bind_query(ast, query)?;
1683            // Each value is cast to its column's type here, so the write only has to place it,
1684            // and the condition is cast to a boolean, so the write only has to test it.
1685            let mut exprs = Vec::with_capacity(scope.columns.len());
1686            let mut names = Vec::with_capacity(scope.columns.len());
1687            for (at, column) in scope.columns.iter().enumerate() {
1688                let expr =
1689                    binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1690                let ty = columns.get(at).map_or(LogicalType::Boolean, |&to| fields[to].ty.clone());
1691                exprs.push(binder.checked_cast_to(expr, &ty, false)?);
1692                names.push(binder.plan_mut().intern(&column.name));
1693            }
1694            let exprs = binder.plan_mut().add_expr_list(&exprs);
1695            let names = binder.plan_mut().add_name_list(&names);
1696            let index = binder.fresh_index();
1697            let root =
1698                binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1699            ConflictAction::Update { columns, plan: Box::new(finish(binder, root)?) }
1700        }
1701    };
1702    Ok(Conflict { key, action })
1703}
1704
1705/// An `UPDATE` or a `DELETE`, bound to the query that produces every row the table has afterwards.
1706///
1707/// The source the transform built is `SELECT *, condition, values... FROM table`. A row the
1708/// condition holds for gets the new values in the named columns for an `UPDATE`, and every other
1709/// row comes through as it was. A null condition is a row that did not match, which is what a
1710/// searched `CASE` does with one, so the one expression covers both. After the table's columns
1711/// comes the flag saying which rows matched, which are the rows an `UPDATE` changed and the rows a
1712/// `DELETE` takes out.
1713fn change(
1714    ast: &Ast,
1715    catalog: &Catalog,
1716    parameters: &Parameters,
1717    session: &Session,
1718    index: ast::InsertRef,
1719    delete: bool,
1720) -> Result<Bound> {
1721    let written = ast.insert(index);
1722    let parts: Vec<&str> = ast.name(written.name).collect();
1723    let name = catalog.resolve(&parts)?;
1724    if catalog.entry(&name)? == Entry::View {
1725        return Err(Error::binder(if delete {
1726            "Can only delete from base table"
1727        } else {
1728            "Can only update base table"
1729        }));
1730    }
1731    let fields: Vec<Field> = catalog.table(&name)?.columns().to_vec();
1732    let mut targets: Vec<usize> = Vec::new();
1733    for column in ast.name(written.columns) {
1734        let at =
1735            fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(|| {
1736                Error::binder(format!("Referenced update column {column} not found in table!"))
1737            })?;
1738        if targets.contains(&at) {
1739            return Err(Error::binder(format!(
1740                "Multiple assignments to same column \"\"{column}\"\""
1741            )));
1742        }
1743        targets.push(at);
1744    }
1745
1746    // Which assignments are `SET c = DEFAULT`, which are the last items of the source's list.
1747    let mut defaulted = vec![false; targets.len()];
1748    if let ast::QueryBody::Select(select) = ast.query(written.source).body {
1749        let items = ast.target_list(ast.select(select).targets);
1750        let first = items.len().saturating_sub(targets.len());
1751        for (at, item) in items[first..].iter().enumerate() {
1752            defaulted[at] = matches!(ast.expr(item.expr), ast::Expr::Default);
1753        }
1754    }
1755    let table = catalog.table(&name)?;
1756    let mut binder = Binder::with(catalog, parameters, session);
1757    binder.default_as_null = defaulted.contains(&true);
1758    let (root, scope) = binder.bind_query(ast, written.source)?;
1759    binder.default_as_null = false;
1760    let width = fields.len();
1761    if scope.len() != width + 1 + targets.len() {
1762        return Err(Error::internal(format!(
1763            "an UPDATE source of {} columns over a table of {width}",
1764            scope.len()
1765        )));
1766    }
1767    let column = |binder: &mut Binder<'_>, at: usize| {
1768        let column = &scope.columns[at];
1769        binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone())
1770    };
1771    let hit = column(&mut binder, width);
1772    let hit = binder.checked_cast_to(hit, &LogicalType::Boolean, false)?;
1773    let mut exprs = Vec::with_capacity(width);
1774    let mut names = Vec::with_capacity(width);
1775    for (at, field) in fields.iter().enumerate() {
1776        let old = column(&mut binder, at);
1777        let expr = match targets.iter().position(|&target| target == at) {
1778            Some(from) => {
1779                let then = if defaulted[from] {
1780                    binder.bind_default(table.default(at), &field.ty)?
1781                } else {
1782                    let new = column(&mut binder, width + 1 + from);
1783                    binder.checked_cast_to(new, &field.ty, false)?
1784                };
1785                let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then }]);
1786                binder
1787                    .plan_mut()
1788                    .add_expr(Expr::Case { arms, otherwise: Some(old) }, field.ty.clone())
1789            }
1790            None => old,
1791        };
1792        exprs.push(expr);
1793        let interned = binder.plan_mut().intern(&field.name);
1794        names.push(interned);
1795    }
1796    // The flag is true only where the condition is, so a row whose condition is null is left
1797    // alone the way a `WHERE` leaves it out.
1798    let yes = binder.add_constant(Value::Boolean(true));
1799    let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then: yes }]);
1800    let otherwise = Some(binder.add_constant(Value::Boolean(false)));
1801    exprs.push(binder.plan_mut().add_expr(Expr::Case { arms, otherwise }, LogicalType::Boolean));
1802    let interned = binder.plan_mut().intern("changed");
1803    names.push(interned);
1804    let exprs = binder.plan_mut().add_expr_list(&exprs);
1805    let names = binder.plan_mut().add_name_list(&names);
1806    let index = binder.fresh_index();
1807    let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1808    let source = finish(binder, root)?;
1809    let returning = returning(ast, catalog, parameters, session, written.returning)?;
1810    let write = if delete { Write::Delete } else { Write::Update };
1811    let checks = if delete { None } else { bind_checks(catalog, parameters, session, &name)? };
1812    Ok(Bound::Insert(Insert { name, source, write, returning, conflict: None, checks }))
1813}