Skip to main content

rudb_bind/
binder.rs

1//! From an `Ast` to a `Plan`.
2//!
3//! The binder walks the written query once, in the order the operators end up in rather than the
4//! order the clauses are written in, which is `FROM`, `WHERE`, `GROUP BY`, `HAVING`, `SELECT`,
5//! `DISTINCT`, `ORDER BY`, `LIMIT`. That order is not a stylistic choice: it is the reason `WHERE`
6//! cannot see an output alias and `HAVING` cannot see a column that was not grouped, and doing it
7//! in any other order means special casing both of those instead of getting them for free.
8//!
9//! Two things leave here settled that nothing downstream reconsiders. Every column is a table index
10//! and a position rather than a name, so the optimizer never has to ask which `id` a name meant.
11//! And every expression has a type, with the casts that make the types line up already written into
12//! the plan as [`Expr::Cast`] nodes, so an executor never has to decide what a comparison between
13//! an `INTEGER` and a `BIGINT` does.
14
15use rudb_catalog::{Catalog, Entry, QualifiedName, same_name};
16use rudb_common::{Error, Field, LogicalType, Result, Session, Value};
17use rudb_functions::{
18    Columns, FILE_ROW_NUMBER, Given, TableFunction, csv_fields, csv_given, files, is_file,
19    is_pattern, parquet_fields, resolve, resolve_table,
20};
21use rudb_parse::ast::{self, Ast, Distinct, LiteralKind, Nulls, Order, Quantifier, SetOp};
22use rudb_parse::{NONE, parse_ast};
23use rudb_plan::{ColumnBinding, Expr, ExprRef, JoinKind, Node, NodeRef, Plan, SetOpKind, SortKey};
24
25use crate::expr::{describe, has_aggregate};
26use crate::parameters::Parameters;
27use crate::scope::{Scope, Visible};
28
29/// Binds a parsed statement against a catalog.
30///
31/// # Errors
32///
33/// If the script does not hold exactly one statement, if a name does not resolve, if a type does
34/// not work out, or if the query uses something M0 does not bind yet.
35pub fn bind(ast: &Ast, catalog: &Catalog) -> Result<Plan> {
36    bind_with(ast, catalog, &Parameters::new(), &Session::new())
37}
38
39/// Binds a parsed query against a catalog, with values for its parameters and its settings.
40///
41/// The session is what `current_setting()` reads, and a caller with no database behind it passes an
42/// empty one, which makes every setting name unrecognized rather than making up an answer.
43///
44/// # Errors
45///
46/// Everything [`bind`] reports, plus an error for a parameter that was given no value.
47pub fn bind_with(
48    ast: &Ast,
49    catalog: &Catalog,
50    parameters: &Parameters,
51    session: &Session,
52) -> Result<Plan> {
53    let query = match ast.statements.as_slice() {
54        [ast::Statement::Query(query)] => *query,
55        [] => return Err(Error::binder("no statement to bind")),
56        // One statement that is not a query is its own answer. Reporting it as a script of several
57        // reads as a count being wrong, and the count is right.
58        [_] => return Err(Error::not_implemented("a statement that is not a query")),
59        _ => return Err(Error::not_implemented("a script of more than one statement")),
60    };
61    let mut binder = Binder::with(catalog, parameters, session);
62    let (root, _) = binder.bind_query(ast, query)?;
63    let mut plan = binder.into_plan();
64    plan.set_root(root);
65    plan.validate()?;
66    Ok(plan)
67}
68
69/// Parses and binds one query, which is the whole front end in one call.
70///
71/// # Errors
72///
73/// Anything the parser or the binder reports.
74pub fn bind_sql(query: &str, catalog: &Catalog) -> Result<Plan> {
75    bind_sql_with(query, catalog, &Session::new())
76}
77
78/// Parses and binds one query, with the settings a call to `current_setting()` reads.
79///
80/// # Errors
81///
82/// Anything the parser or the binder reports.
83pub fn bind_sql_with(query: &str, catalog: &Catalog, session: &Session) -> Result<Plan> {
84    let ast = parse_ast(query)?;
85    bind_with(&ast, catalog, &Parameters::new(), session)
86}
87
88/// What an aggregating select block has decided so far.
89#[derive(Debug)]
90pub(crate) struct Aggregation {
91    /// The table index the aggregate's output binds against.
92    pub(crate) index: u32,
93    /// The group expressions, over the input, which are the first output columns.
94    pub(crate) groups: Vec<ExprRef>,
95    /// The aggregate calls found so far, which follow the groups in the output.
96    pub(crate) aggregates: Vec<ExprRef>,
97}
98
99/// The state one binding run carries.
100#[derive(Debug)]
101pub(crate) struct Binder<'a> {
102    catalog: &'a Catalog,
103    /// What the parameters were given, empty for a statement that is not prepared.
104    pub(crate) parameters: &'a Parameters,
105    /// What the settings are now, which is what `current_setting()` folds to.
106    pub(crate) session: &'a Session,
107    plan: Plan,
108    next_index: u32,
109    /// Set while a select block aggregates, which changes what a bare column means.
110    pub(crate) aggregation: Option<Aggregation>,
111    /// Set while an aggregate's own arguments are being bound, so nesting is caught.
112    pub(crate) in_aggregate: bool,
113    /// Where we are, for an error message that says which clause the writer should look at.
114    pub(crate) clause: &'static str,
115    /// The views whose bodies are open on the stack, which is what catches a cycle.
116    expanding: Vec<String>,
117}
118
119impl<'a> Binder<'a> {
120    pub(crate) fn with(
121        catalog: &'a Catalog,
122        parameters: &'a Parameters,
123        session: &'a Session,
124    ) -> Self {
125        Self {
126            catalog,
127            parameters,
128            session,
129            plan: Plan::new(),
130            next_index: 0,
131            aggregation: None,
132            in_aggregate: false,
133            clause: "SELECT clause",
134            expanding: Vec::new(),
135        }
136    }
137
138    pub(crate) fn plan(&self) -> &Plan {
139        &self.plan
140    }
141
142    pub(crate) fn plan_mut(&mut self) -> &mut Plan {
143        &mut self.plan
144    }
145
146    pub(crate) fn into_plan(self) -> Plan {
147        self.plan
148    }
149
150    /// A table index nothing else has.
151    pub(crate) fn fresh_index(&mut self) -> u32 {
152        let index = self.next_index;
153        self.next_index += 1;
154        index
155    }
156
157    /// A reference to one column of an operator's output.
158    fn column(&mut self, index: u32, position: usize, ty: LogicalType) -> ExprRef {
159        let binding = ColumnBinding::new(index, position as u32);
160        self.plan.add_expr(Expr::Column(binding), ty)
161    }
162
163    // ---------------------------------------------------------------- queries
164
165    pub(crate) fn bind_query(
166        &mut self,
167        ast: &Ast,
168        query: ast::QueryRef,
169    ) -> Result<(NodeRef, Scope)> {
170        let written = ast.query(query);
171        match written.body {
172            ast::QueryBody::Select(select) => self.bind_select(ast, select, &written),
173            ast::QueryBody::SetOp { op, quantifier, by_name, left, right } => {
174                if by_name {
175                    return Err(Error::not_implemented("UNION BY NAME"));
176                }
177                self.bind_set_op(ast, &written, op, quantifier, left, right)
178            }
179            ast::QueryBody::Values(rows) => self.bind_values(ast, &written, rows),
180            ast::QueryBody::Describe(inner) => self.bind_describe(ast, &written, inner),
181        }
182    }
183
184    /// `DESCRIBE <query>`, which is six VARCHAR columns saying what the query returns.
185    ///
186    /// The query is bound and never run, because binding is the whole of the answer: the names and
187    /// the types of a query's columns are settled by the time the binder is done with it, so the
188    /// rows of a describe are a constant from there on. That is why this comes out as a `VALUES`
189    /// whose rows were computed here rather than as an operator of its own, and it is what makes
190    /// `SELECT column_name FROM (DESCRIBE ...) WHERE ...` an ordinary query over an ordinary
191    /// relation with no special case above it.
192    ///
193    /// The six columns, their order and their types are the reference binary's. `key`, `default`
194    /// and `extra` are null for everything this engine can declare, since `PRIMARY KEY`, `UNIQUE`
195    /// and `DEFAULT` are all refused by `CREATE TABLE` today and there is nothing for the first two
196    /// to hold, and `extra` is empty upstream as well on every table it was asked about. They are
197    /// here rather than left out because the width of a result is part of the result, and a program
198    /// that reads the fifth column has to find one.
199    fn bind_describe(
200        &mut self,
201        ast: &Ast,
202        query: &ast::Query,
203        inner: ast::QueryRef,
204    ) -> Result<(NodeRef, Scope)> {
205        let (_, described) = self.bind_query(ast, inner)?;
206        let fields: Vec<Field> = ["column_name", "column_type", "null", "key", "default", "extra"]
207            .iter()
208            .map(|name| Field::new(*name, LogicalType::Varchar))
209            .collect();
210        let mut slices = Vec::with_capacity(described.columns.len());
211        for column in described.columns.clone() {
212            // `NO` and `YES` and not a boolean, because the column is VARCHAR upstream and a
213            // client that prints the result has to get the same four or three characters.
214            let written = [
215                column.name.clone(),
216                column.ty.to_string(),
217                if column.not_null { "NO" } else { "YES" }.to_owned(),
218            ];
219            let mut items: Vec<ExprRef> = written
220                .into_iter()
221                .map(|text| self.plan.add_constant(Value::Varchar(text)))
222                .collect();
223            for _ in 0..3 {
224                let empty = self.plan.add_constant(Value::Null);
225                items.push(self.cast_to(empty, &LogicalType::Varchar));
226            }
227            slices.push(self.plan.add_expr_list(&items));
228        }
229        let rows = self.plan.add_rows(&slices);
230        let columns = self.plan.add_fields(&fields);
231        let index = self.fresh_index();
232        let mut node = self.plan.add_node(Node::Values { index, columns, rows });
233        let mut scope = Scope::empty();
234        for (at, field) in fields.iter().enumerate() {
235            scope.push(Visible {
236                table: String::new(),
237                name: field.name.clone(),
238                binding: ColumnBinding::new(index, at as u32),
239                ty: field.ty.clone(),
240                not_null: false,
241            });
242        }
243        let keys = self.sort_keys(ast, query, &scope, &[])?;
244        if !keys.is_empty() {
245            let keys = self.plan.add_sort_keys(&keys);
246            node = self.plan.add_node(Node::Sort { input: node, keys });
247        }
248        node = self.apply_limit(ast, query, node)?;
249        Ok((node, scope))
250    }
251
252    /// Whether a projected expression is a column passed straight through from below.
253    ///
254    /// Only `DESCRIBE` asks, and only to decide whether the `null` column says `NO`. Anything that
255    /// is computed is nullable however strict its inputs were, which is both the safe reading and
256    /// the one the reference binary gives.
257    fn passes_through(&self, expr: ExprRef, input: &Scope) -> bool {
258        let Expr::Column(binding) = *self.plan.expr(expr) else { return false };
259        input.columns.iter().any(|column| column.binding == binding && column.not_null)
260    }
261
262    /// `VALUES (1, 'a'), (2, 'b')`, as a query in its own right.
263    ///
264    /// The column names are `col0`, `col1` and so on, which is what DuckDB calls them, and the
265    /// column types are what every row in that position promotes to. Promotion is the same rule a
266    /// set operation uses, and for the same reason: a column has one type and the rows have to
267    /// agree on it before anything downstream can read the column.
268    fn bind_values(
269        &mut self,
270        ast: &Ast,
271        query: &ast::Query,
272        rows: ast::Slice,
273    ) -> Result<(NodeRef, Scope)> {
274        let written = ast.rows(rows).to_vec();
275        let Some(first) = written.first() else {
276            return Err(Error::binder("VALUES needs at least one row"));
277        };
278        let width = first.len as usize;
279        for (at, row) in written.iter().enumerate() {
280            if row.len as usize != width {
281                return Err(Error::binder(format!(
282                    "VALUES lists must all be the same length, expected {width} columns but row {} has {}",
283                    at + 1,
284                    row.len
285                )));
286            }
287        }
288        // A row of a `VALUES` cannot see a column, because there is nothing under it to see.
289        let empty = Scope::empty();
290        let previous = std::mem::replace(&mut self.clause, "VALUES clause");
291        let mut bound: Vec<Vec<ExprRef>> = Vec::with_capacity(written.len());
292        for row in &written {
293            let mut items = Vec::with_capacity(width);
294            for &expr in ast.expr_list(*row) {
295                items.push(self.bind_expr(ast, expr, &empty)?);
296            }
297            bound.push(items);
298        }
299        self.clause = previous;
300        let mut types = Vec::with_capacity(width);
301        for at in 0..width {
302            let mut ty = self.plan.expr_type(bound[0][at]).clone();
303            for row in &bound[1..] {
304                let other = self.plan.expr_type(row[at]).clone();
305                ty = ty.promote(&other).ok_or_else(|| {
306                    Error::binder(format!(
307                        "Cannot combine a value of type {ty} with a value of type {other} in column {} of a VALUES",
308                        at + 1
309                    ))
310                })?;
311            }
312            types.push(ty);
313        }
314        let mut slices = Vec::with_capacity(bound.len());
315        for row in &bound {
316            let items: Vec<ExprRef> =
317                row.iter().zip(&types).map(|(&expr, ty)| self.cast_to(expr, ty)).collect();
318            slices.push(self.plan.add_expr_list(&items));
319        }
320        let rows = self.plan.add_rows(&slices);
321        let fields: Vec<Field> = types
322            .iter()
323            .enumerate()
324            .map(|(at, ty)| Field::new(format!("col{at}"), ty.clone()))
325            .collect();
326        let columns = self.plan.add_fields(&fields);
327        let index = self.fresh_index();
328        let mut node = self.plan.add_node(Node::Values { index, columns, rows });
329        let mut scope = Scope::empty();
330        for (at, field) in fields.iter().enumerate() {
331            scope.push(Visible {
332                table: String::new(),
333                name: field.name.clone(),
334                binding: ColumnBinding::new(index, at as u32),
335                ty: field.ty.clone(),
336                not_null: false,
337            });
338        }
339        let keys = self.sort_keys(ast, query, &scope, &[])?;
340        if !keys.is_empty() {
341            let keys = self.plan.add_sort_keys(&keys);
342            node = self.plan.add_node(Node::Sort { input: node, keys });
343        }
344        node = self.apply_limit(ast, query, node)?;
345        Ok((node, scope))
346    }
347
348    fn bind_set_op(
349        &mut self,
350        ast: &Ast,
351        query: &ast::Query,
352        op: SetOp,
353        quantifier: Quantifier,
354        left: ast::QueryRef,
355        right: ast::QueryRef,
356    ) -> Result<(NodeRef, Scope)> {
357        let (left_node, left_scope) = self.bind_query(ast, left)?;
358        let (right_node, right_scope) = self.bind_query(ast, right)?;
359        if left_scope.len() != right_scope.len() {
360            return Err(Error::binder(format!(
361                "Set operations can only apply to expressions with the same number of result columns, but left side has {} and right side has {}",
362                left_scope.len(),
363                right_scope.len()
364            )));
365        }
366        // Both sides have to hand back one set of types, so each column meets the other side's.
367        let mut types = Vec::with_capacity(left_scope.len());
368        for (left, right) in left_scope.columns.iter().zip(&right_scope.columns) {
369            let common = left.ty.promote(&right.ty).ok_or_else(|| {
370                Error::binder(format!(
371                    "Cannot combine a column of type {} with a column of type {} in a set operation",
372                    left.ty, right.ty
373                ))
374            })?;
375            types.push(common);
376        }
377        let left_node = self.conform(left_node, &left_scope, &types);
378        let right_node = self.conform(right_node, &right_scope, &types);
379        let index = self.fresh_index();
380        let kind = match op {
381            SetOp::Union => SetOpKind::Union,
382            SetOp::Except => SetOpKind::Except,
383            SetOp::Intersect => SetOpKind::Intersect,
384        };
385        // UNION alone removes duplicates and UNION ALL keeps them, which is the one place the
386        // unwritten quantifier and ALL disagree.
387        let all = quantifier == Quantifier::All;
388        let mut node = self.plan.add_node(Node::SetOp {
389            left: left_node,
390            right: right_node,
391            kind,
392            all,
393            index,
394        });
395        let mut scope = Scope::empty();
396        for (at, (column, ty)) in left_scope.columns.iter().zip(&types).enumerate() {
397            scope.push(Visible {
398                table: String::new(),
399                name: column.name.clone(),
400                binding: ColumnBinding::new(index, at as u32),
401                ty: ty.clone(),
402                // A column of a set operation is nullable whatever the two sides were, because a
403                // column that refuses nulls on one side and takes them on the other takes them.
404                not_null: false,
405            });
406        }
407        // Above a set operation there is nothing but the output columns, so an ORDER BY term is
408        // either a position, an output name, or an expression over the output, and never needs a
409        // column projected for it that the query did not ask for.
410        let keys = self.sort_keys(ast, query, &scope, &[])?;
411        if !keys.is_empty() {
412            let keys = self.plan.add_sort_keys(&keys);
413            node = self.plan.add_node(Node::Sort { input: node, keys });
414        }
415        node = self.apply_limit(ast, query, node)?;
416        Ok((node, scope))
417    }
418
419    /// Projects one side of a set operation so that its columns have the agreed types.
420    fn conform(&mut self, node: NodeRef, scope: &Scope, types: &[LogicalType]) -> NodeRef {
421        if scope.columns.iter().zip(types).all(|(column, ty)| &column.ty == ty) {
422            return node;
423        }
424        let index = self.fresh_index();
425        let mut exprs = Vec::with_capacity(types.len());
426        let mut names = Vec::with_capacity(types.len());
427        for (column, ty) in scope.columns.iter().zip(types) {
428            let expr = self.plan.add_expr(Expr::Column(column.binding), column.ty.clone());
429            exprs.push(self.cast_to(expr, ty));
430            names.push(self.plan.intern(&column.name));
431        }
432        let exprs = self.plan.add_expr_list(&exprs);
433        let names = self.plan.add_name_list(&names);
434        self.plan.add_node(Node::Project { input: node, index, exprs, names })
435    }
436
437    // ----------------------------------------------------------------- select
438
439    fn bind_select(
440        &mut self,
441        ast: &Ast,
442        select: ast::SelectRef,
443        query: &ast::Query,
444    ) -> Result<(NodeRef, Scope)> {
445        let written = ast.select(select);
446        let (mut node, input) = self.bind_from(ast, written.from)?;
447
448        if written.filter != NONE {
449            self.clause = "WHERE clause";
450            let predicate = self.bind_expr(ast, written.filter, &input)?;
451            let predicate = self.as_boolean(predicate, "WHERE")?;
452            node = self.plan.add_node(Node::Filter { input: node, predicate });
453        }
454
455        let targets = ast.target_list(written.targets).to_vec();
456        if targets.is_empty() {
457            return Err(Error::binder("a SELECT needs at least one expression to select"));
458        }
459
460        let group_items = self.group_items(ast, &written, &targets)?;
461        let aggregating = !group_items.is_empty()
462            || written.having != NONE
463            || targets.iter().any(|target| has_aggregate(ast, target.expr));
464        if aggregating {
465            self.clause = "GROUP BY clause";
466            let mut groups = Vec::with_capacity(group_items.len());
467            for item in &group_items {
468                groups.push(self.bind_expr(ast, *item, &input)?);
469            }
470            let index = self.fresh_index();
471            self.aggregation = Some(Aggregation { index, groups, aggregates: Vec::new() });
472        }
473
474        self.clause = "SELECT clause";
475        let (mut exprs, mut names) = self.bind_targets(ast, &targets, &input)?;
476        let visible = exprs.len();
477
478        let mut having = None;
479        if written.having != NONE {
480            self.clause = "HAVING clause";
481            let predicate = self.bind_expr(ast, written.having, &input)?;
482            let predicate = self.over_aggregate(predicate, &input)?;
483            having = Some(self.as_boolean(predicate, "HAVING")?);
484        }
485
486        // The projection's index has to exist before the sort keys are built, because a key is a
487        // reference to a projected column even when the expression it sorts on is not selected.
488        let project = self.fresh_index();
489        let mut output = Scope::empty();
490        for (at, (expr, name)) in exprs.iter().zip(&names).enumerate() {
491            output.push(Visible {
492                table: String::new(),
493                name: name.clone(),
494                binding: ColumnBinding::new(project, at as u32),
495                ty: self.plan.expr_type(*expr).clone(),
496                not_null: self.passes_through(*expr, &input),
497            });
498        }
499
500        self.clause = "ORDER BY clause";
501        let mut extra = Vec::new();
502        let keys = self.select_sort_keys(
503            ast, query, &input, &output, project, &mut exprs, &mut names, &mut extra,
504        )?;
505        if !extra.is_empty() && written.distinct != Distinct::No {
506            return Err(Error::binder(
507                "For SELECT DISTINCT, ORDER BY expressions must appear in the select list",
508            ));
509        }
510        let on = self.distinct_on(ast, written.distinct, &output)?;
511
512        if let Some(aggregation) = self.aggregation.take() {
513            let index = aggregation.index;
514            let groups = self.plan.add_expr_list(&aggregation.groups);
515            let aggregates = self.plan.add_expr_list(&aggregation.aggregates);
516            node = self.plan.add_node(Node::Aggregate { input: node, index, groups, aggregates });
517        }
518        if let Some(predicate) = having {
519            node = self.plan.add_node(Node::Filter { input: node, predicate });
520        }
521
522        let interned: Vec<u32> = names.iter().map(|name| self.plan.intern(name)).collect();
523        let exprs_slice = self.plan.add_expr_list(&exprs);
524        let names_slice = self.plan.add_name_list(&interned);
525        node = self.plan.add_node(Node::Project {
526            input: node,
527            index: project,
528            exprs: exprs_slice,
529            names: names_slice,
530        });
531
532        if written.distinct != Distinct::No {
533            let on = self.plan.add_expr_list(&on);
534            node = self.plan.add_node(Node::Distinct { input: node, on });
535        }
536        if !keys.is_empty() {
537            let keys = self.plan.add_sort_keys(&keys);
538            node = self.plan.add_node(Node::Sort { input: node, keys });
539        }
540        node = self.apply_limit(ast, query, node)?;
541
542        if extra.is_empty() {
543            output.columns.truncate(visible);
544            return Ok((node, output));
545        }
546        // An expression sorted on but not selected was carried this far to make the sort possible,
547        // and now it goes, because the query did not ask for it.
548        let index = self.fresh_index();
549        let mut kept = Vec::with_capacity(visible);
550        let mut kept_names = Vec::with_capacity(visible);
551        let mut scope = Scope::empty();
552        for (at, name) in names.iter().enumerate().take(visible) {
553            let ty = output.columns[at].ty.clone();
554            kept.push(self.column(project, at, ty.clone()));
555            kept_names.push(self.plan.intern(name));
556            scope.push(Visible {
557                table: String::new(),
558                name: name.clone(),
559                binding: ColumnBinding::new(index, at as u32),
560                ty,
561                not_null: output.columns[at].not_null,
562            });
563        }
564        let exprs = self.plan.add_expr_list(&kept);
565        let names = self.plan.add_name_list(&kept_names);
566        node = self.plan.add_node(Node::Project { input: node, index, exprs, names });
567        Ok((node, scope))
568    }
569
570    /// Binds the target list, expanding every star into the columns it stands for.
571    fn bind_targets(
572        &mut self,
573        ast: &Ast,
574        targets: &[ast::Target],
575        input: &Scope,
576    ) -> Result<(Vec<ExprRef>, Vec<String>)> {
577        let mut exprs = Vec::with_capacity(targets.len());
578        let mut names = Vec::with_capacity(targets.len());
579        for target in targets {
580            if let ast::Expr::Star { qualifier, replacements } = ast.expr(target.expr) {
581                let table = ast.name(qualifier).last().map(str::to_string);
582                let expanded: Vec<Visible> =
583                    input.star(table.as_deref())?.into_iter().cloned().collect();
584                let replacements = ast.target_list(replacements).to_vec();
585                let mut used = vec![false; replacements.len()];
586                for column in expanded {
587                    let found = replacements.iter().zip(&mut used).find(|(replacement, _)| {
588                        same_name(ast.string(replacement.alias), &column.name)
589                    });
590                    // The replacement takes the column's place and its position, and it is named the
591                    // way the replace list spells it rather than the way the table does. That only
592                    // shows when the two differ in case, and `AS EventDate` over a column called
593                    // `eventdate` is exactly the case that shows it.
594                    let (expr, name) = match found {
595                        Some((replacement, used)) => {
596                            *used = true;
597                            let expr = self.bind_expr(ast, replacement.expr, input)?;
598                            (expr, ast.string(replacement.alias).to_string())
599                        }
600                        None => (
601                            self.plan.add_expr(Expr::Column(column.binding), column.ty),
602                            column.name,
603                        ),
604                    };
605                    exprs.push(self.over_aggregate(expr, input)?);
606                    names.push(name);
607                }
608                // A replace list that named something the star did not stand for is a mistake and
609                // not a no op, and it is caught here because this is the first point at which the
610                // set of names the star stands for is known.
611                if let Some((replacement, _)) =
612                    replacements.iter().zip(&used).find(|(_, used)| !**used)
613                {
614                    return Err(missing_replacement(ast.string(replacement.alias), input));
615                }
616                continue;
617            }
618            let expr = self.bind_expr(ast, target.expr, input)?;
619            exprs.push(self.over_aggregate(expr, input)?);
620            names.push(if target.alias == NONE {
621                self.output_name(ast, target.expr, input)
622            } else {
623                ast.string(target.alias).to_string()
624            });
625        }
626        Ok((exprs, names))
627    }
628
629    /// The name an unaliased target gets.
630    ///
631    /// A bare column keeps the spelling the table was created with rather than the spelling the
632    /// query used, so `SELECT USERID FROM hits` has a column called `UserID`. Identifiers match
633    /// without regard to case and the catalog is the one that holds the case.
634    fn output_name(&self, ast: &Ast, target: ast::ExprRef, input: &Scope) -> String {
635        if let ast::Expr::Column { name } = ast.expr(target) {
636            let parts: Vec<&str> = ast.name(name).collect();
637            if let Ok(found) = input.resolve(&parts) {
638                return found.name.clone();
639            }
640        }
641        describe(ast, target)
642    }
643
644    /// The expressions a `GROUP BY` clause names, with positions and output aliases followed.
645    fn group_items(
646        &self,
647        ast: &Ast,
648        select: &ast::Select,
649        targets: &[ast::Target],
650    ) -> Result<Vec<ast::ExprRef>> {
651        if select.group_by_all {
652            // GROUP BY ALL means every target that is not itself an aggregate, which is the set
653            // that would otherwise have to be written out again by hand.
654            return Ok(targets
655                .iter()
656                .filter(|target| !has_aggregate(ast, target.expr))
657                .map(|target| target.expr)
658                .collect());
659        }
660        let mut items = Vec::new();
661        for &item in ast.expr_list(select.group_by) {
662            items.push(self.output_reference(ast, item, targets, "GROUP BY")?.unwrap_or(item));
663        }
664        Ok(items)
665    }
666
667    /// The target a `GROUP BY` or `ORDER BY` term names, when it names one by position or alias.
668    fn output_reference(
669        &self,
670        ast: &Ast,
671        item: ast::ExprRef,
672        targets: &[ast::Target],
673        clause: &str,
674    ) -> Result<Option<ast::ExprRef>> {
675        match ast.expr(item) {
676            ast::Expr::Literal { kind: LiteralKind::Number, text } => {
677                let written = ast.string(text);
678                let position: usize = written.parse().map_err(|_| {
679                    Error::binder(format!("{clause} term {written} is not a column"))
680                })?;
681                if position == 0 || position > targets.len() {
682                    return Err(Error::binder(format!(
683                        "{clause} term out of range - should be between 1 and {}",
684                        targets.len()
685                    )));
686                }
687                Ok(Some(targets[position - 1].expr))
688            }
689            ast::Expr::Column { name } => {
690                let parts: Vec<&str> = ast.name(name).collect();
691                let [written] = parts.as_slice() else { return Ok(None) };
692                let mut found = None;
693                for target in targets {
694                    if target.alias != NONE && same_name(ast.string(target.alias), written) {
695                        if found.is_some() {
696                            return Ok(None);
697                        }
698                        found = Some(target.expr);
699                    }
700                }
701                Ok(found)
702            }
703            _ => Ok(None),
704        }
705    }
706
707    // -------------------------------------------------------------- modifiers
708
709    /// Sort keys for a select, projecting anything sorted on that is not already selected.
710    #[allow(clippy::too_many_arguments)]
711    fn select_sort_keys(
712        &mut self,
713        ast: &Ast,
714        query: &ast::Query,
715        input: &Scope,
716        output: &Scope,
717        project: u32,
718        exprs: &mut Vec<ExprRef>,
719        names: &mut Vec<String>,
720        extra: &mut Vec<usize>,
721    ) -> Result<Vec<SortKey>> {
722        if query.order_by_all {
723            return Ok(self.every_column(output));
724        }
725        let items = ast.order_list(query.order_by).to_vec();
726        let mut keys = Vec::with_capacity(items.len());
727        for item in items {
728            let position = match self.output_position(ast, item.expr, output)? {
729                Some(position) => position,
730                None => {
731                    let bound = self.bind_expr(ast, item.expr, input)?;
732                    let bound = self.over_aggregate(bound, input)?;
733                    match exprs.iter().position(|&held| self.same_expr(held, bound)) {
734                        Some(position) => position,
735                        None => {
736                            exprs.push(bound);
737                            names.push(describe(ast, item.expr));
738                            extra.push(exprs.len() - 1);
739                            exprs.len() - 1
740                        }
741                    }
742                }
743            };
744            let ty = self.plan.expr_type(exprs[position]).clone();
745            let expr = self.column(project, position, ty);
746            keys.push(sort_key(expr, item));
747        }
748        Ok(keys)
749    }
750
751    /// Sort keys over an output that has nothing behind it to project, which is a set operation.
752    fn sort_keys(
753        &mut self,
754        ast: &Ast,
755        query: &ast::Query,
756        output: &Scope,
757        targets: &[ast::Target],
758    ) -> Result<Vec<SortKey>> {
759        if query.order_by_all {
760            return Ok(self.every_column(output));
761        }
762        let items = ast.order_list(query.order_by).to_vec();
763        let mut keys = Vec::with_capacity(items.len());
764        for item in items {
765            let expr = match self.output_position(ast, item.expr, output)? {
766                Some(position) => {
767                    let column = &output.columns[position];
768                    let (binding, ty) = (column.binding, column.ty.clone());
769                    self.plan.add_expr(Expr::Column(binding), ty)
770                }
771                None => {
772                    let _ = targets;
773                    self.bind_expr(ast, item.expr, output)?
774                }
775            };
776            keys.push(sort_key(expr, item));
777        }
778        Ok(keys)
779    }
780
781    fn every_column(&mut self, output: &Scope) -> Vec<SortKey> {
782        let columns: Vec<(ColumnBinding, LogicalType)> =
783            output.columns.iter().map(|column| (column.binding, column.ty.clone())).collect();
784        columns
785            .into_iter()
786            .map(|(binding, ty)| {
787                let expr = self.plan.add_expr(Expr::Column(binding), ty);
788                SortKey { expr, descending: false, nulls_first: false }
789            })
790            .collect()
791    }
792
793    /// Which output column a term names, by position or by name.
794    fn output_position(
795        &self,
796        ast: &Ast,
797        item: ast::ExprRef,
798        output: &Scope,
799    ) -> Result<Option<usize>> {
800        match ast.expr(item) {
801            ast::Expr::Literal { kind: LiteralKind::Number, text } => {
802                let written = ast.string(text);
803                if written.contains(['.', 'e', 'E']) {
804                    return Ok(None);
805                }
806                let position: usize = written.parse().map_err(|_| {
807                    Error::binder(format!("ORDER BY term {written} is not a column"))
808                })?;
809                if position == 0 || position > output.len() {
810                    return Err(Error::binder(format!(
811                        "ORDER BY term out of range - should be between 1 and {}",
812                        output.len()
813                    )));
814                }
815                Ok(Some(position - 1))
816            }
817            ast::Expr::Column { name } => {
818                let parts: Vec<&str> = ast.name(name).collect();
819                let [written] = parts.as_slice() else { return Ok(None) };
820                Ok(output.position_of(None, written))
821            }
822            _ => Ok(None),
823        }
824    }
825
826    /// The expressions a `DISTINCT ON` names, which have to be columns of the output.
827    fn distinct_on(
828        &mut self,
829        ast: &Ast,
830        distinct: Distinct,
831        output: &Scope,
832    ) -> Result<Vec<ExprRef>> {
833        let Distinct::On(items) = distinct else {
834            return Ok(Vec::new());
835        };
836        let items = ast.expr_list(items).to_vec();
837        let mut on = Vec::with_capacity(items.len());
838        for item in items {
839            let Some(position) = self.output_position(ast, item, output)? else {
840                return Err(Error::not_implemented(
841                    "DISTINCT ON an expression that is not in the select list",
842                ));
843            };
844            let column = &output.columns[position];
845            let (binding, ty) = (column.binding, column.ty.clone());
846            on.push(self.plan.add_expr(Expr::Column(binding), ty));
847        }
848        Ok(on)
849    }
850
851    fn apply_limit(&mut self, ast: &Ast, query: &ast::Query, input: NodeRef) -> Result<NodeRef> {
852        if query.limit_percent {
853            return Err(Error::not_implemented("LIMIT with a percentage"));
854        }
855        let count = self.constant_count(ast, query.limit, "LIMIT")?;
856        let offset = self.constant_count(ast, query.offset, "OFFSET")?.unwrap_or(0);
857        if count.is_none() && offset == 0 {
858            return Ok(input);
859        }
860        Ok(self.plan.add_node(Node::Limit { input, count, offset }))
861    }
862
863    /// The row count a `LIMIT` or an `OFFSET` names, which has to be a constant.
864    fn constant_count(
865        &mut self,
866        ast: &Ast,
867        written: ast::ExprRef,
868        clause: &str,
869    ) -> Result<Option<u64>> {
870        if written == NONE {
871            return Ok(None);
872        }
873        self.clause = "LIMIT clause";
874        let scope = Scope::empty();
875        let bound = self.bind_expr(ast, written, &scope)?;
876        let Expr::Constant(value) = *self.plan.expr(bound) else {
877            return Err(Error::not_implemented(format!("a {clause} that is not a constant")));
878        };
879        let count = match self.plan.value(value) {
880            Value::Null => return Ok(None),
881            Value::TinyInt(count) => i128::from(*count),
882            Value::SmallInt(count) => i128::from(*count),
883            Value::Integer(count) => i128::from(*count),
884            Value::BigInt(count) => i128::from(*count),
885            Value::HugeInt(count) => *count,
886            other => {
887                return Err(Error::binder(format!(
888                    "{clause} takes a whole number of rows, not a value of type {}",
889                    other.logical_type()
890                )));
891            }
892        };
893        u64::try_from(count)
894            .map(Some)
895            .map_err(|_| Error::binder(format!("{clause} must not be negative")))
896    }
897
898    // ------------------------------------------------------------------- from
899
900    fn bind_from(&mut self, ast: &Ast, from: ast::Slice) -> Result<(NodeRef, Scope)> {
901        let sources = ast.source_list(from).to_vec();
902        let Some((first, rest)) = sources.split_first() else {
903            // No FROM clause is one row of no columns, which is what SELECT 1 sits on. Not an
904            // empty table: an empty table would make SELECT 1 return nothing.
905            return Ok((self.plan.add_node(Node::Dummy), Scope::empty()));
906        };
907        let (mut node, mut scope) = self.bind_source(ast, *first)?;
908        for source in rest {
909            let (right, right_scope) = self.bind_source(ast, *source)?;
910            node = self.plan.add_node(Node::CrossProduct { left: node, right });
911            scope = scope.concat(right_scope);
912        }
913        Ok((node, scope))
914    }
915
916    fn bind_source(&mut self, ast: &Ast, source: ast::SourceRef) -> Result<(NodeRef, Scope)> {
917        match ast.source(source) {
918            ast::Source::Table { name, alias, columns } => {
919                self.bind_table(ast, name, alias, columns)
920            }
921            ast::Source::Function { name, args, alias, columns } => {
922                self.bind_table_function(ast, name, args, alias, columns)
923            }
924            ast::Source::Subquery { query, alias, columns } => {
925                let (node, mut scope) = self.bind_query(ast, query)?;
926                let label = if alias == NONE {
927                    "unnamed_subquery".to_string()
928                } else {
929                    ast.string(alias).to_string()
930                };
931                scope.relabel(&label);
932                if !columns.is_empty() {
933                    let names: Vec<&str> = ast.name(columns).collect();
934                    scope.rename(&names, &label)?;
935                }
936                Ok((node, scope))
937            }
938            ast::Source::Values { rows, alias, columns } => {
939                let bare = ast::Query::bare(ast::QueryBody::Values(rows));
940                let (node, mut scope) = self.bind_values(ast, &bare, rows)?;
941                let label =
942                    if alias == NONE { String::new() } else { ast.string(alias).to_string() };
943                scope.relabel(&label);
944                if !columns.is_empty() {
945                    let names: Vec<&str> = ast.name(columns).collect();
946                    scope.rename(&names, &label)?;
947                }
948                Ok((node, scope))
949            }
950            ast::Source::Join { left, right, kind, natural, on, using } => {
951                self.bind_join(ast, left, right, kind, natural, on, using)
952            }
953        }
954    }
955
956    fn bind_table(
957        &mut self,
958        ast: &Ast,
959        name: ast::Slice,
960        alias: ast::StrRef,
961        columns: ast::Slice,
962    ) -> Result<(NodeRef, Scope)> {
963        let parts: Vec<&str> = ast.name(name).collect();
964        let catalog = self.catalog;
965        // The catalog is asked first and the file is the fallback, which is the order DuckDB uses:
966        // a table really called `mixed.parquet` wins over a file of that name sitting next to it.
967        let resolved = match catalog.resolve(&parts) {
968            Ok(resolved) => resolved,
969            Err(missing) => {
970                return self.bind_replacement_scan(ast, &parts, alias, columns, missing);
971            }
972        };
973        if catalog.entry(&resolved)? == Entry::View {
974            return self.bind_view(ast, &resolved, alias, columns);
975        }
976        let table = catalog.table(&resolved)?;
977        let fields: Vec<Field> = table.columns().to_vec();
978        let label =
979            if alias == NONE { resolved.table.clone() } else { ast.string(alias).to_string() };
980        let index = self.fresh_index();
981        let mut scope = Scope::empty();
982        for (at, field) in fields.iter().enumerate() {
983            scope.push(Visible {
984                table: label.clone(),
985                name: field.name.clone(),
986                binding: ColumnBinding::new(index, at as u32),
987                ty: field.ty.clone(),
988                not_null: field.not_null,
989            });
990        }
991        if !columns.is_empty() {
992            let names: Vec<&str> = ast.name(columns).collect();
993            scope.rename(&names, &label)?;
994        }
995        let catalog_name = self.plan.intern(&resolved.catalog);
996        let schema = self.plan.intern(&resolved.schema);
997        let table_name = self.plan.intern(&resolved.table);
998        let alias = self.plan.intern(&label);
999        let columns = self.plan.add_fields(&fields);
1000        let node = self.plan.add_node(Node::Get {
1001            catalog: catalog_name,
1002            schema,
1003            table: table_name,
1004            alias,
1005            index,
1006            columns,
1007        });
1008        Ok((node, scope))
1009    }
1010
1011    /// A view where a table goes, which is the body bound again right here.
1012    ///
1013    /// Inline and not behind a node. The view is gone by the time the plan exists, so everything
1014    /// downstream sees the query somebody would have written by hand, and the column pruning that
1015    /// makes `SELECT COUNT(*) FROM 'hits.parquet'` read no columns at all keeps working through
1016    /// `FROM hits`. A `Node::View` would be a barrier with nothing on the other side of it.
1017    ///
1018    /// The scope this builds is a subquery's, right down to the name in the error message. duckdb
1019    /// v1.5.1 reports a view whose column list has gone stale as `table "unnamed_subquery" has 1
1020    /// columns available but 2 columns specified`, which is the sentence its subquery alias rule
1021    /// produces, so a view there is a subquery with the view's name written over it afterwards.
1022    fn bind_view(
1023        &mut self,
1024        ast: &Ast,
1025        name: &QualifiedName,
1026        alias: ast::StrRef,
1027        columns: ast::Slice,
1028    ) -> Result<(NodeRef, Scope)> {
1029        let view = self.catalog.view(name)?;
1030        let full = name.to_string();
1031        if self.expanding.contains(&full) {
1032            // Two quotes each side, which is what the binary prints. It quotes the name on the way
1033            // in and then formats the quoted name into a quoted slot, so a view called `a` comes
1034            // back as `""a""`. That is upstream's wart and copying it is the whole job here.
1035            return Err(Error::binder(format!(
1036                "infinite recursion detected: attempting to recursively bind view \"\"{}\"\"",
1037                name.table
1038            )));
1039        }
1040        let body = parse_ast(view.sql())?;
1041        let query = match body.statements.as_slice() {
1042            [ast::Statement::Query(query)] => *query,
1043            // Only a query can have got past the binder at creation, so this is a view the catalog
1044            // was handed some other way rather than anything a statement can produce.
1045            _ => return Err(Error::binder(format!("view \"{}\" is not a query", name.table))),
1046        };
1047        self.expanding.push(full);
1048        let bound = self.bind_query(&body, query);
1049        self.expanding.pop();
1050        let (node, mut scope) = bound?;
1051
1052        let aliases: Vec<&str> = view.aliases().iter().map(String::as_str).collect();
1053        if !aliases.is_empty() {
1054            scope.rename(&aliases, "unnamed_subquery")?;
1055        }
1056        let label = if alias == NONE { name.table.clone() } else { ast.string(alias).to_string() };
1057        scope.relabel(&label);
1058        if !columns.is_empty() {
1059            let names: Vec<&str> = ast.name(columns).collect();
1060            scope.rename(&names, &label)?;
1061        }
1062        Ok((node, scope))
1063    }
1064
1065    /// A function call where a table goes, such as `range(10)`.
1066    ///
1067    /// The arguments are bound against an empty scope. A table function that can see the row on its
1068    /// left is `LATERAL`, and this is not it, so a column name in here is not resolved against
1069    /// whatever happens to be to the left in the `FROM` list. Letting it would mean `FROM t,
1070    /// range(t.n)` quietly binding to something whose meaning depends on the order the sources were
1071    /// written in.
1072    fn bind_table_function(
1073        &mut self,
1074        ast: &Ast,
1075        name: ast::Slice,
1076        args: ast::Slice,
1077        alias: ast::StrRef,
1078        columns: ast::Slice,
1079    ) -> Result<(NodeRef, Scope)> {
1080        let parts: Vec<&str> = ast.name(name).collect();
1081        // A qualified call names a schema, and the two schemas that exist are the ones every
1082        // built-in lives in. Anything else is a name that has to fail rather than fall through to
1083        // the unqualified lookup and be found somewhere it was not asked for.
1084        let function_name = *parts.last().unwrap_or(&"");
1085        if let Some(schema) = parts.iter().rev().nth(1) {
1086            if !schema.eq_ignore_ascii_case("main") && !schema.eq_ignore_ascii_case("system") {
1087                return Err(Error::catalog(format!(
1088                    "Table Function with name {} does not exist!",
1089                    parts.join(".")
1090                )));
1091            }
1092        }
1093        // The name is looked up before the arguments are bound so that a call of something that is
1094        // not a table function says that, rather than reporting whatever is wrong with the
1095        // arguments of a function that was never going to exist.
1096        let Some(called) = TableFunction::lookup(function_name) else {
1097            return Err(Error::catalog(format!(
1098                "Table Function with name {function_name} does not exist!"
1099            )));
1100        };
1101        let written = ast.target_list(args).to_vec();
1102        let empty = Scope::empty();
1103        let previous = std::mem::replace(&mut self.clause, "table function arguments");
1104        let mut bound = Vec::new();
1105        let mut written_options = Vec::new();
1106        for argument in written {
1107            let expr = self.bind_expr(ast, argument.expr, &empty)?;
1108            if argument.alias == NONE {
1109                bound.push(expr);
1110            } else {
1111                let name = ast.string(argument.alias).to_string();
1112                let (parameter, value) = self.named_argument(called, &name, expr)?;
1113                written_options.push((parameter, value, expr));
1114            }
1115        }
1116        self.clause = previous;
1117        let options = Options::of(&written_options)?;
1118
1119        // The types are what resolve the call, not the count, because `read_parquet(3)` is a
1120        // different answer from `read_parquet('3')` and only the types tell them apart.
1121        let given: Vec<LogicalType> =
1122            bound.iter().map(|&expr| self.plan.expr_type(expr).clone()).collect();
1123        let resolved = resolve_table(function_name, &given)?;
1124        let mut cast: Vec<ExprRef> = bound
1125            .iter()
1126            .zip(&resolved.arguments)
1127            .map(|(&expr, ty)| self.cast_to(expr, ty))
1128            .collect();
1129
1130        let fields = match resolved.columns {
1131            Columns::Fixed(fields) => fields,
1132            columns => {
1133                // The one argument is a pattern, and what replaces it is one constant per file it
1134                // matched. The executor is handed names rather than a pattern, so it never walks a
1135                // directory and the answer cannot change between binding a prepared statement and
1136                // running it, which is the same reason the schema is settled here.
1137                let paths = self.file_paths(cast[0], resolved.function.name())?;
1138                let first = paths.first().map_or("", String::as_str);
1139                let mut fields = match columns {
1140                    // Parquet takes the first file's footer as the answer and CSV sniffs all of
1141                    // them, which is not a choice made here. See `csv_fields`.
1142                    Columns::Csv => csv_fields(&paths, options.given)?,
1143                    _ => parquet_fields(first)?,
1144                };
1145                if options.all_varchar {
1146                    // The sniffer still ran, because the names come out of the same pass over the
1147                    // front of the file and only the types are being overruled. The executor reads
1148                    // the text as VARCHAR because this is the schema it is told to read into, which
1149                    // is the same road a file in a glob takes when the set is wider than the file.
1150                    for field in &mut fields {
1151                        field.ty = LogicalType::Varchar;
1152                    }
1153                }
1154                if options.binary_as_string {
1155                    // A byte array column with no annotation on it is a BLOB, and this is the caller
1156                    // saying that the file's writer meant text. The reader already holds both in the
1157                    // same string column and already validates the bytes, so the whole of the option
1158                    // is what the column is called from here on.
1159                    for field in &mut fields {
1160                        if field.ty == LogicalType::Blob {
1161                            field.ty = LogicalType::Varchar;
1162                        }
1163                    }
1164                }
1165                if options.file_row_number {
1166                    // Not a column of the file, so it goes on the end where a projection cannot be
1167                    // confused about which one it is, and the executor counts it as the rows come
1168                    // out. A file that already has a column of that name is the one case where the
1169                    // option cannot be honoured, and saying so is better than handing back two
1170                    // columns with the same name and letting a reference to it pick one.
1171                    if fields.iter().any(|field| field.name == FILE_ROW_NUMBER) {
1172                        return Err(Error::binder(format!(
1173                            "Duplicate column name \"{FILE_ROW_NUMBER}\": the file already has a \
1174                             column of that name, so file_row_number cannot add one"
1175                        )));
1176                    }
1177                    fields.push(Field::required(FILE_ROW_NUMBER.to_string(), LogicalType::BigInt));
1178                }
1179                cast = paths.iter().map(|path| self.path_constant(path)).collect();
1180                fields
1181            }
1182        };
1183        let label = if alias == NONE {
1184            resolved.function.name().to_string()
1185        } else {
1186            ast.string(alias).to_string()
1187        };
1188        let names: Vec<&str> = ast.name(columns).collect();
1189        self.table_function_source(
1190            resolved.function,
1191            &cast,
1192            &written_options,
1193            fields,
1194            &label,
1195            &names,
1196        )
1197    }
1198
1199    /// One named parameter of a table function call, folded into what the call was given.
1200    ///
1201    /// The value has to be a constant of the type the parameter wants. It has to be constant
1202    /// because an option can decide what the columns are and the columns are settled here, and it
1203    /// has to be already of the type because there is no constant folding in front of the binder
1204    /// yet. DuckDB folds first, so `binary_as_string=1` and `binary_as_string='yes'` are both true
1205    /// there and both are turned away here, which is a gap that closes on its own the day the
1206    /// optimizer runs before the plan is finished. `binary_as_string=True` is what the ClickBench
1207    /// entry writes and is what has to work.
1208    ///
1209    /// A name that is not a parameter of this function is the binary's sentence followed by what it
1210    /// could have been. The binary puts the candidates on their own indented lines and this puts
1211    /// them on the same line, because an error is one line here.
1212    fn named_argument(
1213        &mut self,
1214        function: TableFunction,
1215        name: &str,
1216        expr: ExprRef,
1217    ) -> Result<(&'static str, Value)> {
1218        let known = function
1219            .parameters()
1220            .iter()
1221            .find(|(parameter, _)| parameter.eq_ignore_ascii_case(name));
1222        let Some((parameter, wanted)) = known else {
1223            let candidates: Vec<String> = function
1224                .parameters()
1225                .iter()
1226                .map(|(parameter, ty)| format!("    {parameter} {ty}"))
1227                .collect();
1228            return Err(Error::binder(format!(
1229                "Invalid named parameter \"{name}\" for function {}\nCandidates:\n{}\n",
1230                function.name(),
1231                candidates.join("\n")
1232            )));
1233        };
1234        let Expr::Constant(reference) = *self.plan.expr(expr) else {
1235            return Err(Error::not_implemented(format!(
1236                "the named parameter {parameter} with a value that is not a constant"
1237            )));
1238        };
1239        let value = self.plan.value(reference).clone();
1240        if value == Value::Null {
1241            return Err(Error::binder(null_parameter(function, parameter)));
1242        }
1243        let given = self.plan.expr_type(expr).clone();
1244        if given != *wanted {
1245            return Err(Error::not_implemented(format!(
1246                "the named parameter {parameter} given a {given} where a {wanted} was wanted"
1247            )));
1248        }
1249        Ok((parameter, value))
1250    }
1251
1252    /// A file where a table name goes, which is what DuckDB calls a replacement scan.
1253    ///
1254    /// `SELECT * FROM 'hits.parquet'` is how most DuckDB queries in the wild are written, ClickBench
1255    /// among them, so this is not sugar over `read_parquet` so much as the spelling people use. The
1256    /// catalog has already been asked and has already said no, and `missing` is what it said, so a
1257    /// name that is not a file comes back with the catalog's own answer rather than with a complaint
1258    /// about files.
1259    ///
1260    /// Only a single unqualified name is a candidate. A qualified one names a schema and a schema
1261    /// that does not exist is not a path.
1262    fn bind_replacement_scan(
1263        &mut self,
1264        ast: &Ast,
1265        parts: &[&str],
1266        alias: ast::StrRef,
1267        columns: ast::Slice,
1268        missing: Error,
1269    ) -> Result<(NodeRef, Scope)> {
1270        let [path] = parts else { return Err(missing) };
1271        let path = *path;
1272        let extension = path.rsplit_once('.').map(|(_, after)| after).unwrap_or_default();
1273        let Some(function) = Self::reader_for(extension) else {
1274            if is_file(path) {
1275                // A file that is really there and that nothing here can read is a different mistake
1276                // from a name that is not a file, and DuckDB says so with both lines, the second of
1277                // which is the way out. A file with no dot in it lands here too, which is why the
1278                // test is on the extension having a reader rather than on there being an extension.
1279                return Err(Error::binder(format!(
1280                    "No extension found that is capable of reading the file \"{path}\"\n* If this \
1281                     file is a supported file format you can explicitly use the reader functions, \
1282                     such as read_csv, read_json or read_parquet"
1283                )));
1284            }
1285            return Err(missing);
1286        };
1287        // The pattern is expanded before it is known to match anything, so a name that ends in .csv
1288        // and is not there gives the reader's own message rather than the catalog's. That is
1289        // DuckDB's order and it is the helpful one: somebody who wrote a file name wants to hear
1290        // about the file.
1291        let paths = files(path)?;
1292        let first = paths.first().map_or("", String::as_str);
1293        let fields = match function {
1294            TableFunction::ReadParquet => parquet_fields(first)?,
1295            _ => csv_fields(&paths, Given::default())?,
1296        };
1297        // The name the columns answer to is the file's stem, so `SELECT mixed.a FROM
1298        // 'data/mixed.parquet'` works. That is DuckDB's choice and it is the useful one, since the
1299        // alternative is a table name with a dot and a slash in it that nothing can write. A pattern
1300        // keeps the whole of what was written instead, which is DuckDB's choice too and was
1301        // measured: there is no stem to take when the name stands for a directory full of files.
1302        let label = if alias == NONE {
1303            if is_pattern(path) {
1304                path.to_string()
1305            } else {
1306                let file = path.rsplit_once('/').map_or(path, |(_, file)| file);
1307                file.rsplit_once('.').map_or(file, |(stem, _)| stem).to_string()
1308            }
1309        } else {
1310            ast.string(alias).to_string()
1311        };
1312        let arguments: Vec<ExprRef> = paths.iter().map(|path| self.path_constant(path)).collect();
1313        let names: Vec<&str> = ast.name(columns).collect();
1314        self.table_function_source(function, &arguments, &[], fields, &label, &names)
1315    }
1316
1317    /// One file name, as a constant expression in the plan.
1318    fn path_constant(&mut self, path: &str) -> ExprRef {
1319        let value = self.plan.add_value(Value::Varchar(path.to_string()));
1320        self.plan.add_expr(Expr::Constant(value), LogicalType::Varchar)
1321    }
1322
1323    /// The table function a file with this extension is read by, and `None` for one nothing reads.
1324    ///
1325    /// Both spellings of a tab separated file go to the CSV reader, which is not a shortcut: the
1326    /// extension picks the reader and the reader sniffs the punctuation, so a `.tsv` file that holds
1327    /// commas is read as commas. That was measured rather than assumed. The comparison ignores case
1328    /// because `UP.CSV` reads in duckdb v1.4.1.
1329    fn reader_for(extension: &str) -> Option<TableFunction> {
1330        if extension.eq_ignore_ascii_case("parquet") {
1331            return Some(TableFunction::ReadParquet);
1332        }
1333        if extension.eq_ignore_ascii_case("csv") || extension.eq_ignore_ascii_case("tsv") {
1334            return Some(TableFunction::ReadCsv);
1335        }
1336        None
1337    }
1338
1339    /// The node and the scope of a table function call whose arguments and columns are settled.
1340    ///
1341    /// The half a written out call shares with a replacement scan, which is everything after the
1342    /// question of what the file is called has been answered one way or the other.
1343    fn table_function_source(
1344        &mut self,
1345        function: TableFunction,
1346        args: &[ExprRef],
1347        written: &[(&'static str, Value, ExprRef)],
1348        fields: Vec<Field>,
1349        label: &str,
1350        names: &[&str],
1351    ) -> Result<(NodeRef, Scope)> {
1352        let index = self.fresh_index();
1353        let mut scope = Scope::empty();
1354        for (at, field) in fields.iter().enumerate() {
1355            scope.push(Visible {
1356                table: label.to_string(),
1357                name: field.name.clone(),
1358                binding: ColumnBinding::new(index, at as u32),
1359                ty: field.ty.clone(),
1360                // A reader takes what the file has, and no file format this reads says a column
1361                // cannot be null. The reference binary answers YES for every column of a Parquet.
1362                not_null: false,
1363            });
1364        }
1365        if !names.is_empty() {
1366            scope.rename(names, label)?;
1367        }
1368        let function = self.plan.intern(function.name());
1369        let args = self.plan.add_expr_list(args);
1370        let named: Vec<u32> =
1371            written.iter().map(|(parameter, _, _)| self.plan.intern(parameter)).collect();
1372        let settings: Vec<ExprRef> = written.iter().map(|(_, _, expr)| *expr).collect();
1373        let options = self.plan.add_name_list(&named);
1374        let settings = self.plan.add_expr_list(&settings);
1375        let columns = self.plan.add_fields(&fields);
1376        let node = self.plan.add_node(Node::TableFunction {
1377            index,
1378            function,
1379            args,
1380            options,
1381            settings,
1382            columns,
1383        });
1384        Ok((node, scope))
1385    }
1386
1387    /// Every file a table function's file argument names, in the order they were written.
1388    ///
1389    /// Each pattern has to find at least one file of its own, which is DuckDB's rule and is why
1390    /// this expands one at a time rather than gathering everything and looking at the total. A
1391    /// list keeps its written order and its duplicates, so a file named twice is read twice, which
1392    /// was measured: the sort and the dedup belong to one pattern rather than to the list.
1393    fn file_paths(&self, expr: ExprRef, name: &str) -> Result<Vec<String>> {
1394        let mut paths = Vec::new();
1395        for pattern in self.file_patterns(expr, name)? {
1396            paths.extend(files(&pattern)?);
1397        }
1398        Ok(paths)
1399    }
1400
1401    /// The patterns a table function argument names, which have to be constants.
1402    ///
1403    /// A table function that reads a file is resolved by opening the file, and that happens here
1404    /// rather than when the query runs, because the rest of the statement cannot bind until the
1405    /// column names are known. So the path has to be something this binder can work out without
1406    /// running anything, and a literal is that. DuckDB folds a constant expression first, so
1407    /// `read_parquet('a' || '.parquet')` works there, and folding is M1 work that this will pick up
1408    /// for free once the optimizer runs before the plan is finished rather than after.
1409    ///
1410    /// One string is one pattern and a list is one pattern an item, which is DuckDB's pair of
1411    /// overloads. A null is a different sentence in each of them, both of them measured.
1412    fn file_patterns(&self, expr: ExprRef, name: &str) -> Result<Vec<String>> {
1413        let Expr::Constant(reference) = *self.plan.expr(expr) else {
1414            return Err(Error::not_implemented(
1415                "a table function file name that is not a constant",
1416            ));
1417        };
1418        match self.plan.value(reference) {
1419            Value::Varchar(path) => Ok(vec![path.clone()]),
1420            // DuckDB's own wording, which says list because its other overload takes one.
1421            Value::Null => Err(Error::parser(format!("{name} cannot take NULL list as parameter"))),
1422            Value::List { values, .. } => values
1423                .iter()
1424                .map(|value| match value {
1425                    Value::Varchar(path) => Ok(path.clone()),
1426                    _ => Err(Error::parser(format!(
1427                        "{name} reader cannot take NULL input as parameter"
1428                    ))),
1429                })
1430                .collect(),
1431            other => {
1432                Err(Error::internal(format!("a file name bound as VARCHAR arrived as {other}")))
1433            }
1434        }
1435    }
1436
1437    #[allow(clippy::too_many_arguments)]
1438    fn bind_join(
1439        &mut self,
1440        ast: &Ast,
1441        left: ast::SourceRef,
1442        right: ast::SourceRef,
1443        kind: ast::JoinKind,
1444        natural: bool,
1445        on: ast::ExprRef,
1446        using: ast::Slice,
1447    ) -> Result<(NodeRef, Scope)> {
1448        let (left_node, left_scope) = self.bind_source(ast, left)?;
1449        let (right_node, right_scope) = self.bind_source(ast, right)?;
1450        let split = left_scope.len();
1451        let mut scope = left_scope.concat(right_scope);
1452
1453        // NATURAL is USING over whatever both sides happen to call the same thing, which is why it
1454        // is resolved here and never reaches the plan as its own idea.
1455        let merged: Vec<String> = if natural {
1456            let mut names = Vec::new();
1457            for (at, column) in scope.columns.iter().enumerate().take(split) {
1458                if scope.columns[split..].iter().any(|right| same_name(&right.name, &column.name))
1459                    && !names.iter().any(|held: &String| same_name(held, &column.name))
1460                {
1461                    let _ = at;
1462                    names.push(column.name.clone());
1463                }
1464            }
1465            names
1466        } else {
1467            // A name written twice is one column, not two. `USING (id, id)` is legal and means what
1468            // `USING (id)` means, and the reference binary agrees. Taking it twice would build the
1469            // same equality twice and, worse, drop the right side's copy twice, which takes a
1470            // column out of the answer that nobody named and runs off the end of the scope when the
1471            // copy was the last column in it.
1472            let mut names: Vec<String> = Vec::new();
1473            for name in ast.name(using) {
1474                if !names.iter().any(|held| same_name(held, name)) {
1475                    names.push(name.to_string());
1476                }
1477            }
1478            names
1479        };
1480
1481        let mut conditions = Vec::new();
1482        let mut dropped = Vec::new();
1483        for name in &merged {
1484            let left_at = scope.columns[..split]
1485                .iter()
1486                .position(|column| same_name(&column.name, name))
1487                .ok_or_else(|| {
1488                    Error::binder(format!(
1489                        "column \"{name}\" specified in USING clause does not exist in left table"
1490                    ))
1491                })?;
1492            let right_at = scope.columns[split..]
1493                .iter()
1494                .position(|column| same_name(&column.name, name))
1495                .map(|at| at + split)
1496                .ok_or_else(|| {
1497                    Error::binder(format!(
1498                        "column \"{name}\" specified in USING clause does not exist in right table"
1499                    ))
1500                })?;
1501            let left_column = &scope.columns[left_at];
1502            let (left_binding, left_type) = (left_column.binding, left_column.ty.clone());
1503            let right_column = &scope.columns[right_at];
1504            let (right_binding, right_type) = (right_column.binding, right_column.ty.clone());
1505            let left_expr = self.plan.add_expr(Expr::Column(left_binding), left_type);
1506            let right_expr = self.plan.add_expr(Expr::Column(right_binding), right_type);
1507            conditions.push(self.compare(rudb_plan::CompareOp::Equal, left_expr, right_expr)?);
1508            dropped.push(right_at);
1509        }
1510        // A joined-on column appears once, so the right side's copy goes. Dropping from the back
1511        // keeps the positions of the ones still to drop correct.
1512        dropped.sort_unstable();
1513        for at in dropped.into_iter().rev() {
1514            scope.remove(at);
1515        }
1516
1517        if on != NONE {
1518            if !merged.is_empty() {
1519                return Err(Error::binder("a join cannot have both ON and USING"));
1520            }
1521            self.clause = "JOIN condition";
1522            let predicate = self.bind_expr(ast, on, &scope)?;
1523            conditions.push(self.as_boolean(predicate, "JOIN")?);
1524        }
1525
1526        if kind == ast::JoinKind::Cross {
1527            if !conditions.is_empty() {
1528                return Err(Error::binder("a CROSS JOIN cannot have a condition"));
1529            }
1530            let node =
1531                self.plan.add_node(Node::CrossProduct { left: left_node, right: right_node });
1532            return Ok((node, scope));
1533        }
1534        if conditions.is_empty() && kind == ast::JoinKind::Inner {
1535            let node =
1536                self.plan.add_node(Node::CrossProduct { left: left_node, right: right_node });
1537            return Ok((node, scope));
1538        }
1539        let kind = match kind {
1540            ast::JoinKind::Inner | ast::JoinKind::Cross => JoinKind::Inner,
1541            ast::JoinKind::Left => JoinKind::Left,
1542            ast::JoinKind::Right => JoinKind::Right,
1543            ast::JoinKind::Full => JoinKind::Full,
1544            ast::JoinKind::Semi => JoinKind::Semi,
1545            ast::JoinKind::Anti => JoinKind::Anti,
1546            ast::JoinKind::Positional => JoinKind::Positional,
1547        };
1548        let conditions = self.plan.add_expr_list(&conditions);
1549        let node =
1550            self.plan.add_node(Node::Join { left: left_node, right: right_node, kind, conditions });
1551        Ok((node, scope))
1552    }
1553
1554    // -------------------------------------------------------------- aggregates
1555
1556    /// Binds an aggregate call, records it, and hands back a reference to where its result lands.
1557    pub(crate) fn bind_aggregate(
1558        &mut self,
1559        ast: &Ast,
1560        name: &str,
1561        args: &[ast::ExprRef],
1562        distinct: bool,
1563        scope: &Scope,
1564    ) -> Result<ExprRef> {
1565        if self.in_aggregate {
1566            return Err(Error::binder(format!(
1567                "aggregate function calls cannot be nested, and {name}() is inside one"
1568            )));
1569        }
1570        if self.aggregation.is_none() {
1571            return Err(Error::binder(format!(
1572                "aggregate function calls cannot be used in the {}",
1573                self.clause
1574            )));
1575        }
1576        self.in_aggregate = true;
1577        let mut bound = Vec::with_capacity(args.len());
1578        let mut failure = None;
1579        for &arg in args {
1580            match self.bind_expr(ast, arg, scope) {
1581                Ok(expr) => bound.push(expr),
1582                Err(error) => {
1583                    failure = Some(error);
1584                    break;
1585                }
1586            }
1587        }
1588        self.in_aggregate = false;
1589        if let Some(error) = failure {
1590            return Err(error);
1591        }
1592
1593        let types: Vec<LogicalType> =
1594            bound.iter().map(|&arg| self.plan.expr_type(arg).clone()).collect();
1595        let resolved = resolve(name, &types)?;
1596        let mut cast = Vec::with_capacity(bound.len());
1597        for (arg, wanted) in bound.iter().zip(&resolved.arguments) {
1598            cast.push(self.cast_to(*arg, wanted));
1599        }
1600        let args = self.plan.add_expr_list(&cast);
1601        let name = self.plan.intern(resolved.name);
1602        let ty = resolved.returns;
1603        let call =
1604            self.plan.add_expr(Expr::Aggregate { name, args, distinct, filter: None }, ty.clone());
1605
1606        // Two identical aggregates are one column of the aggregate's output. `SELECT sum(x),
1607        // sum(x) / count(*)` computes one sum, not two.
1608        let existing = self.aggregation.as_ref().map(|held| held.aggregates.clone());
1609        let existing = existing.unwrap_or_default();
1610        let at = match existing.iter().position(|&held| self.same_expr(held, call)) {
1611            Some(at) => at,
1612            None => {
1613                let aggregation = self.aggregation.as_mut().expect("checked above");
1614                aggregation.aggregates.push(call);
1615                aggregation.aggregates.len() - 1
1616            }
1617        };
1618        let aggregation = self.aggregation.as_ref().expect("checked above");
1619        let (index, groups) = (aggregation.index, aggregation.groups.len());
1620        Ok(self.column(index, groups + at, ty))
1621    }
1622
1623    /// Rewrites a bound expression into one the aggregate's output can answer.
1624    ///
1625    /// A subexpression that is one of the group expressions becomes a reference to that group. A
1626    /// column that is neither grouped nor inside an aggregate is the error every SQL user has seen,
1627    /// and it is reported here because this is the first point where it is knowable.
1628    pub(crate) fn over_aggregate(&mut self, expr: ExprRef, scope: &Scope) -> Result<ExprRef> {
1629        let Some(aggregation) = self.aggregation.as_ref() else {
1630            return Ok(expr);
1631        };
1632        let index = aggregation.index;
1633        let groups = aggregation.groups.clone();
1634        for (at, group) in groups.iter().enumerate() {
1635            if self.same_expr(expr, *group) {
1636                let ty = self.plan.expr_type(*group).clone();
1637                return Ok(self.column(index, at, ty));
1638            }
1639        }
1640        let ty = self.plan.expr_type(expr).clone();
1641        match self.plan.expr(expr).clone() {
1642            Expr::Column(binding) if binding.table == index => Ok(expr),
1643            Expr::Column(binding) => {
1644                let name =
1645                    scope.columns.iter().find(|column| column.binding == binding).map_or_else(
1646                        || "a column".to_string(),
1647                        |column| format!("\"{}\"", column.name),
1648                    );
1649                Err(Error::binder(format!(
1650                    "column {name} must appear in the GROUP BY clause or must be part of an aggregate function"
1651                )))
1652            }
1653            Expr::Constant(_) | Expr::Aggregate { .. } => Ok(expr),
1654            Expr::Cast { input, try_cast } => {
1655                let input = self.over_aggregate(input, scope)?;
1656                Ok(self.plan.add_expr(Expr::Cast { input, try_cast }, ty))
1657            }
1658            Expr::Compare { op, left, right } => {
1659                let left = self.over_aggregate(left, scope)?;
1660                let right = self.over_aggregate(right, scope)?;
1661                Ok(self.plan.add_expr(Expr::Compare { op, left, right }, ty))
1662            }
1663            Expr::Conjunction { op, children } => {
1664                let written = self.plan.expr_list(children).to_vec();
1665                let mut rewritten = Vec::with_capacity(written.len());
1666                for child in written {
1667                    rewritten.push(self.over_aggregate(child, scope)?);
1668                }
1669                let children = self.plan.add_expr_list(&rewritten);
1670                Ok(self.plan.add_expr(Expr::Conjunction { op, children }, ty))
1671            }
1672            Expr::Function { name, args } => {
1673                let written = self.plan.expr_list(args).to_vec();
1674                let mut rewritten = Vec::with_capacity(written.len());
1675                for arg in written {
1676                    rewritten.push(self.over_aggregate(arg, scope)?);
1677                }
1678                let args = self.plan.add_expr_list(&rewritten);
1679                Ok(self.plan.add_expr(Expr::Function { name, args }, ty))
1680            }
1681            Expr::Case { arms, otherwise } => {
1682                let written = self.plan.arm_list(arms).to_vec();
1683                let mut rewritten = Vec::with_capacity(written.len());
1684                for arm in written {
1685                    let when = self.over_aggregate(arm.when, scope)?;
1686                    let then = self.over_aggregate(arm.then, scope)?;
1687                    rewritten.push(rudb_plan::Arm { when, then });
1688                }
1689                let otherwise = match otherwise {
1690                    Some(expr) => Some(self.over_aggregate(expr, scope)?),
1691                    None => None,
1692                };
1693                let arms = self.plan.add_arms(&rewritten);
1694                Ok(self.plan.add_expr(Expr::Case { arms, otherwise }, ty))
1695            }
1696        }
1697    }
1698
1699    /// Whether two bound expressions are the same expression, by shape rather than by reference.
1700    pub(crate) fn same_expr(&self, left: ExprRef, right: ExprRef) -> bool {
1701        same_expr(&self.plan, left, right)
1702    }
1703}
1704
1705/// The named parameters a table function call was written with.
1706///
1707/// A struct rather than the fields loose, because the seventeen DuckDB has on `read_parquet` and the
1708/// thirty on `read_csv` are all going to want somewhere to go, and because a call with none of them
1709/// written should read as the default of this rather than as a bare false somewhere.
1710///
1711/// The CSV half goes on to the reader and is opened with, here and again in the executor. The
1712/// Parquet half is answered here and nothing downstream sees it, which is what `binary_as_string`
1713/// turning a BLOB column into a VARCHAR one is.
1714#[derive(Debug, Default)]
1715struct Options {
1716    /// `binary_as_string`, which says an unannotated byte array column in a Parquet file holds
1717    /// text. The ClickBench file has twenty eight of those and every query reads them as strings.
1718    binary_as_string: bool,
1719    /// `all_varchar`, which reads every column of a CSV file as text rather than sniffing a type.
1720    all_varchar: bool,
1721    /// `file_row_number`, which adds a column holding each row's ordinal inside its own file.
1722    ///
1723    /// The one Parquet option here that the executor has to act on rather than the binder, since
1724    /// the column is not in the file and has to be counted as the rows come out of it.
1725    file_row_number: bool,
1726    /// `delim`, `sep`, `quote`, `escape` and `header`, which are what the sniffer would decide.
1727    given: Given,
1728}
1729
1730impl Options {
1731    /// What these named parameters add up to.
1732    ///
1733    /// Each one was already checked against the function's list, so a name in here is a name that
1734    /// function takes and the value is already the type it wants. What is left is reading them, and
1735    /// the last one written wins, which is DuckDB's answer to `delim='|', delim=','` and was
1736    /// measured rather than assumed.
1737    fn of(written: &[(&'static str, Value, ExprRef)]) -> Result<Self> {
1738        let mut options = Self::default();
1739        for (parameter, value, _) in written {
1740            match (*parameter, value) {
1741                ("binary_as_string", Value::Boolean(on)) => options.binary_as_string = *on,
1742                ("all_varchar", Value::Boolean(on)) => options.all_varchar = *on,
1743                ("file_row_number", Value::Boolean(on)) => options.file_row_number = *on,
1744                _ => {}
1745            }
1746        }
1747        let named: Vec<(&str, Value)> =
1748            written.iter().map(|(parameter, value, _)| (*parameter, value.clone())).collect();
1749        options.given = csv_given(&named)?;
1750        Ok(options)
1751    }
1752}
1753
1754/// DuckDB's complaint about a named parameter that was given a null, which is a different sentence
1755/// for almost every parameter.
1756///
1757/// Three of them were measured on `v2.0.0-dev84237` and no two agree: `binary_as_string` is the
1758/// first, `all_varchar` is the second and `header` is the third. They read like three people each
1759/// writing the message in front of them, which is what they are, and a harness that compares error
1760/// text compares all of it. Anything not measured gets the first one, which is the most general of
1761/// the three.
1762fn null_parameter(function: TableFunction, parameter: &str) -> String {
1763    match parameter {
1764        "header" => format!("\"{parameter}\" expects a non-null boolean value (e.g. TRUE or 1)"),
1765        "all_varchar" => format!("{} \"{parameter}\" cannot be NULL", function.name()),
1766        _ => format!("Cannot use NULL as argument to \"{parameter}\""),
1767    }
1768}
1769
1770/// The complaint about a `REPLACE` entry that named a column the star did not stand for.
1771///
1772/// It reads like the complaint about any other name that is not there, down to the list of names
1773/// that are, because from the writer's side it is the same mistake.
1774fn missing_replacement(name: &str, input: &Scope) -> Error {
1775    Error::binder(format!(
1776        "Column \"{name}\" in REPLACE list not found in FROM clause{}",
1777        input.candidates()
1778    ))
1779}
1780
1781/// A sort key with SQL's defaults filled in.
1782///
1783/// Unstated is ascending, and unstated nulls go where the direction puts them, which is last for
1784/// ascending and first for descending. That is DuckDB's rule and it is the one that makes
1785/// `ORDER BY x DESC` the exact reverse of `ORDER BY x`.
1786fn sort_key(expr: ExprRef, item: ast::OrderItem) -> SortKey {
1787    let descending = item.order == Order::Descending;
1788    let nulls_first = match item.nulls {
1789        Nulls::First => true,
1790        Nulls::Last => false,
1791        Nulls::Unstated => descending,
1792    };
1793    SortKey { expr, descending, nulls_first }
1794}
1795
1796/// Structural equality over two expressions of one plan.
1797fn same_expr(plan: &Plan, left: ExprRef, right: ExprRef) -> bool {
1798    if left == right {
1799        return true;
1800    }
1801    if plan.expr_type(left) != plan.expr_type(right) {
1802        return false;
1803    }
1804    let lists = |left, right| {
1805        let left: &[ExprRef] = plan.expr_list(left);
1806        let right: &[ExprRef] = plan.expr_list(right);
1807        left.len() == right.len()
1808            && left.iter().zip(right).all(|(&left, &right)| same_expr(plan, left, right))
1809    };
1810    match (plan.expr(left), plan.expr(right)) {
1811        (Expr::Column(left), Expr::Column(right)) => left == right,
1812        (Expr::Constant(left), Expr::Constant(right)) => plan.value(*left) == plan.value(*right),
1813        (
1814            Expr::Cast { input: left, try_cast: left_try },
1815            Expr::Cast { input: right, try_cast: right_try },
1816        ) => left_try == right_try && same_expr(plan, *left, *right),
1817        (
1818            Expr::Compare { op: left_op, left: left_a, right: left_b },
1819            Expr::Compare { op: right_op, left: right_a, right: right_b },
1820        ) => {
1821            left_op == right_op
1822                && same_expr(plan, *left_a, *right_a)
1823                && same_expr(plan, *left_b, *right_b)
1824        }
1825        (
1826            Expr::Conjunction { op: left_op, children: left_children },
1827            Expr::Conjunction { op: right_op, children: right_children },
1828        ) => left_op == right_op && lists(*left_children, *right_children),
1829        (
1830            Expr::Function { name: left_name, args: left_args },
1831            Expr::Function { name: right_name, args: right_args },
1832        ) => plan.string(*left_name) == plan.string(*right_name) && lists(*left_args, *right_args),
1833        (
1834            Expr::Aggregate {
1835                name: left_name,
1836                args: left_args,
1837                distinct: left_distinct,
1838                filter: left_filter,
1839            },
1840            Expr::Aggregate {
1841                name: right_name,
1842                args: right_args,
1843                distinct: right_distinct,
1844                filter: right_filter,
1845            },
1846        ) => {
1847            plan.string(*left_name) == plan.string(*right_name)
1848                && left_distinct == right_distinct
1849                && match (left_filter, right_filter) {
1850                    (None, None) => true,
1851                    (Some(left), Some(right)) => same_expr(plan, *left, *right),
1852                    _ => false,
1853                }
1854                && lists(*left_args, *right_args)
1855        }
1856        (
1857            Expr::Case { arms: left_arms, otherwise: left_otherwise },
1858            Expr::Case { arms: right_arms, otherwise: right_otherwise },
1859        ) => {
1860            let left_arms = plan.arm_list(*left_arms);
1861            let right_arms = plan.arm_list(*right_arms);
1862            left_arms.len() == right_arms.len()
1863                && left_arms.iter().zip(right_arms).all(|(left, right)| {
1864                    same_expr(plan, left.when, right.when) && same_expr(plan, left.then, right.then)
1865                })
1866                && match (left_otherwise, right_otherwise) {
1867                    (None, None) => true,
1868                    (Some(left), Some(right)) => same_expr(plan, *left, *right),
1869                    _ => false,
1870                }
1871        }
1872        _ => false,
1873    }
1874}