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    /// `INSERT INTO`.
45    Insert(Insert),
46    /// `SET name = value`, or `RESET name`, which is the same thing with no value.
47    Setting(Setting),
48    /// Flushes a persistent database snapshot.
49    Checkpoint,
50    /// `BEGIN`, `COMMIT` or `ROLLBACK`, which have nothing to bind and are carried as written.
51    Transaction(ast::Transaction),
52    /// `EXPLAIN` over a query, holding the plan of the query rather than the query.
53    ///
54    /// The same `Plan` a [`Bound::Query`] would have carried, bound the same way and by the same
55    /// code. What makes it an explain is that the layer above optimizes it and prints it instead
56    /// of running it, which is the point: a plan that was built differently because somebody asked
57    /// to see it is not the plan that runs.
58    ///
59    /// With `analyze` set the layer above runs it as well and prints what happened on it. Still the
60    /// same plan, for the same reason.
61    ///
62    /// With `statistics` set it prints what the planner knew as well, which is the use and the class
63    /// behind every number in the plan. That one changes nothing about the plan or the run either.
64    Explain { plan: Plan, analyze: bool, statistics: bool },
65}
66
67/// A bound `SET` or `RESET`.
68///
69/// The value is a [`Value`] rather than an expression, because every setting there is takes a
70/// string or a number and nothing that runs one wants a plan. What a setting does with the value it
71/// gets is the setting's own business and is decided a layer up, since the binder has no idea what
72/// settings exist.
73///
74/// The narrow part of that is that the value has to already be a constant. `SET threads = 2 + 2` is
75/// four in DuckDB and is refused here, because folding it needs the expression rewriter and the
76/// rewriter is two layers above the binder. Nothing writes arithmetic in a `SET` and the refusal
77/// says what it is, so this waits for a reason to move.
78#[derive(Debug)]
79pub struct Setting {
80    /// The setting name, as written.
81    pub name: String,
82    /// The scope word, if one was written.
83    pub scope: ast::Scope,
84    /// The value, or `None` for a `RESET`.
85    pub value: Option<Value>,
86    /// Whether the statement was written as a bare `PRAGMA name`, which carries its value in it.
87    pub pragma: bool,
88}
89
90/// A bound `CREATE TABLE`.
91#[derive(Debug)]
92pub struct CreateTable {
93    /// The full name the table gets.
94    pub name: QualifiedName,
95    /// The columns, in order, with the types already resolved. For a `CREATE TABLE AS` these are
96    /// the query's output types under whatever names the statement or the query gave them.
97    pub columns: Vec<Field>,
98    /// The query to fill it from, for a `CREATE TABLE AS`.
99    pub source: Option<Plan>,
100    /// Whether an existing table of that name is left alone rather than being an error.
101    pub if_not_exists: bool,
102    /// Whether an existing table of that name is dropped first.
103    pub or_replace: bool,
104    /// The primary key and the unique constraints, over the columns by place.
105    pub keys: Vec<rudb_catalog::Key>,
106    /// Each column's `DEFAULT` as the SQL of its expression, or `None` for a column with none.
107    pub defaults: Vec<Option<String>>,
108    /// The SQL of each `CHECK`, in the order written.
109    pub checks: Vec<String>,
110    /// The foreign keys, in the order written.
111    pub foreign: Vec<rudb_catalog::ForeignKey>,
112}
113
114/// A bound `CREATE VIEW`.
115///
116/// The body is the text that was written rather than the plan it bound to. It was bound once on the
117/// way through here, which is what refuses a view over a table that is not there, and the plan that
118/// came out of that is then thrown away, because a view follows the tables underneath it and a plan
119/// cannot. See [`rudb_catalog::View`].
120#[derive(Debug)]
121pub struct CreateView {
122    /// The full name the view gets.
123    pub name: QualifiedName,
124    /// The body, as written.
125    pub sql: String,
126    /// The whole statement written back out, which is what `duckdb_views()` reports as `sql`.
127    ///
128    /// Written here because this is the last place the tree is in reach. See
129    /// [`rudb_catalog::View::statement`] for what the column is and why it is not the text.
130    pub statement: String,
131    /// The column names the statement gave, which rename a prefix of what the body produces.
132    pub aliases: Vec<String>,
133    /// Whether an existing entry of that name is left alone rather than being an error.
134    pub if_not_exists: bool,
135    /// Whether an existing entry of that name is dropped first.
136    pub or_replace: bool,
137    /// The columns binding the body produced, after the alias list was applied.
138    ///
139    /// Worked out here because this is where the body is bound, and carried to the catalog because
140    /// that is where `duckdb_columns()` and `duckdb_views()` read it from. See the doc on
141    /// `rudb_catalog::View` for why the catalog keeps a list it will have to refresh later.
142    pub columns: Vec<Field>,
143}
144
145/// A bound `DROP TABLE` or `DROP VIEW`.
146#[derive(Debug)]
147pub struct DropTable {
148    /// The tables or views to drop, already resolved. With `IF EXISTS` a name that does not resolve
149    /// is not in here at all, which is what makes running this a sequence of drops that cannot
150    /// fail for being missing. Dropping one of these as the wrong type still can, because `DROP
151    /// TABLE IF EXISTS v` where `v` is a view is an error in DuckDB and was measured to be one.
152    pub names: Vec<QualifiedName>,
153    /// Which of the two the statement said it was dropping.
154    pub kind: Entry,
155}
156
157/// A bound `INSERT`.
158#[derive(Debug)]
159pub struct Insert {
160    /// The table to append to.
161    pub name: QualifiedName,
162    /// The rows to append. The output is the table's columns, in the table's order, with the
163    /// table's types, so nothing between here and the append has a decision left to make.
164    pub source: Plan,
165    /// Which of the three writes the source is for.
166    pub write: Write,
167    /// The `RETURNING` list, bound as a query over the table and run over the rows the statement
168    /// wrote in place of the table's own.
169    pub returning: Option<Box<Plan>>,
170    /// What an append does with a row whose key the table already holds.
171    pub conflict: Option<Conflict>,
172    /// The table's `CHECK` constraints, for the rows an append or an update writes.
173    pub checks: Option<Checks>,
174}
175
176/// The `CHECK` constraints of a table, bound as one query over it.
177///
178/// The query answers, for each row the table holds, whether each constraint fails on it. The write
179/// runs it with the table standing in for the rows it wrote, so a failed constraint is found before
180/// anything the statement wrote is kept.
181#[derive(Debug)]
182pub struct Checks {
183    /// One boolean column per constraint, true where the row fails it. A null is a pass.
184    pub plan: Box<Plan>,
185    /// The pin's message for each constraint, in the same order as the columns.
186    pub messages: Vec<String>,
187}
188
189/// A bound `ON CONFLICT`, `INSERT OR REPLACE` or `INSERT OR IGNORE`.
190#[derive(Debug)]
191pub struct Conflict {
192    /// Which of the table's keys a clash is on, or `None` for any of them.
193    pub key: Option<usize>,
194    /// What happens to a row that clashes.
195    pub action: ConflictAction,
196}
197
198/// What happens to a row whose key the table already holds.
199#[derive(Debug)]
200pub enum ConflictAction {
201    /// The row is dropped.
202    Nothing,
203    /// The held row takes the new row's values in these columns.
204    Replace(Vec<usize>),
205    /// The held row takes the values the plan works out in these columns. The plan reads the held
206    /// rows as the table and the new rows as [`QualifiedName::excluded`], one of each per row it
207    /// answers, and after a value for each column answers whether the row is updated at all.
208    Update {
209        /// The columns that are set, by place in the table.
210        columns: Vec<usize>,
211        /// The query that works the values out.
212        plan: Box<Plan>,
213    },
214}
215
216/// What an [`Insert`]'s source means for the table.
217#[derive(Debug, Clone, Copy, PartialEq, Eq)]
218pub enum Write {
219    /// The rows are added to the table.
220    Append,
221    /// The rows are the whole table afterwards, and one more column after the table's says which
222    /// of them the statement changed, so it can count them and return them.
223    Update,
224    /// The rows are the table as it was, and the column after the table's says which of them
225    /// the statement deletes. The table keeps the rest.
226    Delete,
227}
228
229/// The `RETURNING` query of a writing statement, bound over the table it writes.
230fn returning(
231    ast: &Ast,
232    catalog: &Catalog,
233    parameters: &Parameters,
234    session: &Session,
235    query: Option<ast::QueryRef>,
236) -> Result<Option<Box<Plan>>> {
237    let Some(query) = query else { return Ok(None) };
238    let mut binder = Binder::with(catalog, parameters, session);
239    let (root, _) = binder.bind_query(ast, query)?;
240    Ok(Some(Box::new(finish(binder, root)?)))
241}
242
243/// Binds one parsed statement against a catalog.
244///
245/// # Errors
246///
247/// If the script does not hold exactly one statement, if a name does not resolve, if a type does
248/// not work out, or if the statement uses something that is not bound yet.
249pub fn bind_statement(ast: &Ast, catalog: &Catalog) -> Result<Bound> {
250    bind_statement_with(ast, catalog, &Parameters::new(), &Session::new())
251}
252
253/// Binds one parsed statement against a catalog, with values for its parameters and its settings.
254///
255/// This is the prepared statement path. The statement is parsed once and bound once per set of
256/// values, so a parameter is a constant by the time the plan exists and everything after the binder
257/// sees an ordinary query. That is why there is no parameter in `rudb_plan::Expr`.
258///
259/// # Errors
260///
261/// Everything [`bind_statement`] reports, plus an error for a parameter that was given no value.
262pub fn bind_statement_with(
263    ast: &Ast,
264    catalog: &Catalog,
265    parameters: &Parameters,
266    session: &Session,
267) -> Result<Bound> {
268    bind_one(ast, catalog, parameters, session, false)
269}
270
271/// Binds one statement the way [`bind_statement_with`] does, except that a query reads a Parquet
272/// file that could go through a native mirror from its columns and row count alone.
273///
274/// For the first bind of a query that will be bound again once its mirrors are in. A query that
275/// comes back with [`rudb_plan::Plan::wanted_mirrors`] empty was bound in full and can run. One that
276/// comes back with any must be bound again with [`bind_statement_with`] before it runs, because the
277/// reads that asked for a mirror were bound without the bounds and the distinct counts the
278/// optimizer would have used.
279///
280/// # Errors
281///
282/// Everything [`bind_statement_with`] reports.
283pub fn bind_statement_outlined(
284    ast: &Ast,
285    catalog: &Catalog,
286    parameters: &Parameters,
287    session: &Session,
288) -> Result<Bound> {
289    bind_one(ast, catalog, parameters, session, true)
290}
291
292fn bind_one(
293    ast: &Ast,
294    catalog: &Catalog,
295    parameters: &Parameters,
296    session: &Session,
297    outlined: bool,
298) -> Result<Bound> {
299    let statement = match ast.statements.as_slice() {
300        [statement] => *statement,
301        [] => return Err(Error::binder("no statement to bind")),
302        _ => return Err(Error::not_implemented("a script of more than one statement")),
303    };
304    match statement {
305        ast::Statement::Query(query) => {
306            let mut binder = Binder::with(catalog, parameters, session);
307            binder.outlined = outlined;
308            let (root, _) = binder.bind_query(ast, query)?;
309            Ok(Bound::Query(finish(binder, root)?))
310        }
311        ast::Statement::CreateTable(index) => {
312            create_table(ast, catalog, parameters, session, index)
313        }
314        ast::Statement::CreateView(index) => create_view(ast, catalog, parameters, session, index),
315        ast::Statement::DropTable(index) => drop_table(ast, catalog, index),
316        ast::Statement::Insert(index) => insert(ast, catalog, parameters, session, index),
317        ast::Statement::Update(index) => change(ast, catalog, parameters, session, index, false),
318        ast::Statement::Delete(index) => change(ast, catalog, parameters, session, index, true),
319        ast::Statement::Set(index) | ast::Statement::Reset(index) => {
320            setting(ast, catalog, parameters, session, index)
321        }
322        ast::Statement::Checkpoint => Ok(Bound::Checkpoint),
323        ast::Statement::Transaction(kind) => Ok(Bound::Transaction(kind)),
324        ast::Statement::Explain { query, analyze, statistics } => {
325            let mut binder = Binder::with(catalog, parameters, session);
326            let (root, _) = binder.bind_query(ast, query)?;
327            Ok(Bound::Explain { plan: finish(binder, root)?, analyze, statistics })
328        }
329    }
330}
331
332/// Parses and binds one statement, which is the whole front end in one call.
333///
334/// # Errors
335///
336/// Anything the parser or the binder reports.
337pub fn bind_statement_sql(sql: &str, catalog: &Catalog) -> Result<Bound> {
338    let ast = parse_ast(sql)?;
339    bind_statement(&ast, catalog)
340}
341
342/// Roots a binder's plan and checks it.
343fn finish(binder: Binder<'_>, root: rudb_plan::NodeRef) -> Result<Plan> {
344    let mut plan = binder.into_plan();
345    plan.set_root(root);
346    plan.validate()?;
347    Ok(plan)
348}
349
350fn create_table(
351    ast: &Ast,
352    catalog: &Catalog,
353    parameters: &Parameters,
354    session: &Session,
355    index: ast::CreateTableRef,
356) -> Result<Bound> {
357    let written = ast.create_table(index);
358    let parts: Vec<&str> = ast.name(written.name).collect();
359    let name = if written.temporary {
360        catalog.resolve_for_create_temporary(&parts)?
361    } else {
362        catalog.resolve_for_create(&parts)?
363    };
364    let defs = ast.column_defs(written.columns);
365    let (mut columns, source) = if written.query == NONE {
366        let mut columns = Vec::with_capacity(defs.len());
367        for def in defs {
368            let text = ast.string(def.ty);
369            if text.is_empty() {
370                return Err(Error::binder(format!(
371                    "Column \"{}\" was declared without a type",
372                    ast.string(def.name)
373                )));
374            }
375            let ty = LogicalType::parse(text)?;
376            let column = ast.string(def.name);
377            columns.push(if def.not_null {
378                Field::required(column, ty)
379            } else {
380                Field::new(column, ty)
381            });
382        }
383        (columns, None)
384    } else {
385        let mut binder = Binder::with(catalog, parameters, session);
386        let (root, scope) = binder.bind_query(ast, written.query)?;
387        if defs.len() > scope.len() {
388            // DuckDB's sentence, typo and all. A column list shorter than the query is fine and
389            // renames a prefix, so only this direction is an error.
390            return Err(Error::binder("Target table has more colum names than query result."));
391        }
392        let mut columns = Vec::with_capacity(scope.columns.len());
393        for (at, column) in scope.columns.iter().enumerate() {
394            let named = match defs.get(at) {
395                Some(def) => ast.string(def.name).to_string(),
396                None => column.name.clone(),
397            };
398            columns.push(Field::new(named, column.ty.clone()));
399        }
400        if defs.is_empty() {
401            deduplicate(&mut columns);
402        }
403        (columns, Some(finish(binder, root)?))
404    };
405    duplicate_check(&columns)?;
406    let mut defaults = Vec::with_capacity(defs.len());
407    for def in defs {
408        defaults.push(if def.default == NONE {
409            None
410        } else {
411            Some(default_text(ast, def.default, catalog, parameters, session)?)
412        });
413    }
414    let mut checks = Vec::new();
415    for &expr in ast.expr_list(written.checks) {
416        checks.push(check_text(ast, expr, &columns, catalog, parameters, session)?);
417    }
418    let mut keys = Vec::new();
419    for (at, &names) in ast.name_list(written.keys).iter().enumerate() {
420        let mut places = Vec::new();
421        for wanted in ast.name(names) {
422            let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted))
423            else {
424                return Err(Error::catalog(format!(
425                    "table \"{}\" does not have a column named \"{wanted}\"",
426                    name.table
427                )));
428            };
429            places.push(place);
430        }
431        let primary = at as u32 == written.primary;
432        if primary {
433            for &place in &places {
434                columns[place].not_null = true;
435            }
436        }
437        keys.push(rudb_catalog::Key { columns: places, primary });
438    }
439    let mut foreign = Vec::new();
440    let lists = ast.name_list(written.foreign).iter();
441    let tables = ast.name_list(written.foreign_tables).iter();
442    let referenced = ast.name_list(written.foreign_referenced).iter();
443    for ((&names, &table), &wanted) in lists.zip(tables).zip(referenced) {
444        let names: Vec<&str> = ast.name(names).collect();
445        let parts: Vec<&str> = ast.name(table).collect();
446        let wanted: Vec<&str> = ast.name(wanted).collect();
447        let key = (names.as_slice(), parts.as_slice(), wanted.as_slice());
448        foreign.push(foreign_key(catalog, &name, (&columns, &keys), key)?);
449    }
450    Ok(Bound::CreateTable(CreateTable {
451        name,
452        columns,
453        source,
454        if_not_exists: written.if_not_exists,
455        or_replace: written.or_replace,
456        keys,
457        defaults,
458        checks,
459        foreign,
460    }))
461}
462
463/// One `FOREIGN KEY` of a table being made, refused the way the pin refuses one that names no key
464/// of the referenced table or pairs columns of different types.
465///
466/// The referenced table is the one being made when the name is its own, and then its columns and
467/// keys are the ones this statement declares.
468fn foreign_key(
469    catalog: &Catalog,
470    made: &QualifiedName,
471    (columns, keys): (&[Field], &[rudb_catalog::Key]),
472    (names, parts, wanted): (&[&str], &[&str], &[&str]),
473) -> Result<rudb_catalog::ForeignKey> {
474    let mut places = Vec::with_capacity(names.len());
475    for &wanted in names {
476        let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted)) else {
477            return Err(Error::binder(format!(
478                "Failed to create foreign key: referencing column \"{wanted}\" does not exist"
479            )));
480        };
481        places.push(place);
482    }
483    let own = parts.last().is_some_and(|last| same_name(last, &made.table))
484        && catalog.resolve(parts).map_or(true, |resolved| resolved == *made);
485    let (table, fields, held): (QualifiedName, Vec<Field>, Vec<rudb_catalog::Key>) = if own {
486        (made.clone(), columns.to_vec(), keys.to_vec())
487    } else {
488        let resolved = catalog.resolve(parts)?;
489        let table = catalog.table(&resolved)?;
490        (resolved, table.columns().to_vec(), table.keys().to_vec())
491    };
492    let referenced = if wanted.is_empty() {
493        let Some(primary) = held.iter().find(|key| key.primary) else {
494            return Err(Error::binder(format!(
495                "Failed to create foreign key: there is no primary key for referenced table \"{}\"",
496                table.table
497            )));
498        };
499        if primary.columns.len() != places.len() {
500            return Err(Error::parser(
501                "The number of referencing and referenced columns for foreign keys must be the same",
502            ));
503        }
504        primary.columns.clone()
505    } else {
506        let mut referenced = Vec::with_capacity(wanted.len());
507        for &column in wanted {
508            let Some(place) = fields.iter().position(|field| same_name(&field.name, column)) else {
509                return Err(Error::binder(format!(
510                    "Failed to create foreign key: referenced table \"{}\" does not have a column \
511                     named \"{column}\"",
512                    table.table
513                )));
514            };
515            referenced.push(place);
516        }
517        let mut sorted = referenced.clone();
518        sorted.sort_unstable();
519        let matched = held.iter().any(|key| {
520            let mut columns = key.columns.clone();
521            columns.sort_unstable();
522            columns == sorted
523        });
524        if !matched && held.is_empty() {
525            return Err(Error::binder(format!(
526                "Failed to create foreign key: there is no primary key or unique constraint for \
527                 referenced table \"{}\"",
528                table.table
529            )));
530        }
531        if !matched {
532            return Err(Error::binder(format!(
533                "Failed to create foreign key: referenced table \"{}\" does not have a primary key \
534                 or unique constraint on the columns {}",
535                table.table,
536                wanted.join(", ")
537            )));
538        }
539        referenced
540    };
541    for (&from, &to) in places.iter().zip(&referenced) {
542        if columns[from].ty != fields[to].ty {
543            return Err(Error::binder(format!(
544                "Failed to create foreign key: incompatible types between column \"{}\" (\"{}\") \
545                 and column \"{}\" (\"{}\")",
546                fields[to].name, fields[to].ty, columns[from].name, columns[from].ty
547            )));
548        }
549    }
550    Ok(rudb_catalog::ForeignKey { columns: places, table, referenced })
551}
552
553/// The SQL a `CHECK` is kept as, refused the way the pin refuses one when the table is made.
554fn check_text(
555    ast: &Ast,
556    expr: ast::ExprRef,
557    columns: &[Field],
558    catalog: &Catalog,
559    parameters: &Parameters,
560    session: &Session,
561) -> Result<String> {
562    if crate::expr::has_aggregate(ast, expr) {
563        return Err(Error::binder("aggregate functions are not allowed in check constraints"));
564    }
565    let mut binder = Binder::with(catalog, parameters, session);
566    let index = binder.fresh_index();
567    let mut scope = crate::scope::Scope::empty();
568    for (at, field) in columns.iter().enumerate() {
569        scope.push(crate::scope::Visible {
570            table: String::new(),
571            name: field.name.clone(),
572            binding: rudb_plan::ColumnBinding::new(index, at as u32),
573            ty: field.ty.clone(),
574            not_null: false,
575            key: None,
576            default: None,
577            qualified: false,
578            also: None,
579        });
580    }
581    match binder.bind_expr(ast, expr, &scope) {
582        Err(error) if error.message().starts_with("Referenced column \"") => {
583            let column = error.message().split('"').nth(1).unwrap_or_default();
584            Err(Error::binder(format!(
585                "Table does not contain column \"{column}\" referenced in check constraint!"
586            )))
587        }
588        Err(error) => Err(error),
589        Ok(_) if !binder.windows.is_empty() => {
590            Err(Error::binder("window functions are not allowed in check constraints"))
591        }
592        Ok(_) => Ok(deparse::expression(ast, expr)),
593    }
594}
595
596/// The `CHECK` constraints of a table as the query a write runs over the rows it wrote, or `None`
597/// for a table with none.
598fn bind_checks(
599    catalog: &Catalog,
600    parameters: &Parameters,
601    session: &Session,
602    name: &QualifiedName,
603) -> Result<Option<Checks>> {
604    let table = catalog.table(name)?;
605    if table.checks().is_empty() {
606        return Ok(None);
607    }
608    let failed: Vec<String> =
609        table.checks().iter().map(|text| format!("NOT CAST(({text}) AS BOOLEAN)")).collect();
610    let ast = parse_ast(&format!("SELECT {}", failed.join(", ")))?;
611    let ast::Statement::Query(query) = ast.statements[0] else {
612        return Err(Error::internal("a check that is not an expression"));
613    };
614    let ast::QueryBody::Select(select) = ast.query(query).body else {
615        return Err(Error::internal("a check that is not an expression"));
616    };
617    let mut binder = Binder::with(catalog, parameters, session);
618    let (root, scope) =
619        binder.bind_catalog_table(&ast, name, name.table.clone(), ast::Slice::default())?;
620    let mut exprs = Vec::with_capacity(failed.len());
621    let mut names = Vec::with_capacity(failed.len());
622    for target in ast.target_list(ast.select(select).targets) {
623        exprs.push(binder.bind_expr(&ast, target.expr, &scope)?);
624        names.push(binder.plan_mut().intern("failed"));
625    }
626    let exprs = binder.plan_mut().add_expr_list(&exprs);
627    let names = binder.plan_mut().add_name_list(&names);
628    let index = binder.fresh_index();
629    let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
630    let messages = table
631        .checks()
632        .iter()
633        .map(|text| {
634            format!(
635                "CHECK constraint failed on table \"{}\" with expression CHECK({text})",
636                name.table
637            )
638        })
639        .collect();
640    Ok(Some(Checks { plan: Box::new(finish(binder, root)?), messages }))
641}
642
643/// The SQL a column's `DEFAULT` is kept as, refused the way the pin refuses one when the table is
644/// made. The expression is bound once here to find out, and bound again by every insert that needs
645/// it, because a default like `random()` is worked out per row.
646fn default_text(
647    ast: &Ast,
648    expr: ast::ExprRef,
649    catalog: &Catalog,
650    parameters: &Parameters,
651    session: &Session,
652) -> Result<String> {
653    if crate::expr::has_aggregate(ast, expr) {
654        return Err(Error::binder("DEFAULT value cannot contain aggregates!"));
655    }
656    let mut binder = Binder::with(catalog, parameters, session);
657    let before = binder.plan_mut().node_count();
658    match binder.bind_expr(ast, expr, &crate::scope::Scope::empty()) {
659        Err(error) if error.message().starts_with("Referenced ") => {
660            Err(Error::binder("DEFAULT value cannot contain column names"))
661        }
662        Err(error) => Err(error),
663        // Nothing but a subquery adds a node to the plan while an expression over no rows binds.
664        Ok(_) if binder.plan_mut().node_count() > before => {
665            Err(Error::binder("DEFAULT value cannot contain subqueries"))
666        }
667        Ok(_) if !binder.windows.is_empty() => {
668            Err(Error::binder("DEFAULT value cannot contain window functions!"))
669        }
670        Ok(_) => Ok(deparse::expression(ast, expr)),
671    }
672}
673
674/// Renames the columns a query repeated, which is what makes `CREATE TABLE t AS SELECT 1 AS a, 2 AS
675/// a` a table rather than an error.
676///
677/// A query is allowed to produce two columns of one name and `SELECT 1 AS a, 2 AS a` prints two
678/// columns called `a`, so a statement that turns a query into a table has to decide what to do with
679/// that, and DuckDB renames rather than refusing. The suffix is `_1`, then `_2`, counting up until
680/// the name is free, so a query that already has an `a_1` in it pushes the renamed column to `a_2`
681/// rather than colliding with it.
682///
683/// This only runs when the statement wrote no column list. With a list, even a short one, duckdb
684/// v1.4.1 takes the names as they come and a repeat is an error, so `CREATE TABLE t (z) AS SELECT 1
685/// AS a, 2 AS a` is a table of `z` and `a` and adding a third `a` to that query is a refusal.
686fn deduplicate(columns: &mut [Field]) {
687    for at in 0..columns.len() {
688        let taken = |name: &str, upto: usize, columns: &[Field]| {
689            columns[..upto].iter().any(|held| same_name(&held.name, name))
690        };
691        if !taken(&columns[at].name, at, columns) {
692            continue;
693        }
694        let mut suffix = 1;
695        let mut candidate = format!("{}_{suffix}", columns[at].name);
696        while taken(&candidate, at, columns) {
697            suffix += 1;
698            candidate = format!("{}_{suffix}", columns[at].name);
699        }
700        columns[at].name = candidate;
701    }
702}
703
704/// Binds a `CREATE VIEW`, which means binding the body and then throwing the plan away.
705///
706/// Throwing it away is the point. The body is bound here so that a view over a table that is not
707/// there is refused now rather than at the first select, and so that the column list can be checked
708/// against what the body actually produces. What the catalog keeps is the text, because a view
709/// follows the tables underneath it and a plan is a photograph of the day it was built.
710fn create_view(
711    ast: &Ast,
712    catalog: &Catalog,
713    parameters: &Parameters,
714    session: &Session,
715    index: ast::CreateViewRef,
716) -> Result<Bound> {
717    let written = ast.create_view(index);
718    let parts: Vec<&str> = ast.name(written.name).collect();
719    let name = if written.temporary {
720        catalog.resolve_for_create_temporary(&parts)?
721    } else {
722        catalog.resolve_for_create(&parts)?
723    };
724    let aliases: Vec<String> = ast.name(written.columns).map(str::to_string).collect();
725
726    let mut binder = Binder::with(catalog, parameters, session);
727    // The plan is thrown away and the columns are all that is kept, so a file is read for its
728    // columns and nothing else.
729    binder.outlined = true;
730    let (_, mut scope) = binder.bind_query(ast, written.query)?;
731    if aliases.len() > scope.len() {
732        return Err(Error::binder("More VIEW aliases than columns in query result"));
733    }
734    if !aliases.is_empty() {
735        let written: Vec<&str> = aliases.iter().map(String::as_str).collect();
736        scope.rename(&written, "unnamed_subquery")?;
737    }
738
739    Ok(Bound::CreateView(CreateView {
740        name,
741        sql: ast.string(written.sql).to_string(),
742        statement: deparse::create_view(ast, index),
743        aliases,
744        if_not_exists: written.if_not_exists,
745        or_replace: written.or_replace,
746        columns: scope.fields(),
747    }))
748}
749
750fn drop_table(ast: &Ast, catalog: &Catalog, index: ast::DropTableRef) -> Result<Bound> {
751    let written = ast.drop_table(index);
752    let kind = if written.view { Entry::View } else { Entry::Table };
753    let mut names = Vec::new();
754    for &name in ast.name_list(written.names) {
755        let parts: Vec<&str> = ast.name(name).collect();
756        // The statement said which of the two it meant, so a name that is not there is a missing
757        // one of those and not a missing table.
758        match catalog.resolve_as(&parts, kind) {
759            Ok(resolved) => names.push(resolved),
760            Err(error) if written.if_exists => drop(error),
761            Err(error) => return Err(error),
762        }
763    }
764    Ok(Bound::DropTable(DropTable { names, kind }))
765}
766
767/// Binds a `SET` or a `RESET`, which is resolving its value and nothing else.
768///
769/// The name is not checked here. The binder knows what tables exist and has no idea what settings
770/// exist, since a setting is a knob on the engine rather than an entry in a catalog, and a version
771/// of this that held the list would be the binder holding a copy of something it cannot enforce.
772fn setting(
773    ast: &Ast,
774    catalog: &Catalog,
775    parameters: &Parameters,
776    session: &Session,
777    index: ast::SettingRef,
778) -> Result<Bound> {
779    let written = ast.setting(index);
780    let name = ast.string(written.name).to_string();
781    let value = if written.value == NONE {
782        None
783    } else {
784        let mut binder = Binder::with(catalog, parameters, session);
785        let bound = binder.bind_setting_value(ast, written.value)?;
786        let Expr::Constant(value) = *binder.plan().expr(bound) else {
787            return Err(Error::not_implemented(format!(
788                "a value for {name} that is not a constant"
789            )));
790        };
791        Some(binder.plan().value(value).clone())
792    };
793    Ok(Bound::Setting(Setting { name, scope: written.scope, value, pragma: written.pragma }))
794}
795
796/// Sorts an insert's rows into the order the target table declared.
797///
798/// Returns the input unchanged when the statement supplies none of the declared columns, because
799/// every one of them is then a constant null and sorting on a constant is a sort that buys nothing
800/// and costs a pass. A statement that supplies some of them sorts on those: the declaration is
801/// about the order the rows are written in, and the columns that are there still order them.
802///
803/// The leading key carries the width. `date_trunc('month', d)` and `d` sort the same rows into the
804/// same fragments for any predicate a month wide or wider, and the difference is what happens
805/// inside a month: bucketed, the second key orders the whole month, which is the key locality the
806/// joins want and the reason the width is part of the declaration at all.
807fn clustered(
808    binder: &mut Binder<'_>,
809    input: rudb_plan::NodeRef,
810    scope: &crate::scope::Scope,
811    clustering: &Clustering,
812    targets: &[usize],
813    fields: &[Field],
814) -> Result<rudb_plan::NodeRef> {
815    let mut keys: Vec<SortKey> = Vec::with_capacity(clustering.columns().len());
816    for (at, &column) in clustering.columns().iter().enumerate() {
817        let Some(from) = targets.iter().position(|&target| target == column as usize) else {
818            continue;
819        };
820        let source = &scope.columns[from];
821        let expr = binder.plan_mut().add_expr(Expr::Column(source.binding), source.ty.clone());
822        // Cast to the column's own type before bucketing, since the source of a load is a file
823        // whose date column can arrive as a timestamp and `date_trunc` gives back the type it was
824        // handed. Sorting on a different type than the column stores would still be an order, but
825        // it would not be the order the declaration names.
826        let expr = binder.checked_cast_to(expr, &fields[column as usize].ty, false)?;
827        let expr =
828            if at == 0 { bucketed(binder, expr, clustering.width(), fields, column) } else { expr };
829        keys.push(SortKey { expr, descending: false, nulls_first: false });
830    }
831    if keys.is_empty() {
832        return Ok(input);
833    }
834    let keys = binder.plan_mut().add_sort_keys(&keys);
835    Ok(binder.plan_mut().add_node(Node::Sort { input, keys }))
836}
837
838/// The declaration with an automatic width turned into the bucket the incoming rows ask for.
839///
840/// A declaration that named no width says the bucket should come from how many rows a partition
841/// would hold, and this is the only place that number is in reach. The rows are the source's, not
842/// the target's: a load into an empty table has a target with nothing to count, and the whole case
843/// the rule exists for is the first load of a big table. So the count and the range come off the
844/// source's own zones, which is the Parquet footer for a file and the directory for a table, and
845/// both are already on the plan because the estimator wanted them.
846///
847/// Everything about this is best effort and that is by design. The three widths hold the same rows
848/// and answer the same queries, so guessing wrong costs some pruning or some key locality and
849/// cannot cost an answer. A source that is a join, a group by or a values list has no zones to read
850/// and gets [`Width::DEFAULT`], which is what the fixed default was before the rule existed.
851fn fitted(
852    binder: &Binder<'_>,
853    scope: &crate::scope::Scope,
854    clustering: &Clustering,
855    targets: &[usize],
856) -> Clustering {
857    if clustering.width() != Width::Auto {
858        return clustering.clone();
859    }
860    let Some(from) = targets.iter().position(|&target| target == clustering.partition() as usize)
861    else {
862        return clustering.fitted(0, 0);
863    };
864    let source = &scope.columns[from];
865    let Some(zones) = binder.plan().sole_zones() else {
866        return clustering.fitted(0, 0);
867    };
868    // By name, and off whichever store the plan reads rather than off the one this column is bound
869    // to. The binding points at the projection over the scan, since a load is a projection into the
870    // target's types, and following a binding back through a projection is the optimizer's job. A
871    // load reads one table or one file, so the store with bounds on it is the store the name is in.
872    let Some(at) = zones.column(&source.name) else {
873        return clustering.fitted(0, 0);
874    };
875    let rows = zones.surviving(&[]).unwrap_or(0);
876    let days = span(&zones.extreme(at, End::Low), &zones.extreme(at, End::High)).unwrap_or(0);
877    clustering.fitted(rows, days)
878}
879
880/// How many days a column covers, from the smallest and largest values in it.
881///
882/// `None` wherever the two do not make a span, which is a column that is entirely null, a store
883/// that could not fold its parts into one answer, and a pair of bounds that are not the same shape.
884/// All of them mean the same thing here, which is that there is nothing to divide the row count by.
885fn span(low: &Stat<ColumnBound>, high: &Stat<ColumnBound>) -> Option<u64> {
886    let (Stat::Known { value: low, .. }, Stat::Known { value: high, .. }) = (low, high) else {
887        return None;
888    };
889    let days = match (low, high) {
890        // A date is a day count already, which is the common case and the only exact one.
891        (ColumnBound::Int(low), ColumnBound::Int(high)) => high.checked_sub(*low)?,
892        // A timestamp is a count of seconds at whichever unit the column keeps, so the span is that
893        // difference divided by a day's worth of them. A scale wide enough to overflow the divisor
894        // is a column no calendar covers and falls out as no span at all.
895        (
896            ColumnBound::Scaled { unscaled: low, scale: at },
897            ColumnBound::Scaled { unscaled: high, scale: to },
898        ) if at == to => {
899            let day = 86_400_i128.checked_mul(10_i128.checked_pow(u32::from(*at))?)?;
900            high.checked_sub(*low)? / day
901        }
902        _ => return None,
903    };
904    u64::try_from(days).ok()
905}
906
907/// Wraps a sort key in the calendar bucket its declaration asked for.
908fn bucketed(
909    binder: &mut Binder<'_>,
910    expr: ExprRef,
911    width: Width,
912    fields: &[Field],
913    column: u32,
914) -> ExprRef {
915    if width == Width::Exact {
916        return expr;
917    }
918    let unit = binder.plan_mut().add_value(Value::Varchar(width.to_string().to_lowercase()));
919    let unit = binder.plan_mut().add_expr(Expr::Constant(unit), LogicalType::Varchar);
920    let args = binder.plan_mut().add_expr_list(&[unit, expr]);
921    let name = binder.plan_mut().intern("date_trunc");
922    let ty = fields[column as usize].ty.clone();
923    binder.plan_mut().add_expr(Expr::Function { name, args }, ty)
924}
925
926fn insert(
927    ast: &Ast,
928    catalog: &Catalog,
929    parameters: &Parameters,
930    session: &Session,
931    index: ast::InsertRef,
932) -> Result<Bound> {
933    let written = ast.insert(index);
934    let parts: Vec<&str> = ast.name(written.name).collect();
935    let name = catalog.resolve(&parts)?;
936    if catalog.entry(&name)? == Entry::View {
937        // The binary's sentence, article and all. A view has no rows of its own to append to, and
938        // an updatable view is a rule about rewriting the insert that neither database has.
939        return Err(Error::catalog(format!("{} is not an table", name.table)));
940    }
941    let target = catalog.table(&name)?;
942    let fields: Vec<Field> = target.columns().to_vec();
943    let clustering = target.clustering().cloned();
944
945    // Which table column each source column lands in. Without a column list that is the first n
946    // columns in order, and with one it is whatever the list says, which is also the check that
947    // the list names columns the table has and names none of them twice.
948    let targets: Vec<usize> = if written.columns.is_empty() {
949        (0..fields.len()).collect()
950    } else {
951        let mut targets = Vec::new();
952        for column in ast.name(written.columns) {
953            let at = fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(
954                || {
955                    Error::binder(format!(
956                        "Table \"{}\" does not have a column named \"{column}\"",
957                        name.table
958                    ))
959                },
960            )?;
961            if targets.contains(&at) {
962                return Err(Error::binder(format!(
963                    "Column \"{column}\" is named twice in the same INSERT"
964                )));
965            }
966            targets.push(at);
967        }
968        targets
969    };
970
971    let defaults: Vec<(LogicalType, Option<String>)> = (0..fields.len())
972        .map(|at| (fields[at].ty.clone(), target.default(at).map(str::to_owned)))
973        .collect();
974    let mut binder = Binder::with(catalog, parameters, session);
975    let (root, scope) = if written.source == NONE {
976        // `DEFAULT VALUES` is one row with nothing in it, and the projection below fills every
977        // column with its default.
978        (binder.plan_mut().add_node(Node::Dummy), crate::scope::Scope::empty())
979    } else {
980        // A `DEFAULT` item of a `VALUES` row is the default of the column it lands in, which only
981        // this statement knows, so the `VALUES` right under it is told.
982        if matches!(ast.query(written.source).body, ast::QueryBody::Values(_)) {
983            binder.insert_defaults = Some(targets.iter().map(|&at| defaults[at].clone()).collect());
984        }
985        binder.bind_query(ast, written.source)?
986    };
987    let targets = if written.source == NONE { Vec::new() } else { targets };
988    if scope.len() != targets.len() {
989        return Err(Error::binder(format!(
990            "Table \"{}\" has {} columns but {} values were supplied",
991            name.table,
992            targets.len(),
993            scope.len()
994        )));
995    }
996
997    // A table that declared what order its rows go in gets the sort here, under the projection
998    // rather than over it, because a projection does not reorder rows and the bindings the sort
999    // keys need are the ones the query just produced. This is the whole of the loader honouring
1000    // the declaration: the rows arrive at the writer in order and the per fragment ranges, which
1001    // are built from whatever order arrives, come out narrow instead of each covering the table.
1002    let root = match &clustering {
1003        None => root,
1004        Some(clustering) => {
1005            // The width is settled here and not on the table. A declaration that left the bucket to
1006            // the data is a standing instruction, so it stays on the table as one and every load
1007            // answers it with the rows that load is carrying. What the sort needs is an answer, and
1008            // that is what this is.
1009            let fitted = fitted(&binder, &scope, clustering, &targets);
1010            clustered(&mut binder, root, &scope, &fitted, &targets, &fields)?
1011        }
1012    };
1013
1014    // The projection that makes the source look exactly like the table. Every column the statement
1015    // did not name becomes a null of the column's own type, so the append never has to know that a
1016    // column list was written at all.
1017    let mut exprs: Vec<ExprRef> = Vec::with_capacity(fields.len());
1018    let mut names = Vec::with_capacity(fields.len());
1019    for (at, field) in fields.iter().enumerate() {
1020        let expr = match targets.iter().position(|&target| target == at) {
1021            Some(from) => {
1022                let column = &scope.columns[from];
1023                let expr =
1024                    binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1025                binder.checked_cast_to(expr, &field.ty, false)?
1026            }
1027            // The column's default, or a null of the column's own type when it has none.
1028            None => binder.bind_default(defaults[at].1.as_deref(), &field.ty)?,
1029        };
1030        exprs.push(expr);
1031        let interned = binder.plan_mut().intern(&field.name);
1032        names.push(interned);
1033    }
1034    let exprs = binder.plan_mut().add_expr_list(&exprs);
1035    let names = binder.plan_mut().add_name_list(&names);
1036    let index = binder.fresh_index();
1037    let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1038    let source = finish(binder, root)?;
1039    let returning = returning(ast, catalog, parameters, session, written.returning)?;
1040    let conflict = match written.conflict {
1041        Some(conflict) => {
1042            Some(bind_conflict(ast, catalog, parameters, session, &name, &targets, conflict)?)
1043        }
1044        None => None,
1045    };
1046    let checks = bind_checks(catalog, parameters, session, &name)?;
1047    Ok(Bound::Insert(Insert { name, source, write: Write::Append, returning, conflict, checks }))
1048}
1049
1050/// Which key an `ON CONFLICT` is about and what it does, refused the way the pin refuses one that
1051/// names no key or leaves which key open when that matters.
1052fn bind_conflict(
1053    ast: &Ast,
1054    catalog: &Catalog,
1055    parameters: &Parameters,
1056    session: &Session,
1057    name: &QualifiedName,
1058    targets: &[usize],
1059    conflict: ast::Conflict,
1060) -> Result<Conflict> {
1061    let table = catalog.table(name)?;
1062    let fields = table.columns();
1063    let keys = table.keys();
1064    let key = if conflict.target.is_empty() {
1065        if keys.is_empty() {
1066            return Err(Error::binder(
1067                "There are no UNIQUE/PRIMARY KEY constraints that refer to this table, specify ON \
1068                 CONFLICT columns manually",
1069            ));
1070        }
1071        match conflict.action {
1072            ast::ConflictAction::Nothing => None,
1073            _ if keys.len() > 1 => {
1074                return Err(Error::binder(
1075                    "Conflict target has to be provided for a DO UPDATE operation when the table \
1076                     has multiple UNIQUE/PRIMARY KEY constraints",
1077                ));
1078            }
1079            _ => Some(0),
1080        }
1081    } else {
1082        let mut wanted = Vec::new();
1083        for column in ast.name(conflict.target) {
1084            let Some(at) = fields.iter().position(|field| same_name(&field.name, column)) else {
1085                return Err(Error::binder(format!(
1086                    "Table \"{}\" does not have a column with name \"{column}\"",
1087                    name.table
1088                )));
1089            };
1090            wanted.push(at);
1091        }
1092        wanted.sort_unstable();
1093        wanted.dedup();
1094        let found = keys.iter().position(|key| {
1095            let mut held = key.columns.clone();
1096            held.sort_unstable();
1097            held == wanted
1098        });
1099        let Some(found) = found else {
1100            return Err(Error::binder(
1101                "The specified columns as conflict target are not referenced by a UNIQUE/PRIMARY \
1102                 KEY CONSTRAINT or INDEX",
1103            ));
1104        };
1105        Some(found)
1106    };
1107    let action = match conflict.action {
1108        ast::ConflictAction::Nothing => ConflictAction::Nothing,
1109        ast::ConflictAction::Replace => ConflictAction::Replace(targets.to_vec()),
1110        ast::ConflictAction::Update { columns: written, query } => {
1111            let mut columns = Vec::new();
1112            for column in ast.name(written) {
1113                let Some(at) = fields.iter().position(|field| same_name(&field.name, column))
1114                else {
1115                    return Err(Error::binder(format!(
1116                        "Referenced update column {column} not found in table!"
1117                    )));
1118                };
1119                if columns.contains(&at) {
1120                    return Err(Error::binder(format!(
1121                        "Multiple assignments to same column \"\"{column}\"\""
1122                    )));
1123                }
1124                columns.push(at);
1125            }
1126            let mut binder = Binder::with(catalog, parameters, session);
1127            binder.upsert = true;
1128            let (root, scope) = binder.bind_query(ast, query)?;
1129            // Each value is cast to its column's type here, so the write only has to place it,
1130            // and the condition is cast to a boolean, so the write only has to test it.
1131            let mut exprs = Vec::with_capacity(scope.columns.len());
1132            let mut names = Vec::with_capacity(scope.columns.len());
1133            for (at, column) in scope.columns.iter().enumerate() {
1134                let expr =
1135                    binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1136                let ty = columns.get(at).map_or(LogicalType::Boolean, |&to| fields[to].ty.clone());
1137                exprs.push(binder.checked_cast_to(expr, &ty, false)?);
1138                names.push(binder.plan_mut().intern(&column.name));
1139            }
1140            let exprs = binder.plan_mut().add_expr_list(&exprs);
1141            let names = binder.plan_mut().add_name_list(&names);
1142            let index = binder.fresh_index();
1143            let root =
1144                binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1145            ConflictAction::Update { columns, plan: Box::new(finish(binder, root)?) }
1146        }
1147    };
1148    Ok(Conflict { key, action })
1149}
1150
1151/// An `UPDATE` or a `DELETE`, bound to the query that produces every row the table has afterwards.
1152///
1153/// The source the transform built is `SELECT *, condition, values... FROM table`. A row the
1154/// condition holds for gets the new values in the named columns for an `UPDATE`, and every other
1155/// row comes through as it was. A null condition is a row that did not match, which is what a
1156/// searched `CASE` does with one, so the one expression covers both. After the table's columns
1157/// comes the flag saying which rows matched, which are the rows an `UPDATE` changed and the rows a
1158/// `DELETE` takes out.
1159fn change(
1160    ast: &Ast,
1161    catalog: &Catalog,
1162    parameters: &Parameters,
1163    session: &Session,
1164    index: ast::InsertRef,
1165    delete: bool,
1166) -> Result<Bound> {
1167    let written = ast.insert(index);
1168    let parts: Vec<&str> = ast.name(written.name).collect();
1169    let name = catalog.resolve(&parts)?;
1170    if catalog.entry(&name)? == Entry::View {
1171        return Err(Error::binder(if delete {
1172            "Can only delete from base table"
1173        } else {
1174            "Can only update base table"
1175        }));
1176    }
1177    let fields: Vec<Field> = catalog.table(&name)?.columns().to_vec();
1178    let mut targets: Vec<usize> = Vec::new();
1179    for column in ast.name(written.columns) {
1180        let at =
1181            fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(|| {
1182                Error::binder(format!("Referenced update column {column} not found in table!"))
1183            })?;
1184        if targets.contains(&at) {
1185            return Err(Error::binder(format!(
1186                "Multiple assignments to same column \"\"{column}\"\""
1187            )));
1188        }
1189        targets.push(at);
1190    }
1191
1192    // Which assignments are `SET c = DEFAULT`, which are the last items of the source's list.
1193    let mut defaulted = vec![false; targets.len()];
1194    if let ast::QueryBody::Select(select) = ast.query(written.source).body {
1195        let items = ast.target_list(ast.select(select).targets);
1196        let first = items.len().saturating_sub(targets.len());
1197        for (at, item) in items[first..].iter().enumerate() {
1198            defaulted[at] = matches!(ast.expr(item.expr), ast::Expr::Default);
1199        }
1200    }
1201    let table = catalog.table(&name)?;
1202    let mut binder = Binder::with(catalog, parameters, session);
1203    binder.default_as_null = defaulted.contains(&true);
1204    let (root, scope) = binder.bind_query(ast, written.source)?;
1205    binder.default_as_null = false;
1206    let width = fields.len();
1207    if scope.len() != width + 1 + targets.len() {
1208        return Err(Error::internal(format!(
1209            "an UPDATE source of {} columns over a table of {width}",
1210            scope.len()
1211        )));
1212    }
1213    let column = |binder: &mut Binder<'_>, at: usize| {
1214        let column = &scope.columns[at];
1215        binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone())
1216    };
1217    let hit = column(&mut binder, width);
1218    let hit = binder.checked_cast_to(hit, &LogicalType::Boolean, false)?;
1219    let mut exprs = Vec::with_capacity(width);
1220    let mut names = Vec::with_capacity(width);
1221    for (at, field) in fields.iter().enumerate() {
1222        let old = column(&mut binder, at);
1223        let expr = match targets.iter().position(|&target| target == at) {
1224            Some(from) => {
1225                let then = if defaulted[from] {
1226                    binder.bind_default(table.default(at), &field.ty)?
1227                } else {
1228                    let new = column(&mut binder, width + 1 + from);
1229                    binder.checked_cast_to(new, &field.ty, false)?
1230                };
1231                let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then }]);
1232                binder
1233                    .plan_mut()
1234                    .add_expr(Expr::Case { arms, otherwise: Some(old) }, field.ty.clone())
1235            }
1236            None => old,
1237        };
1238        exprs.push(expr);
1239        let interned = binder.plan_mut().intern(&field.name);
1240        names.push(interned);
1241    }
1242    // The flag is true only where the condition is, so a row whose condition is null is left
1243    // alone the way a `WHERE` leaves it out.
1244    let yes = binder.add_constant(Value::Boolean(true));
1245    let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then: yes }]);
1246    let otherwise = Some(binder.add_constant(Value::Boolean(false)));
1247    exprs.push(binder.plan_mut().add_expr(Expr::Case { arms, otherwise }, LogicalType::Boolean));
1248    let interned = binder.plan_mut().intern("changed");
1249    names.push(interned);
1250    let exprs = binder.plan_mut().add_expr_list(&exprs);
1251    let names = binder.plan_mut().add_name_list(&names);
1252    let index = binder.fresh_index();
1253    let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1254    let source = finish(binder, root)?;
1255    let returning = returning(ast, catalog, parameters, session, written.returning)?;
1256    let write = if delete { Write::Delete } else { Write::Update };
1257    let checks = if delete { None } else { bind_checks(catalog, parameters, session, &name)? };
1258    Ok(Bound::Insert(Insert { name, source, write, returning, conflict: None, checks }))
1259}