Skip to main content

rudb_bind/
statement.rs

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