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