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, same_name};
16use rudb_common::{Error, Field, LogicalType, Result, Value};
17use rudb_functions::{Columns, TableFunction, parquet_fields, resolve, resolve_table};
18use rudb_parse::ast::{self, Ast, Distinct, LiteralKind, Nulls, Order, Quantifier, SetOp};
19use rudb_parse::{NONE, parse_ast};
20use rudb_plan::{ColumnBinding, Expr, ExprRef, JoinKind, Node, NodeRef, Plan, SetOpKind, SortKey};
21
22use crate::expr::{describe, has_aggregate};
23use crate::scope::{Scope, Visible};
24
25/// Binds a parsed statement against a catalog.
26///
27/// # Errors
28///
29/// If the script does not hold exactly one statement, if a name does not resolve, if a type does
30/// not work out, or if the query uses something M0 does not bind yet.
31pub fn bind(ast: &Ast, catalog: &Catalog) -> Result<Plan> {
32    let query = match ast.statements.as_slice() {
33        [ast::Statement::Query(query)] => *query,
34        [] => return Err(Error::binder("no statement to bind")),
35        _ => return Err(Error::not_implemented("a script of more than one statement")),
36    };
37    let mut binder = Binder::new(catalog);
38    let (root, _) = binder.bind_query(ast, query)?;
39    let mut plan = binder.into_plan();
40    plan.set_root(root);
41    plan.validate()?;
42    Ok(plan)
43}
44
45/// Parses and binds one query, which is the whole front end in one call.
46///
47/// # Errors
48///
49/// Anything the parser or the binder reports.
50pub fn bind_sql(query: &str, catalog: &Catalog) -> Result<Plan> {
51    let ast = parse_ast(query)?;
52    bind(&ast, catalog)
53}
54
55/// What an aggregating select block has decided so far.
56#[derive(Debug)]
57pub(crate) struct Aggregation {
58    /// The table index the aggregate's output binds against.
59    pub(crate) index: u32,
60    /// The group expressions, over the input, which are the first output columns.
61    pub(crate) groups: Vec<ExprRef>,
62    /// The aggregate calls found so far, which follow the groups in the output.
63    pub(crate) aggregates: Vec<ExprRef>,
64}
65
66/// The state one binding run carries.
67#[derive(Debug)]
68pub(crate) struct Binder<'a> {
69    catalog: &'a Catalog,
70    plan: Plan,
71    next_index: u32,
72    /// Set while a select block aggregates, which changes what a bare column means.
73    pub(crate) aggregation: Option<Aggregation>,
74    /// Set while an aggregate's own arguments are being bound, so nesting is caught.
75    pub(crate) in_aggregate: bool,
76    /// Where we are, for an error message that says which clause the writer should look at.
77    pub(crate) clause: &'static str,
78}
79
80impl<'a> Binder<'a> {
81    pub(crate) fn new(catalog: &'a Catalog) -> Self {
82        Self {
83            catalog,
84            plan: Plan::new(),
85            next_index: 0,
86            aggregation: None,
87            in_aggregate: false,
88            clause: "SELECT clause",
89        }
90    }
91
92    pub(crate) fn plan(&self) -> &Plan {
93        &self.plan
94    }
95
96    pub(crate) fn plan_mut(&mut self) -> &mut Plan {
97        &mut self.plan
98    }
99
100    pub(crate) fn into_plan(self) -> Plan {
101        self.plan
102    }
103
104    /// A table index nothing else has.
105    pub(crate) fn fresh_index(&mut self) -> u32 {
106        let index = self.next_index;
107        self.next_index += 1;
108        index
109    }
110
111    /// A reference to one column of an operator's output.
112    fn column(&mut self, index: u32, position: usize, ty: LogicalType) -> ExprRef {
113        let binding = ColumnBinding::new(index, position as u32);
114        self.plan.add_expr(Expr::Column(binding), ty)
115    }
116
117    // ---------------------------------------------------------------- queries
118
119    pub(crate) fn bind_query(
120        &mut self,
121        ast: &Ast,
122        query: ast::QueryRef,
123    ) -> Result<(NodeRef, Scope)> {
124        let written = ast.query(query);
125        match written.body {
126            ast::QueryBody::Select(select) => self.bind_select(ast, select, &written),
127            ast::QueryBody::SetOp { op, quantifier, by_name, left, right } => {
128                if by_name {
129                    return Err(Error::not_implemented("UNION BY NAME"));
130                }
131                self.bind_set_op(ast, &written, op, quantifier, left, right)
132            }
133            ast::QueryBody::Values(rows) => self.bind_values(ast, &written, rows),
134        }
135    }
136
137    /// `VALUES (1, 'a'), (2, 'b')`, as a query in its own right.
138    ///
139    /// The column names are `col0`, `col1` and so on, which is what DuckDB calls them, and the
140    /// column types are what every row in that position promotes to. Promotion is the same rule a
141    /// set operation uses, and for the same reason: a column has one type and the rows have to
142    /// agree on it before anything downstream can read the column.
143    fn bind_values(
144        &mut self,
145        ast: &Ast,
146        query: &ast::Query,
147        rows: ast::Slice,
148    ) -> Result<(NodeRef, Scope)> {
149        let written = ast.rows(rows).to_vec();
150        let Some(first) = written.first() else {
151            return Err(Error::binder("VALUES needs at least one row"));
152        };
153        let width = first.len as usize;
154        for (at, row) in written.iter().enumerate() {
155            if row.len as usize != width {
156                return Err(Error::binder(format!(
157                    "VALUES lists must all be the same length, expected {width} columns but row {} has {}",
158                    at + 1,
159                    row.len
160                )));
161            }
162        }
163        // A row of a `VALUES` cannot see a column, because there is nothing under it to see.
164        let empty = Scope::empty();
165        let previous = std::mem::replace(&mut self.clause, "VALUES clause");
166        let mut bound: Vec<Vec<ExprRef>> = Vec::with_capacity(written.len());
167        for row in &written {
168            let mut items = Vec::with_capacity(width);
169            for &expr in ast.expr_list(*row) {
170                items.push(self.bind_expr(ast, expr, &empty)?);
171            }
172            bound.push(items);
173        }
174        self.clause = previous;
175        let mut types = Vec::with_capacity(width);
176        for at in 0..width {
177            let mut ty = self.plan.expr_type(bound[0][at]).clone();
178            for row in &bound[1..] {
179                let other = self.plan.expr_type(row[at]).clone();
180                ty = ty.promote(&other).ok_or_else(|| {
181                    Error::binder(format!(
182                        "Cannot combine a value of type {ty} with a value of type {other} in column {} of a VALUES",
183                        at + 1
184                    ))
185                })?;
186            }
187            types.push(ty);
188        }
189        let mut slices = Vec::with_capacity(bound.len());
190        for row in &bound {
191            let items: Vec<ExprRef> =
192                row.iter().zip(&types).map(|(&expr, ty)| self.cast_to(expr, ty)).collect();
193            slices.push(self.plan.add_expr_list(&items));
194        }
195        let rows = self.plan.add_rows(&slices);
196        let fields: Vec<Field> = types
197            .iter()
198            .enumerate()
199            .map(|(at, ty)| Field::new(format!("col{at}"), ty.clone()))
200            .collect();
201        let columns = self.plan.add_fields(&fields);
202        let index = self.fresh_index();
203        let mut node = self.plan.add_node(Node::Values { index, columns, rows });
204        let mut scope = Scope::empty();
205        for (at, field) in fields.iter().enumerate() {
206            scope.push(Visible {
207                table: String::new(),
208                name: field.name.clone(),
209                binding: ColumnBinding::new(index, at as u32),
210                ty: field.ty.clone(),
211            });
212        }
213        let keys = self.sort_keys(ast, query, &scope, &[])?;
214        if !keys.is_empty() {
215            let keys = self.plan.add_sort_keys(&keys);
216            node = self.plan.add_node(Node::Sort { input: node, keys });
217        }
218        node = self.apply_limit(ast, query, node)?;
219        Ok((node, scope))
220    }
221
222    fn bind_set_op(
223        &mut self,
224        ast: &Ast,
225        query: &ast::Query,
226        op: SetOp,
227        quantifier: Quantifier,
228        left: ast::QueryRef,
229        right: ast::QueryRef,
230    ) -> Result<(NodeRef, Scope)> {
231        let (left_node, left_scope) = self.bind_query(ast, left)?;
232        let (right_node, right_scope) = self.bind_query(ast, right)?;
233        if left_scope.len() != right_scope.len() {
234            return Err(Error::binder(format!(
235                "Set operations can only apply to expressions with the same number of result columns, but left side has {} and right side has {}",
236                left_scope.len(),
237                right_scope.len()
238            )));
239        }
240        // Both sides have to hand back one set of types, so each column meets the other side's.
241        let mut types = Vec::with_capacity(left_scope.len());
242        for (left, right) in left_scope.columns.iter().zip(&right_scope.columns) {
243            let common = left.ty.promote(&right.ty).ok_or_else(|| {
244                Error::binder(format!(
245                    "Cannot combine a column of type {} with a column of type {} in a set operation",
246                    left.ty, right.ty
247                ))
248            })?;
249            types.push(common);
250        }
251        let left_node = self.conform(left_node, &left_scope, &types);
252        let right_node = self.conform(right_node, &right_scope, &types);
253        let index = self.fresh_index();
254        let kind = match op {
255            SetOp::Union => SetOpKind::Union,
256            SetOp::Except => SetOpKind::Except,
257            SetOp::Intersect => SetOpKind::Intersect,
258        };
259        // UNION alone removes duplicates and UNION ALL keeps them, which is the one place the
260        // unwritten quantifier and ALL disagree.
261        let all = quantifier == Quantifier::All;
262        let mut node = self.plan.add_node(Node::SetOp {
263            left: left_node,
264            right: right_node,
265            kind,
266            all,
267            index,
268        });
269        let mut scope = Scope::empty();
270        for (at, (column, ty)) in left_scope.columns.iter().zip(&types).enumerate() {
271            scope.push(Visible {
272                table: String::new(),
273                name: column.name.clone(),
274                binding: ColumnBinding::new(index, at as u32),
275                ty: ty.clone(),
276            });
277        }
278        // Above a set operation there is nothing but the output columns, so an ORDER BY term is
279        // either a position, an output name, or an expression over the output, and never needs a
280        // column projected for it that the query did not ask for.
281        let keys = self.sort_keys(ast, query, &scope, &[])?;
282        if !keys.is_empty() {
283            let keys = self.plan.add_sort_keys(&keys);
284            node = self.plan.add_node(Node::Sort { input: node, keys });
285        }
286        node = self.apply_limit(ast, query, node)?;
287        Ok((node, scope))
288    }
289
290    /// Projects one side of a set operation so that its columns have the agreed types.
291    fn conform(&mut self, node: NodeRef, scope: &Scope, types: &[LogicalType]) -> NodeRef {
292        if scope.columns.iter().zip(types).all(|(column, ty)| &column.ty == ty) {
293            return node;
294        }
295        let index = self.fresh_index();
296        let mut exprs = Vec::with_capacity(types.len());
297        let mut names = Vec::with_capacity(types.len());
298        for (column, ty) in scope.columns.iter().zip(types) {
299            let expr = self.plan.add_expr(Expr::Column(column.binding), column.ty.clone());
300            exprs.push(self.cast_to(expr, ty));
301            names.push(self.plan.intern(&column.name));
302        }
303        let exprs = self.plan.add_expr_list(&exprs);
304        let names = self.plan.add_name_list(&names);
305        self.plan.add_node(Node::Project { input: node, index, exprs, names })
306    }
307
308    // ----------------------------------------------------------------- select
309
310    fn bind_select(
311        &mut self,
312        ast: &Ast,
313        select: ast::SelectRef,
314        query: &ast::Query,
315    ) -> Result<(NodeRef, Scope)> {
316        let written = ast.select(select);
317        let (mut node, input) = self.bind_from(ast, written.from)?;
318
319        if written.filter != NONE {
320            self.clause = "WHERE clause";
321            let predicate = self.bind_expr(ast, written.filter, &input)?;
322            let predicate = self.as_boolean(predicate, "WHERE")?;
323            node = self.plan.add_node(Node::Filter { input: node, predicate });
324        }
325
326        let targets = ast.target_list(written.targets).to_vec();
327        if targets.is_empty() {
328            return Err(Error::binder("a SELECT needs at least one expression to select"));
329        }
330
331        let group_items = self.group_items(ast, &written, &targets)?;
332        let aggregating = !group_items.is_empty()
333            || written.having != NONE
334            || targets.iter().any(|target| has_aggregate(ast, target.expr));
335        if aggregating {
336            self.clause = "GROUP BY clause";
337            let mut groups = Vec::with_capacity(group_items.len());
338            for item in &group_items {
339                groups.push(self.bind_expr(ast, *item, &input)?);
340            }
341            let index = self.fresh_index();
342            self.aggregation = Some(Aggregation { index, groups, aggregates: Vec::new() });
343        }
344
345        self.clause = "SELECT clause";
346        let (mut exprs, mut names) = self.bind_targets(ast, &targets, &input)?;
347        let visible = exprs.len();
348
349        let mut having = None;
350        if written.having != NONE {
351            self.clause = "HAVING clause";
352            let predicate = self.bind_expr(ast, written.having, &input)?;
353            let predicate = self.over_aggregate(predicate, &input)?;
354            having = Some(self.as_boolean(predicate, "HAVING")?);
355        }
356
357        // The projection's index has to exist before the sort keys are built, because a key is a
358        // reference to a projected column even when the expression it sorts on is not selected.
359        let project = self.fresh_index();
360        let mut output = Scope::empty();
361        for (at, (expr, name)) in exprs.iter().zip(&names).enumerate() {
362            output.push(Visible {
363                table: String::new(),
364                name: name.clone(),
365                binding: ColumnBinding::new(project, at as u32),
366                ty: self.plan.expr_type(*expr).clone(),
367            });
368        }
369
370        self.clause = "ORDER BY clause";
371        let mut extra = Vec::new();
372        let keys = self.select_sort_keys(
373            ast, query, &input, &output, project, &mut exprs, &mut names, &mut extra,
374        )?;
375        if !extra.is_empty() && written.distinct != Distinct::No {
376            return Err(Error::binder(
377                "For SELECT DISTINCT, ORDER BY expressions must appear in the select list",
378            ));
379        }
380        let on = self.distinct_on(ast, written.distinct, &output)?;
381
382        if let Some(aggregation) = self.aggregation.take() {
383            let index = aggregation.index;
384            let groups = self.plan.add_expr_list(&aggregation.groups);
385            let aggregates = self.plan.add_expr_list(&aggregation.aggregates);
386            node = self.plan.add_node(Node::Aggregate { input: node, index, groups, aggregates });
387        }
388        if let Some(predicate) = having {
389            node = self.plan.add_node(Node::Filter { input: node, predicate });
390        }
391
392        let interned: Vec<u32> = names.iter().map(|name| self.plan.intern(name)).collect();
393        let exprs_slice = self.plan.add_expr_list(&exprs);
394        let names_slice = self.plan.add_name_list(&interned);
395        node = self.plan.add_node(Node::Project {
396            input: node,
397            index: project,
398            exprs: exprs_slice,
399            names: names_slice,
400        });
401
402        if written.distinct != Distinct::No {
403            let on = self.plan.add_expr_list(&on);
404            node = self.plan.add_node(Node::Distinct { input: node, on });
405        }
406        if !keys.is_empty() {
407            let keys = self.plan.add_sort_keys(&keys);
408            node = self.plan.add_node(Node::Sort { input: node, keys });
409        }
410        node = self.apply_limit(ast, query, node)?;
411
412        if extra.is_empty() {
413            output.columns.truncate(visible);
414            return Ok((node, output));
415        }
416        // An expression sorted on but not selected was carried this far to make the sort possible,
417        // and now it goes, because the query did not ask for it.
418        let index = self.fresh_index();
419        let mut kept = Vec::with_capacity(visible);
420        let mut kept_names = Vec::with_capacity(visible);
421        let mut scope = Scope::empty();
422        for (at, name) in names.iter().enumerate().take(visible) {
423            let ty = output.columns[at].ty.clone();
424            kept.push(self.column(project, at, ty.clone()));
425            kept_names.push(self.plan.intern(name));
426            scope.push(Visible {
427                table: String::new(),
428                name: name.clone(),
429                binding: ColumnBinding::new(index, at as u32),
430                ty,
431            });
432        }
433        let exprs = self.plan.add_expr_list(&kept);
434        let names = self.plan.add_name_list(&kept_names);
435        node = self.plan.add_node(Node::Project { input: node, index, exprs, names });
436        Ok((node, scope))
437    }
438
439    /// Binds the target list, expanding every star into the columns it stands for.
440    fn bind_targets(
441        &mut self,
442        ast: &Ast,
443        targets: &[ast::Target],
444        input: &Scope,
445    ) -> Result<(Vec<ExprRef>, Vec<String>)> {
446        let mut exprs = Vec::with_capacity(targets.len());
447        let mut names = Vec::with_capacity(targets.len());
448        for target in targets {
449            if let ast::Expr::Star { qualifier } = ast.expr(target.expr) {
450                let table = ast.name(qualifier).last().map(str::to_string);
451                let expanded: Vec<Visible> =
452                    input.star(table.as_deref())?.into_iter().cloned().collect();
453                for column in expanded {
454                    let expr = self.plan.add_expr(Expr::Column(column.binding), column.ty);
455                    exprs.push(self.over_aggregate(expr, input)?);
456                    names.push(column.name);
457                }
458                continue;
459            }
460            let expr = self.bind_expr(ast, target.expr, input)?;
461            exprs.push(self.over_aggregate(expr, input)?);
462            names.push(if target.alias == NONE {
463                self.output_name(ast, target.expr, input)
464            } else {
465                ast.string(target.alias).to_string()
466            });
467        }
468        Ok((exprs, names))
469    }
470
471    /// The name an unaliased target gets.
472    ///
473    /// A bare column keeps the spelling the table was created with rather than the spelling the
474    /// query used, so `SELECT USERID FROM hits` has a column called `UserID`. Identifiers match
475    /// without regard to case and the catalog is the one that holds the case.
476    fn output_name(&self, ast: &Ast, target: ast::ExprRef, input: &Scope) -> String {
477        if let ast::Expr::Column { name } = ast.expr(target) {
478            let parts: Vec<&str> = ast.name(name).collect();
479            if let Ok(found) = input.resolve(&parts) {
480                return found.name.clone();
481            }
482        }
483        describe(ast, target)
484    }
485
486    /// The expressions a `GROUP BY` clause names, with positions and output aliases followed.
487    fn group_items(
488        &self,
489        ast: &Ast,
490        select: &ast::Select,
491        targets: &[ast::Target],
492    ) -> Result<Vec<ast::ExprRef>> {
493        if select.group_by_all {
494            // GROUP BY ALL means every target that is not itself an aggregate, which is the set
495            // that would otherwise have to be written out again by hand.
496            return Ok(targets
497                .iter()
498                .filter(|target| !has_aggregate(ast, target.expr))
499                .map(|target| target.expr)
500                .collect());
501        }
502        let mut items = Vec::new();
503        for &item in ast.expr_list(select.group_by) {
504            items.push(self.output_reference(ast, item, targets, "GROUP BY")?.unwrap_or(item));
505        }
506        Ok(items)
507    }
508
509    /// The target a `GROUP BY` or `ORDER BY` term names, when it names one by position or alias.
510    fn output_reference(
511        &self,
512        ast: &Ast,
513        item: ast::ExprRef,
514        targets: &[ast::Target],
515        clause: &str,
516    ) -> Result<Option<ast::ExprRef>> {
517        match ast.expr(item) {
518            ast::Expr::Literal { kind: LiteralKind::Number, text } => {
519                let written = ast.string(text);
520                let position: usize = written.parse().map_err(|_| {
521                    Error::binder(format!("{clause} term {written} is not a column"))
522                })?;
523                if position == 0 || position > targets.len() {
524                    return Err(Error::binder(format!(
525                        "{clause} term out of range - should be between 1 and {}",
526                        targets.len()
527                    )));
528                }
529                Ok(Some(targets[position - 1].expr))
530            }
531            ast::Expr::Column { name } => {
532                let parts: Vec<&str> = ast.name(name).collect();
533                let [written] = parts.as_slice() else { return Ok(None) };
534                let mut found = None;
535                for target in targets {
536                    if target.alias != NONE && same_name(ast.string(target.alias), written) {
537                        if found.is_some() {
538                            return Ok(None);
539                        }
540                        found = Some(target.expr);
541                    }
542                }
543                Ok(found)
544            }
545            _ => Ok(None),
546        }
547    }
548
549    // -------------------------------------------------------------- modifiers
550
551    /// Sort keys for a select, projecting anything sorted on that is not already selected.
552    #[allow(clippy::too_many_arguments)]
553    fn select_sort_keys(
554        &mut self,
555        ast: &Ast,
556        query: &ast::Query,
557        input: &Scope,
558        output: &Scope,
559        project: u32,
560        exprs: &mut Vec<ExprRef>,
561        names: &mut Vec<String>,
562        extra: &mut Vec<usize>,
563    ) -> Result<Vec<SortKey>> {
564        if query.order_by_all {
565            return Ok(self.every_column(output));
566        }
567        let items = ast.order_list(query.order_by).to_vec();
568        let mut keys = Vec::with_capacity(items.len());
569        for item in items {
570            let position = match self.output_position(ast, item.expr, output)? {
571                Some(position) => position,
572                None => {
573                    let bound = self.bind_expr(ast, item.expr, input)?;
574                    let bound = self.over_aggregate(bound, input)?;
575                    match exprs.iter().position(|&held| self.same_expr(held, bound)) {
576                        Some(position) => position,
577                        None => {
578                            exprs.push(bound);
579                            names.push(describe(ast, item.expr));
580                            extra.push(exprs.len() - 1);
581                            exprs.len() - 1
582                        }
583                    }
584                }
585            };
586            let ty = self.plan.expr_type(exprs[position]).clone();
587            let expr = self.column(project, position, ty);
588            keys.push(sort_key(expr, item));
589        }
590        Ok(keys)
591    }
592
593    /// Sort keys over an output that has nothing behind it to project, which is a set operation.
594    fn sort_keys(
595        &mut self,
596        ast: &Ast,
597        query: &ast::Query,
598        output: &Scope,
599        targets: &[ast::Target],
600    ) -> Result<Vec<SortKey>> {
601        if query.order_by_all {
602            return Ok(self.every_column(output));
603        }
604        let items = ast.order_list(query.order_by).to_vec();
605        let mut keys = Vec::with_capacity(items.len());
606        for item in items {
607            let expr = match self.output_position(ast, item.expr, output)? {
608                Some(position) => {
609                    let column = &output.columns[position];
610                    let (binding, ty) = (column.binding, column.ty.clone());
611                    self.plan.add_expr(Expr::Column(binding), ty)
612                }
613                None => {
614                    let _ = targets;
615                    self.bind_expr(ast, item.expr, output)?
616                }
617            };
618            keys.push(sort_key(expr, item));
619        }
620        Ok(keys)
621    }
622
623    fn every_column(&mut self, output: &Scope) -> Vec<SortKey> {
624        let columns: Vec<(ColumnBinding, LogicalType)> =
625            output.columns.iter().map(|column| (column.binding, column.ty.clone())).collect();
626        columns
627            .into_iter()
628            .map(|(binding, ty)| {
629                let expr = self.plan.add_expr(Expr::Column(binding), ty);
630                SortKey { expr, descending: false, nulls_first: false }
631            })
632            .collect()
633    }
634
635    /// Which output column a term names, by position or by name.
636    fn output_position(
637        &self,
638        ast: &Ast,
639        item: ast::ExprRef,
640        output: &Scope,
641    ) -> Result<Option<usize>> {
642        match ast.expr(item) {
643            ast::Expr::Literal { kind: LiteralKind::Number, text } => {
644                let written = ast.string(text);
645                if written.contains(['.', 'e', 'E']) {
646                    return Ok(None);
647                }
648                let position: usize = written.parse().map_err(|_| {
649                    Error::binder(format!("ORDER BY term {written} is not a column"))
650                })?;
651                if position == 0 || position > output.len() {
652                    return Err(Error::binder(format!(
653                        "ORDER BY term out of range - should be between 1 and {}",
654                        output.len()
655                    )));
656                }
657                Ok(Some(position - 1))
658            }
659            ast::Expr::Column { name } => {
660                let parts: Vec<&str> = ast.name(name).collect();
661                let [written] = parts.as_slice() else { return Ok(None) };
662                Ok(output.position_of(None, written))
663            }
664            _ => Ok(None),
665        }
666    }
667
668    /// The expressions a `DISTINCT ON` names, which have to be columns of the output.
669    fn distinct_on(
670        &mut self,
671        ast: &Ast,
672        distinct: Distinct,
673        output: &Scope,
674    ) -> Result<Vec<ExprRef>> {
675        let Distinct::On(items) = distinct else {
676            return Ok(Vec::new());
677        };
678        let items = ast.expr_list(items).to_vec();
679        let mut on = Vec::with_capacity(items.len());
680        for item in items {
681            let Some(position) = self.output_position(ast, item, output)? else {
682                return Err(Error::not_implemented(
683                    "DISTINCT ON an expression that is not in the select list",
684                ));
685            };
686            let column = &output.columns[position];
687            let (binding, ty) = (column.binding, column.ty.clone());
688            on.push(self.plan.add_expr(Expr::Column(binding), ty));
689        }
690        Ok(on)
691    }
692
693    fn apply_limit(&mut self, ast: &Ast, query: &ast::Query, input: NodeRef) -> Result<NodeRef> {
694        if query.limit_percent {
695            return Err(Error::not_implemented("LIMIT with a percentage"));
696        }
697        let count = self.constant_count(ast, query.limit, "LIMIT")?;
698        let offset = self.constant_count(ast, query.offset, "OFFSET")?.unwrap_or(0);
699        if count.is_none() && offset == 0 {
700            return Ok(input);
701        }
702        Ok(self.plan.add_node(Node::Limit { input, count, offset }))
703    }
704
705    /// The row count a `LIMIT` or an `OFFSET` names, which has to be a constant.
706    fn constant_count(
707        &mut self,
708        ast: &Ast,
709        written: ast::ExprRef,
710        clause: &str,
711    ) -> Result<Option<u64>> {
712        if written == NONE {
713            return Ok(None);
714        }
715        self.clause = "LIMIT clause";
716        let scope = Scope::empty();
717        let bound = self.bind_expr(ast, written, &scope)?;
718        let Expr::Constant(value) = *self.plan.expr(bound) else {
719            return Err(Error::not_implemented(format!("a {clause} that is not a constant")));
720        };
721        let count = match self.plan.value(value) {
722            Value::Null => return Ok(None),
723            Value::TinyInt(count) => i128::from(*count),
724            Value::SmallInt(count) => i128::from(*count),
725            Value::Integer(count) => i128::from(*count),
726            Value::BigInt(count) => i128::from(*count),
727            Value::HugeInt(count) => *count,
728            other => {
729                return Err(Error::binder(format!(
730                    "{clause} takes a whole number of rows, not a value of type {}",
731                    other.logical_type()
732                )));
733            }
734        };
735        u64::try_from(count)
736            .map(Some)
737            .map_err(|_| Error::binder(format!("{clause} must not be negative")))
738    }
739
740    // ------------------------------------------------------------------- from
741
742    fn bind_from(&mut self, ast: &Ast, from: ast::Slice) -> Result<(NodeRef, Scope)> {
743        let sources = ast.source_list(from).to_vec();
744        let Some((first, rest)) = sources.split_first() else {
745            // No FROM clause is one row of no columns, which is what SELECT 1 sits on. Not an
746            // empty table: an empty table would make SELECT 1 return nothing.
747            return Ok((self.plan.add_node(Node::Dummy), Scope::empty()));
748        };
749        let (mut node, mut scope) = self.bind_source(ast, *first)?;
750        for source in rest {
751            let (right, right_scope) = self.bind_source(ast, *source)?;
752            node = self.plan.add_node(Node::CrossProduct { left: node, right });
753            scope = scope.concat(right_scope);
754        }
755        Ok((node, scope))
756    }
757
758    fn bind_source(&mut self, ast: &Ast, source: ast::SourceRef) -> Result<(NodeRef, Scope)> {
759        match ast.source(source) {
760            ast::Source::Table { name, alias, columns } => {
761                self.bind_table(ast, name, alias, columns)
762            }
763            ast::Source::Function { name, args, alias, columns } => {
764                self.bind_table_function(ast, name, args, alias, columns)
765            }
766            ast::Source::Subquery { query, alias, columns } => {
767                let (node, mut scope) = self.bind_query(ast, query)?;
768                let label = if alias == NONE {
769                    "unnamed_subquery".to_string()
770                } else {
771                    ast.string(alias).to_string()
772                };
773                scope.relabel(&label);
774                if !columns.is_empty() {
775                    let names: Vec<&str> = ast.name(columns).collect();
776                    scope.rename(&names, &label)?;
777                }
778                Ok((node, scope))
779            }
780            ast::Source::Values { rows, alias, columns } => {
781                let bare = ast::Query::bare(ast::QueryBody::Values(rows));
782                let (node, mut scope) = self.bind_values(ast, &bare, rows)?;
783                let label =
784                    if alias == NONE { String::new() } else { ast.string(alias).to_string() };
785                scope.relabel(&label);
786                if !columns.is_empty() {
787                    let names: Vec<&str> = ast.name(columns).collect();
788                    scope.rename(&names, &label)?;
789                }
790                Ok((node, scope))
791            }
792            ast::Source::Join { left, right, kind, natural, on, using } => {
793                self.bind_join(ast, left, right, kind, natural, on, using)
794            }
795        }
796    }
797
798    fn bind_table(
799        &mut self,
800        ast: &Ast,
801        name: ast::Slice,
802        alias: ast::StrRef,
803        columns: ast::Slice,
804    ) -> Result<(NodeRef, Scope)> {
805        let parts: Vec<&str> = ast.name(name).collect();
806        let catalog = self.catalog;
807        // The catalog is asked first and the file is the fallback, which is the order DuckDB uses:
808        // a table really called `mixed.parquet` wins over a file of that name sitting next to it.
809        let found = catalog.resolve(&parts).and_then(|resolved| {
810            let table = catalog.table(&resolved)?;
811            Ok((resolved, table))
812        });
813        let (resolved, table) = match found {
814            Ok(found) => found,
815            Err(missing) => {
816                return self.bind_replacement_scan(ast, &parts, alias, columns, missing);
817            }
818        };
819        let fields: Vec<Field> = table.columns().to_vec();
820        let label =
821            if alias == NONE { resolved.table.clone() } else { ast.string(alias).to_string() };
822        let index = self.fresh_index();
823        let mut scope = Scope::empty();
824        for (at, field) in fields.iter().enumerate() {
825            scope.push(Visible {
826                table: label.clone(),
827                name: field.name.clone(),
828                binding: ColumnBinding::new(index, at as u32),
829                ty: field.ty.clone(),
830            });
831        }
832        if !columns.is_empty() {
833            let names: Vec<&str> = ast.name(columns).collect();
834            scope.rename(&names, &label)?;
835        }
836        let catalog_name = self.plan.intern(&resolved.catalog);
837        let schema = self.plan.intern(&resolved.schema);
838        let table_name = self.plan.intern(&resolved.table);
839        let alias = self.plan.intern(&label);
840        let columns = self.plan.add_fields(&fields);
841        let node = self.plan.add_node(Node::Get {
842            catalog: catalog_name,
843            schema,
844            table: table_name,
845            alias,
846            index,
847            columns,
848        });
849        Ok((node, scope))
850    }
851
852    /// A function call where a table goes, such as `range(10)`.
853    ///
854    /// The arguments are bound against an empty scope. A table function that can see the row on its
855    /// left is `LATERAL`, and this is not it, so a column name in here is not resolved against
856    /// whatever happens to be to the left in the `FROM` list. Letting it would mean `FROM t,
857    /// range(t.n)` quietly binding to something whose meaning depends on the order the sources were
858    /// written in.
859    fn bind_table_function(
860        &mut self,
861        ast: &Ast,
862        name: ast::Slice,
863        args: ast::Slice,
864        alias: ast::StrRef,
865        columns: ast::Slice,
866    ) -> Result<(NodeRef, Scope)> {
867        let parts: Vec<&str> = ast.name(name).collect();
868        // A qualified call names a schema, and the two schemas that exist are the ones every
869        // built-in lives in. Anything else is a name that has to fail rather than fall through to
870        // the unqualified lookup and be found somewhere it was not asked for.
871        let function_name = *parts.last().unwrap_or(&"");
872        if let Some(schema) = parts.iter().rev().nth(1) {
873            if !schema.eq_ignore_ascii_case("main") && !schema.eq_ignore_ascii_case("system") {
874                return Err(Error::catalog(format!(
875                    "Table Function with name {} does not exist!",
876                    parts.join(".")
877                )));
878            }
879        }
880        // The name is looked up before the arguments are bound so that a call of something that is
881        // not a table function says that, rather than reporting whatever is wrong with the
882        // arguments of a function that was never going to exist.
883        if TableFunction::lookup(function_name).is_none() {
884            return Err(Error::catalog(format!(
885                "Table Function with name {function_name} does not exist!"
886            )));
887        }
888        let written = ast.expr_list(args).to_vec();
889        let empty = Scope::empty();
890        let previous = std::mem::replace(&mut self.clause, "table function arguments");
891        let mut bound = Vec::with_capacity(written.len());
892        for expr in written {
893            bound.push(self.bind_expr(ast, expr, &empty)?);
894        }
895        self.clause = previous;
896
897        // The types are what resolve the call, not the count, because `read_parquet(3)` is a
898        // different answer from `read_parquet('3')` and only the types tell them apart.
899        let given: Vec<LogicalType> =
900            bound.iter().map(|&expr| self.plan.expr_type(expr).clone()).collect();
901        let resolved = resolve_table(function_name, &given)?;
902        let cast: Vec<ExprRef> = bound
903            .iter()
904            .zip(&resolved.arguments)
905            .map(|(&expr, ty)| self.cast_to(expr, ty))
906            .collect();
907
908        let fields = match resolved.columns {
909            Columns::Fixed(fields) => fields,
910            Columns::Parquet => parquet_fields(&self.file_argument(cast[0])?)?,
911        };
912        let label = if alias == NONE {
913            resolved.function.name().to_string()
914        } else {
915            ast.string(alias).to_string()
916        };
917        let names: Vec<&str> = ast.name(columns).collect();
918        self.table_function_source(resolved.function, &cast, fields, &label, &names)
919    }
920
921    /// A file where a table name goes, which is what DuckDB calls a replacement scan.
922    ///
923    /// `SELECT * FROM 'hits.parquet'` is how most DuckDB queries in the wild are written, ClickBench
924    /// among them, so this is not sugar over `read_parquet` so much as the spelling people use. The
925    /// catalog has already been asked and has already said no, and `missing` is what it said, so a
926    /// name that is not a file comes back with the catalog's own answer rather than with a complaint
927    /// about files.
928    ///
929    /// Only a single unqualified name is a candidate. A qualified one names a schema and a schema
930    /// that does not exist is not a path.
931    fn bind_replacement_scan(
932        &mut self,
933        ast: &Ast,
934        parts: &[&str],
935        alias: ast::StrRef,
936        columns: ast::Slice,
937        missing: Error,
938    ) -> Result<(NodeRef, Scope)> {
939        let [path] = parts else { return Err(missing) };
940        let path = *path;
941        let extension = path.rsplit_once('.').map(|(_, after)| after).unwrap_or_default();
942        if !extension.eq_ignore_ascii_case("parquet") {
943            return Err(missing);
944        }
945        let fields = parquet_fields(path)?;
946        // The name the columns answer to is the file's stem, so `SELECT mixed.a FROM
947        // 'data/mixed.parquet'` works. That is DuckDB's choice and it is the useful one, since the
948        // alternative is a table name with a dot and a slash in it that nothing can write.
949        let label = if alias == NONE {
950            let file = path.rsplit_once('/').map_or(path, |(_, file)| file);
951            file.rsplit_once('.').map_or(file, |(stem, _)| stem).to_string()
952        } else {
953            ast.string(alias).to_string()
954        };
955        let value = self.plan.add_value(Value::Varchar(path.to_string()));
956        let argument = self.plan.add_expr(Expr::Constant(value), LogicalType::Varchar);
957        let names: Vec<&str> = ast.name(columns).collect();
958        self.table_function_source(TableFunction::ReadParquet, &[argument], fields, &label, &names)
959    }
960
961    /// The node and the scope of a table function call whose arguments and columns are settled.
962    ///
963    /// The half a written out call shares with a replacement scan, which is everything after the
964    /// question of what the file is called has been answered one way or the other.
965    fn table_function_source(
966        &mut self,
967        function: TableFunction,
968        args: &[ExprRef],
969        fields: Vec<Field>,
970        label: &str,
971        names: &[&str],
972    ) -> Result<(NodeRef, Scope)> {
973        let index = self.fresh_index();
974        let mut scope = Scope::empty();
975        for (at, field) in fields.iter().enumerate() {
976            scope.push(Visible {
977                table: label.to_string(),
978                name: field.name.clone(),
979                binding: ColumnBinding::new(index, at as u32),
980                ty: field.ty.clone(),
981            });
982        }
983        if !names.is_empty() {
984            scope.rename(names, label)?;
985        }
986        let function = self.plan.intern(function.name());
987        let args = self.plan.add_expr_list(args);
988        let columns = self.plan.add_fields(&fields);
989        let node = self.plan.add_node(Node::TableFunction { index, function, args, columns });
990        Ok((node, scope))
991    }
992
993    /// The file name a table function argument names, which has to be a constant.
994    ///
995    /// A table function that reads a file is resolved by opening the file, and that happens here
996    /// rather than when the query runs, because the rest of the statement cannot bind until the
997    /// column names are known. So the path has to be something this binder can work out without
998    /// running anything, and a literal is that. DuckDB folds a constant expression first, so
999    /// `read_parquet('a' || '.parquet')` works there, and folding is M1 work that this will pick up
1000    /// for free once the optimizer runs before the plan is finished rather than after.
1001    fn file_argument(&self, expr: ExprRef) -> Result<String> {
1002        let Expr::Constant(reference) = *self.plan.expr(expr) else {
1003            return Err(Error::not_implemented(
1004                "a table function file name that is not a constant",
1005            ));
1006        };
1007        match self.plan.value(reference) {
1008            Value::Varchar(path) => Ok(path.clone()),
1009            // DuckDB's own wording, which says list because its overload takes one.
1010            Value::Null => Err(Error::parser("read_parquet cannot take NULL list as parameter")),
1011            other => {
1012                Err(Error::internal(format!("a file name bound as VARCHAR arrived as {other}")))
1013            }
1014        }
1015    }
1016
1017    #[allow(clippy::too_many_arguments)]
1018    fn bind_join(
1019        &mut self,
1020        ast: &Ast,
1021        left: ast::SourceRef,
1022        right: ast::SourceRef,
1023        kind: ast::JoinKind,
1024        natural: bool,
1025        on: ast::ExprRef,
1026        using: ast::Slice,
1027    ) -> Result<(NodeRef, Scope)> {
1028        let (left_node, left_scope) = self.bind_source(ast, left)?;
1029        let (right_node, right_scope) = self.bind_source(ast, right)?;
1030        let split = left_scope.len();
1031        let mut scope = left_scope.concat(right_scope);
1032
1033        // NATURAL is USING over whatever both sides happen to call the same thing, which is why it
1034        // is resolved here and never reaches the plan as its own idea.
1035        let merged: Vec<String> = if natural {
1036            let mut names = Vec::new();
1037            for (at, column) in scope.columns.iter().enumerate().take(split) {
1038                if scope.columns[split..].iter().any(|right| same_name(&right.name, &column.name))
1039                    && !names.iter().any(|held: &String| same_name(held, &column.name))
1040                {
1041                    let _ = at;
1042                    names.push(column.name.clone());
1043                }
1044            }
1045            names
1046        } else {
1047            ast.name(using).map(str::to_string).collect()
1048        };
1049
1050        let mut conditions = Vec::new();
1051        let mut dropped = Vec::new();
1052        for name in &merged {
1053            let left_at = scope.columns[..split]
1054                .iter()
1055                .position(|column| same_name(&column.name, name))
1056                .ok_or_else(|| {
1057                    Error::binder(format!(
1058                        "column \"{name}\" specified in USING clause does not exist in left table"
1059                    ))
1060                })?;
1061            let right_at = scope.columns[split..]
1062                .iter()
1063                .position(|column| same_name(&column.name, name))
1064                .map(|at| at + split)
1065                .ok_or_else(|| {
1066                    Error::binder(format!(
1067                        "column \"{name}\" specified in USING clause does not exist in right table"
1068                    ))
1069                })?;
1070            let left_column = &scope.columns[left_at];
1071            let (left_binding, left_type) = (left_column.binding, left_column.ty.clone());
1072            let right_column = &scope.columns[right_at];
1073            let (right_binding, right_type) = (right_column.binding, right_column.ty.clone());
1074            let left_expr = self.plan.add_expr(Expr::Column(left_binding), left_type);
1075            let right_expr = self.plan.add_expr(Expr::Column(right_binding), right_type);
1076            conditions.push(self.compare(rudb_plan::CompareOp::Equal, left_expr, right_expr)?);
1077            dropped.push(right_at);
1078        }
1079        // A joined-on column appears once, so the right side's copy goes. Dropping from the back
1080        // keeps the positions of the ones still to drop correct.
1081        dropped.sort_unstable();
1082        for at in dropped.into_iter().rev() {
1083            scope.remove(at);
1084        }
1085
1086        if on != NONE {
1087            if !merged.is_empty() {
1088                return Err(Error::binder("a join cannot have both ON and USING"));
1089            }
1090            self.clause = "JOIN condition";
1091            let predicate = self.bind_expr(ast, on, &scope)?;
1092            conditions.push(self.as_boolean(predicate, "JOIN")?);
1093        }
1094
1095        if kind == ast::JoinKind::Cross {
1096            if !conditions.is_empty() {
1097                return Err(Error::binder("a CROSS JOIN cannot have a condition"));
1098            }
1099            let node =
1100                self.plan.add_node(Node::CrossProduct { left: left_node, right: right_node });
1101            return Ok((node, scope));
1102        }
1103        if conditions.is_empty() && kind == ast::JoinKind::Inner {
1104            let node =
1105                self.plan.add_node(Node::CrossProduct { left: left_node, right: right_node });
1106            return Ok((node, scope));
1107        }
1108        let kind = match kind {
1109            ast::JoinKind::Inner | ast::JoinKind::Cross => JoinKind::Inner,
1110            ast::JoinKind::Left => JoinKind::Left,
1111            ast::JoinKind::Right => JoinKind::Right,
1112            ast::JoinKind::Full => JoinKind::Full,
1113            ast::JoinKind::Semi => JoinKind::Semi,
1114            ast::JoinKind::Anti => JoinKind::Anti,
1115            ast::JoinKind::Positional => JoinKind::Positional,
1116        };
1117        let conditions = self.plan.add_expr_list(&conditions);
1118        let node =
1119            self.plan.add_node(Node::Join { left: left_node, right: right_node, kind, conditions });
1120        Ok((node, scope))
1121    }
1122
1123    // -------------------------------------------------------------- aggregates
1124
1125    /// Binds an aggregate call, records it, and hands back a reference to where its result lands.
1126    pub(crate) fn bind_aggregate(
1127        &mut self,
1128        ast: &Ast,
1129        name: &str,
1130        args: &[ast::ExprRef],
1131        distinct: bool,
1132        scope: &Scope,
1133    ) -> Result<ExprRef> {
1134        if self.in_aggregate {
1135            return Err(Error::binder(format!(
1136                "aggregate function calls cannot be nested, and {name}() is inside one"
1137            )));
1138        }
1139        if self.aggregation.is_none() {
1140            return Err(Error::binder(format!(
1141                "aggregate function calls cannot be used in the {}",
1142                self.clause
1143            )));
1144        }
1145        self.in_aggregate = true;
1146        let mut bound = Vec::with_capacity(args.len());
1147        let mut failure = None;
1148        for &arg in args {
1149            match self.bind_expr(ast, arg, scope) {
1150                Ok(expr) => bound.push(expr),
1151                Err(error) => {
1152                    failure = Some(error);
1153                    break;
1154                }
1155            }
1156        }
1157        self.in_aggregate = false;
1158        if let Some(error) = failure {
1159            return Err(error);
1160        }
1161
1162        let types: Vec<LogicalType> =
1163            bound.iter().map(|&arg| self.plan.expr_type(arg).clone()).collect();
1164        let resolved = resolve(name, &types)?;
1165        let mut cast = Vec::with_capacity(bound.len());
1166        for (arg, wanted) in bound.iter().zip(&resolved.arguments) {
1167            cast.push(self.cast_to(*arg, wanted));
1168        }
1169        let args = self.plan.add_expr_list(&cast);
1170        let name = self.plan.intern(resolved.name);
1171        let ty = resolved.returns;
1172        let call =
1173            self.plan.add_expr(Expr::Aggregate { name, args, distinct, filter: None }, ty.clone());
1174
1175        // Two identical aggregates are one column of the aggregate's output. `SELECT sum(x),
1176        // sum(x) / count(*)` computes one sum, not two.
1177        let existing = self.aggregation.as_ref().map(|held| held.aggregates.clone());
1178        let existing = existing.unwrap_or_default();
1179        let at = match existing.iter().position(|&held| self.same_expr(held, call)) {
1180            Some(at) => at,
1181            None => {
1182                let aggregation = self.aggregation.as_mut().expect("checked above");
1183                aggregation.aggregates.push(call);
1184                aggregation.aggregates.len() - 1
1185            }
1186        };
1187        let aggregation = self.aggregation.as_ref().expect("checked above");
1188        let (index, groups) = (aggregation.index, aggregation.groups.len());
1189        Ok(self.column(index, groups + at, ty))
1190    }
1191
1192    /// Rewrites a bound expression into one the aggregate's output can answer.
1193    ///
1194    /// A subexpression that is one of the group expressions becomes a reference to that group. A
1195    /// column that is neither grouped nor inside an aggregate is the error every SQL user has seen,
1196    /// and it is reported here because this is the first point where it is knowable.
1197    pub(crate) fn over_aggregate(&mut self, expr: ExprRef, scope: &Scope) -> Result<ExprRef> {
1198        let Some(aggregation) = self.aggregation.as_ref() else {
1199            return Ok(expr);
1200        };
1201        let index = aggregation.index;
1202        let groups = aggregation.groups.clone();
1203        for (at, group) in groups.iter().enumerate() {
1204            if self.same_expr(expr, *group) {
1205                let ty = self.plan.expr_type(*group).clone();
1206                return Ok(self.column(index, at, ty));
1207            }
1208        }
1209        let ty = self.plan.expr_type(expr).clone();
1210        match self.plan.expr(expr).clone() {
1211            Expr::Column(binding) if binding.table == index => Ok(expr),
1212            Expr::Column(binding) => {
1213                let name =
1214                    scope.columns.iter().find(|column| column.binding == binding).map_or_else(
1215                        || "a column".to_string(),
1216                        |column| format!("\"{}\"", column.name),
1217                    );
1218                Err(Error::binder(format!(
1219                    "column {name} must appear in the GROUP BY clause or must be part of an aggregate function"
1220                )))
1221            }
1222            Expr::Constant(_) | Expr::Aggregate { .. } => Ok(expr),
1223            Expr::Cast { input, try_cast } => {
1224                let input = self.over_aggregate(input, scope)?;
1225                Ok(self.plan.add_expr(Expr::Cast { input, try_cast }, ty))
1226            }
1227            Expr::Compare { op, left, right } => {
1228                let left = self.over_aggregate(left, scope)?;
1229                let right = self.over_aggregate(right, scope)?;
1230                Ok(self.plan.add_expr(Expr::Compare { op, left, right }, ty))
1231            }
1232            Expr::Conjunction { op, children } => {
1233                let written = self.plan.expr_list(children).to_vec();
1234                let mut rewritten = Vec::with_capacity(written.len());
1235                for child in written {
1236                    rewritten.push(self.over_aggregate(child, scope)?);
1237                }
1238                let children = self.plan.add_expr_list(&rewritten);
1239                Ok(self.plan.add_expr(Expr::Conjunction { op, children }, ty))
1240            }
1241            Expr::Function { name, args } => {
1242                let written = self.plan.expr_list(args).to_vec();
1243                let mut rewritten = Vec::with_capacity(written.len());
1244                for arg in written {
1245                    rewritten.push(self.over_aggregate(arg, scope)?);
1246                }
1247                let args = self.plan.add_expr_list(&rewritten);
1248                Ok(self.plan.add_expr(Expr::Function { name, args }, ty))
1249            }
1250            Expr::Case { arms, otherwise } => {
1251                let written = self.plan.arm_list(arms).to_vec();
1252                let mut rewritten = Vec::with_capacity(written.len());
1253                for arm in written {
1254                    let when = self.over_aggregate(arm.when, scope)?;
1255                    let then = self.over_aggregate(arm.then, scope)?;
1256                    rewritten.push(rudb_plan::Arm { when, then });
1257                }
1258                let otherwise = match otherwise {
1259                    Some(expr) => Some(self.over_aggregate(expr, scope)?),
1260                    None => None,
1261                };
1262                let arms = self.plan.add_arms(&rewritten);
1263                Ok(self.plan.add_expr(Expr::Case { arms, otherwise }, ty))
1264            }
1265        }
1266    }
1267
1268    /// Whether two bound expressions are the same expression, by shape rather than by reference.
1269    pub(crate) fn same_expr(&self, left: ExprRef, right: ExprRef) -> bool {
1270        same_expr(&self.plan, left, right)
1271    }
1272}
1273
1274/// A sort key with SQL's defaults filled in.
1275///
1276/// Unstated is ascending, and unstated nulls go where the direction puts them, which is last for
1277/// ascending and first for descending. That is DuckDB's rule and it is the one that makes
1278/// `ORDER BY x DESC` the exact reverse of `ORDER BY x`.
1279fn sort_key(expr: ExprRef, item: ast::OrderItem) -> SortKey {
1280    let descending = item.order == Order::Descending;
1281    let nulls_first = match item.nulls {
1282        Nulls::First => true,
1283        Nulls::Last => false,
1284        Nulls::Unstated => descending,
1285    };
1286    SortKey { expr, descending, nulls_first }
1287}
1288
1289/// Structural equality over two expressions of one plan.
1290fn same_expr(plan: &Plan, left: ExprRef, right: ExprRef) -> bool {
1291    if left == right {
1292        return true;
1293    }
1294    if plan.expr_type(left) != plan.expr_type(right) {
1295        return false;
1296    }
1297    let lists = |left, right| {
1298        let left: &[ExprRef] = plan.expr_list(left);
1299        let right: &[ExprRef] = plan.expr_list(right);
1300        left.len() == right.len()
1301            && left.iter().zip(right).all(|(&left, &right)| same_expr(plan, left, right))
1302    };
1303    match (plan.expr(left), plan.expr(right)) {
1304        (Expr::Column(left), Expr::Column(right)) => left == right,
1305        (Expr::Constant(left), Expr::Constant(right)) => plan.value(*left) == plan.value(*right),
1306        (
1307            Expr::Cast { input: left, try_cast: left_try },
1308            Expr::Cast { input: right, try_cast: right_try },
1309        ) => left_try == right_try && same_expr(plan, *left, *right),
1310        (
1311            Expr::Compare { op: left_op, left: left_a, right: left_b },
1312            Expr::Compare { op: right_op, left: right_a, right: right_b },
1313        ) => {
1314            left_op == right_op
1315                && same_expr(plan, *left_a, *right_a)
1316                && same_expr(plan, *left_b, *right_b)
1317        }
1318        (
1319            Expr::Conjunction { op: left_op, children: left_children },
1320            Expr::Conjunction { op: right_op, children: right_children },
1321        ) => left_op == right_op && lists(*left_children, *right_children),
1322        (
1323            Expr::Function { name: left_name, args: left_args },
1324            Expr::Function { name: right_name, args: right_args },
1325        ) => plan.string(*left_name) == plan.string(*right_name) && lists(*left_args, *right_args),
1326        (
1327            Expr::Aggregate {
1328                name: left_name,
1329                args: left_args,
1330                distinct: left_distinct,
1331                filter: left_filter,
1332            },
1333            Expr::Aggregate {
1334                name: right_name,
1335                args: right_args,
1336                distinct: right_distinct,
1337                filter: right_filter,
1338            },
1339        ) => {
1340            plan.string(*left_name) == plan.string(*right_name)
1341                && left_distinct == right_distinct
1342                && match (left_filter, right_filter) {
1343                    (None, None) => true,
1344                    (Some(left), Some(right)) => same_expr(plan, *left, *right),
1345                    _ => false,
1346                }
1347                && lists(*left_args, *right_args)
1348        }
1349        (
1350            Expr::Case { arms: left_arms, otherwise: left_otherwise },
1351            Expr::Case { arms: right_arms, otherwise: right_otherwise },
1352        ) => {
1353            let left_arms = plan.arm_list(*left_arms);
1354            let right_arms = plan.arm_list(*right_arms);
1355            left_arms.len() == right_arms.len()
1356                && left_arms.iter().zip(right_arms).all(|(left, right)| {
1357                    same_expr(plan, left.when, right.when) && same_expr(plan, left.then, right.then)
1358                })
1359                && match (left_otherwise, right_otherwise) {
1360                    (None, None) => true,
1361                    (Some(left), Some(right)) => same_expr(plan, *left, *right),
1362                    _ => false,
1363                }
1364        }
1365        _ => false,
1366    }
1367}