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