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