Skip to main content

mz_sql/plan/
query.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! SQL `Query`s are the declarative, computational part of SQL.
11//! This module turns `Query`s into `HirRelationExpr`s - a more explicit, algebraic way of
12//! describing computation.
13
14//! Functions named plan_* are typically responsible for handling a single node of the SQL ast.
15//! E.g. `plan_query` is responsible for handling `sqlparser::ast::Query`.
16//! plan_* functions which correspond to operations on relations typically return a `HirRelationExpr`.
17//! plan_* functions which correspond to operations on scalars typically return a `HirScalarExpr`
18//! and a `SqlScalarType`. (The latter is because it's not always possible to infer from a
19//! `HirScalarExpr` what the intended type is - notably in the case of decimals where the
20//! scale/precision are encoded only in the type).
21
22//! Aggregates are particularly twisty.
23//!
24//! In SQL, a GROUP BY turns any columns not in the group key into vectors of
25//! values. Then anywhere later in the scope, an aggregate function can be
26//! applied to that group. Inside the arguments of an aggregate function, other
27//! normal functions are applied element-wise over the vectors. Thus, `SELECT
28//! sum(foo.x + foo.y) FROM foo GROUP BY x` means adding the scalar `x` to the
29//! vector `y` and summing the results.
30//!
31//! In `HirRelationExpr`, aggregates can only be applied immediately at the time
32//! of grouping.
33//!
34//! To deal with this, whenever we see a SQL GROUP BY we look ahead for
35//! aggregates and precompute them in the `HirRelationExpr::Reduce`. When we
36//! reach the same aggregates during normal planning later on, we look them up
37//! in an `ExprContext` to find the precomputed versions.
38
39use std::borrow::Cow;
40use std::cell::RefCell;
41use std::collections::{BTreeMap, BTreeSet};
42use std::convert::{TryFrom, TryInto};
43use std::num::NonZeroU64;
44use std::rc::Rc;
45use std::sync::{Arc, LazyLock};
46use std::{iter, mem};
47
48use itertools::Itertools;
49use mz_expr::func::variadic::{
50    ArrayCreate, ArrayIndex, Coalesce, Greatest, Least, ListCreate, ListIndex, ListSliceLinear,
51    MapBuild, RecordCreate,
52};
53use mz_expr::virtual_syntax::AlgExcept;
54use mz_expr::{
55    Eval, Id, LetRecLimit, LocalId, MapFilterProject, MirScalarExpr, REPEAT_ROW_NAME,
56    RowSetFinishing, TableFunc, func as expr_func,
57};
58use mz_ore::collections::CollectionExt;
59use mz_ore::error::ErrorExt;
60use mz_ore::id_gen::IdGen;
61use mz_ore::option::FallibleMapExt;
62use mz_ore::stack::{CheckedRecursion, RecursionGuard};
63use mz_ore::str::StrExt;
64use mz_repr::adt::char::CharLength;
65use mz_repr::adt::numeric::{NUMERIC_DATUM_MAX_PRECISION, NumericMaxScale};
66use mz_repr::adt::timestamp::TimestampPrecision;
67use mz_repr::adt::varchar::VarCharMaxLength;
68use mz_repr::namespaces::MZ_CATALOG_SCHEMA;
69use mz_repr::{
70    CatalogItemId, ColumnIndex, ColumnName, Datum, RelationDesc, RelationVersionSelector,
71    ReprColumnType, Row, RowArena, SqlColumnType, SqlRelationType, SqlScalarType,
72    UNKNOWN_COLUMN_NAME, strconv,
73};
74use mz_sql_parser::ast::display::AstDisplay;
75use mz_sql_parser::ast::visit::Visit;
76use mz_sql_parser::ast::visit_mut::{self, VisitMut};
77use mz_sql_parser::ast::{
78    AsOf, Assignment, AstInfo, CreateWebhookSourceBody, CreateWebhookSourceCheck,
79    CreateWebhookSourceHeader, CreateWebhookSourceSecret, CteBlock, DeleteStatement, Distinct,
80    Expr, Function, FunctionArgs, HomogenizingFunction, Ident, InsertSource, IsExprConstruct, Join,
81    JoinConstraint, JoinOperator, Limit, MapEntry, MutRecBlock, MutRecBlockOption,
82    MutRecBlockOptionName, OrderByExpr, Query, Select, SelectItem, SelectOption, SelectOptionName,
83    SetExpr, SetOperator, ShowStatement, SubscriptPosition, TableAlias, TableFactor,
84    TableWithJoins, UnresolvedItemName, UpdateStatement, Value, Values, WindowFrame,
85    WindowFrameBound, WindowFrameUnits, WindowSpec, visit,
86};
87use mz_sql_parser::ident;
88
89use crate::catalog::{CatalogItemType, CatalogType, SessionCatalog};
90use crate::func::{self, Func, FuncSpec, TableFuncImpl};
91use crate::names::{
92    Aug, FullItemName, PartialItemName, ResolvedDataType, ResolvedItemName, SchemaSpecifier,
93};
94use crate::plan::PlanError::InvalidWmrRecursionLimit;
95use crate::plan::error::PlanError;
96use crate::plan::hir::{
97    AbstractColumnType, AbstractExpr, AggregateExpr, AggregateFunc, AggregateWindowExpr,
98    BinaryFunc, CoercibleScalarExpr, CoercibleScalarType, ColumnOrder, ColumnRef, Hir,
99    HirRelationExpr, HirScalarExpr, JoinKind, ScalarWindowExpr, ScalarWindowFunc, UnaryFunc,
100    ValueWindowExpr, ValueWindowFunc, VariadicFunc, WindowExpr, WindowExprType,
101};
102use crate::plan::plan_utils::{self, GroupSizeHints, JoinSide};
103use crate::plan::scope::{Scope, ScopeItem, ScopeUngroupedColumn};
104use crate::plan::statement::{StatementContext, StatementDesc, show};
105use crate::plan::typeconv::{self, CastContext, plan_hypothetical_cast};
106use crate::plan::{
107    Params, PlanContext, QueryWhen, ShowCreatePlan, WebhookValidation, WebhookValidationSecret,
108    literal, transform_ast,
109};
110use crate::session::vars::ENABLE_WITH_ORDINALITY_LEGACY_FALLBACK;
111use crate::session::vars::{self, FeatureFlag};
112use crate::{ORDINALITY_COL_NAME, normalize};
113
114#[derive(Debug)]
115pub struct PlannedRootQuery<E> {
116    pub expr: E,
117    pub desc: RelationDesc,
118    pub finishing: RowSetFinishing<HirScalarExpr, HirScalarExpr>,
119    pub scope: Scope,
120}
121
122/// Plans a top-level query, returning the `HirRelationExpr` describing the query
123/// plan, the `RelationDesc` describing the shape of the result set, a
124/// `RowSetFinishing` describing post-processing that must occur before results
125/// are sent to the client, and the types of the parameters in the query, if any
126/// were present.
127///
128/// Note that the returned `RelationDesc` describes the expression after
129/// applying the returned `RowSetFinishing`.
130#[mz_ore::instrument(target = "compiler", level = "trace", name = "ast_to_hir")]
131pub fn plan_root_query(
132    scx: &StatementContext,
133    mut query: Query<Aug>,
134    lifetime: QueryLifetime,
135) -> Result<PlannedRootQuery<HirRelationExpr>, PlanError> {
136    transform_ast::transform(scx, &mut query)?;
137    let mut qcx = QueryContext::root(scx, lifetime);
138    let PlannedQuery {
139        mut expr,
140        scope,
141        order_by,
142        limit,
143        offset,
144        project,
145        group_size_hints,
146    } = plan_query(&mut qcx, &query)?;
147
148    let mut finishing = RowSetFinishing {
149        limit,
150        offset,
151        project,
152        order_by,
153    };
154
155    // Attempt to push the finishing's ordering past its projection. This allows
156    // data to be projected down on the workers rather than the coordinator. It
157    // also improves the optimizer's demand analysis, as the optimizer can only
158    // reason about demand information in `expr` (i.e., it can't see
159    // `finishing.project`).
160    try_push_projection_order_by(&mut expr, &mut finishing.project, &mut finishing.order_by);
161
162    if lifetime.is_maintained() {
163        expr.finish_maintained(&mut finishing, group_size_hints);
164    }
165
166    let typ = qcx.relation_type(&expr);
167    let typ = SqlRelationType::new(
168        finishing
169            .project
170            .iter()
171            .map(|i| typ.column_types[*i].clone())
172            .collect(),
173    );
174    let desc = RelationDesc::new(typ, scope.column_names());
175
176    Ok(PlannedRootQuery {
177        expr,
178        desc,
179        finishing,
180        scope,
181    })
182}
183
184/// Attempts to push a projection through an order by.
185///
186/// The returned bool indicates whether the pushdown was successful or not.
187/// Successful pushdown requires that all the columns referenced in `order_by`
188/// are included in `project`.
189///
190/// When successful, `expr` is wrapped in a projection node, `order_by` is
191/// rewritten to account for the pushed-down projection, and `project` is
192/// replaced with the trivial projection. When unsuccessful, no changes are made
193/// to any of the inputs.
194fn try_push_projection_order_by(
195    expr: &mut HirRelationExpr,
196    project: &mut Vec<usize>,
197    order_by: &mut Vec<ColumnOrder>,
198) -> bool {
199    let mut unproject = vec![None; expr.arity()];
200    for (out_i, in_i) in project.iter().copied().enumerate() {
201        unproject[in_i] = Some(out_i);
202    }
203    if order_by
204        .iter()
205        .all(|ob| ob.column < unproject.len() && unproject[ob.column].is_some())
206    {
207        let trivial_project = (0..project.len()).collect();
208        *expr = expr.take().project(mem::replace(project, trivial_project));
209        for ob in order_by {
210            ob.column = unproject[ob.column].unwrap();
211        }
212        true
213    } else {
214        false
215    }
216}
217
218pub fn plan_insert_query(
219    scx: &StatementContext,
220    table_name: ResolvedItemName,
221    columns: Vec<Ident>,
222    source: InsertSource<Aug>,
223    returning: Vec<SelectItem<Aug>>,
224) -> Result<
225    (
226        CatalogItemId,
227        HirRelationExpr,
228        PlannedRootQuery<Vec<HirScalarExpr>>,
229    ),
230    PlanError,
231> {
232    let mut qcx = QueryContext::root(scx, QueryLifetime::OneShot);
233    let table = scx.get_item_by_resolved_name(&table_name)?;
234
235    // Validate the target of the insert.
236    if table.item_type() != CatalogItemType::Table {
237        sql_bail!(
238            "cannot insert into {} '{}'",
239            table.item_type(),
240            table_name.full_name_str()
241        );
242    }
243    let desc = table
244        .relation_desc()
245        .ok_or_else(|| sql_err!("item does not have a relation description"))?;
246    let mut defaults = table
247        .writable_table_details()
248        .ok_or_else(|| {
249            sql_err!(
250                "cannot insert into non-writeable table '{}'",
251                table_name.full_name_str()
252            )
253        })?
254        .to_vec();
255
256    for default in &mut defaults {
257        transform_ast::transform(scx, default)?;
258    }
259
260    if table.id().is_system() {
261        sql_bail!(
262            "cannot insert into system table '{}'",
263            table_name.full_name_str()
264        );
265    }
266
267    let columns: Vec<_> = columns.into_iter().map(normalize::column_name).collect();
268
269    // Validate target column order.
270    let mut source_types = Vec::with_capacity(columns.len());
271    let mut ordering = Vec::with_capacity(columns.len());
272
273    if columns.is_empty() {
274        // Columns in source query must be in order. Let's guess the full shape and truncate to the
275        // right size later after planning the source query
276        source_types.extend(desc.iter_types().map(|x| &x.scalar_type));
277        ordering.extend(0..desc.arity());
278    } else {
279        let column_by_name: BTreeMap<&ColumnName, (usize, &SqlColumnType)> = desc
280            .iter()
281            .enumerate()
282            .map(|(idx, (name, typ))| (name, (idx, typ)))
283            .collect();
284
285        for c in &columns {
286            if let Some((idx, typ)) = column_by_name.get(c) {
287                ordering.push(*idx);
288                source_types.push(&typ.scalar_type);
289            } else {
290                sql_bail!(
291                    "column {} of relation {} does not exist",
292                    c.quoted(),
293                    table_name.full_name_str().quoted()
294                );
295            }
296        }
297        if let Some(dup) = columns.iter().duplicates().next() {
298            sql_bail!("column {} specified more than once", dup.quoted());
299        }
300    };
301
302    // Plan the source.
303    let expr = match source {
304        InsertSource::Query(mut query) => {
305            transform_ast::transform(scx, &mut query)?;
306
307            match query {
308                // Special-case simple VALUES clauses as PostgreSQL does.
309                Query {
310                    body: SetExpr::Values(Values(values)),
311                    ctes,
312                    order_by,
313                    limit: None,
314                    offset: None,
315                } if ctes.is_empty() && order_by.is_empty() => {
316                    let names: Vec<_> = ordering.iter().map(|i| desc.get_name(*i)).collect();
317                    plan_values_insert(&qcx, &names, &source_types, &values)?
318                }
319                _ => {
320                    let (expr, _scope) = plan_nested_query(&mut qcx, &query)?;
321                    expr
322                }
323            }
324        }
325        InsertSource::DefaultValues => {
326            HirRelationExpr::constant(vec![vec![]], SqlRelationType::empty())
327        }
328    };
329
330    let expr_arity = expr.arity();
331
332    // Validate that the arity of the source query is at most the size of declared columns or the
333    // size of the table if none are declared
334    let max_columns = if columns.is_empty() {
335        desc.arity()
336    } else {
337        columns.len()
338    };
339    if expr_arity > max_columns {
340        sql_bail!("INSERT has more expressions than target columns");
341    }
342    // But it should never have less than the declared columns (or zero)
343    if expr_arity < columns.len() {
344        sql_bail!("INSERT has more target columns than expressions");
345    }
346
347    // Trim now that we know for sure the correct arity of the source query
348    source_types.truncate(expr_arity);
349    ordering.truncate(expr_arity);
350
351    // Ensure the types of the source query match the types of the target table,
352    // installing assignment casts where necessary and possible.
353    let expr = cast_relation(&qcx, CastContext::Assignment, expr, source_types).map_err(|e| {
354        sql_err!(
355            "column {} is of type {} but expression is of type {}",
356            desc.get_name(ordering[e.column]).quoted(),
357            qcx.humanize_sql_scalar_type(&e.target_type, false),
358            qcx.humanize_sql_scalar_type(&e.source_type, false),
359        )
360    })?;
361
362    // Fill in any omitted columns and rearrange into correct order
363    let mut map_exprs = vec![];
364    let mut project_key = Vec::with_capacity(desc.arity());
365
366    // Maps from table column index to position in the source query
367    let col_to_source: BTreeMap<_, _> = ordering.iter().enumerate().map(|(a, b)| (b, a)).collect();
368
369    let column_details = desc.iter_types().zip_eq(defaults).enumerate();
370    for (col_idx, (col_typ, default)) in column_details {
371        if let Some(src_idx) = col_to_source.get(&col_idx) {
372            project_key.push(*src_idx);
373        } else {
374            let hir = plan_default_expr(scx, &default, &col_typ.scalar_type)?;
375            project_key.push(expr_arity + map_exprs.len());
376            map_exprs.push(hir);
377        }
378    }
379
380    let returning = {
381        let (scope, typ) = if let ResolvedItemName::Item {
382            full_name,
383            version: _,
384            ..
385        } = table_name
386        {
387            let scope = Scope::from_source(Some(full_name.clone().into()), desc.iter_names());
388            let typ = desc.typ().clone();
389            (scope, typ)
390        } else {
391            (Scope::empty(), SqlRelationType::empty())
392        };
393        let ecx = &ExprContext {
394            qcx: &qcx,
395            name: "RETURNING clause",
396            scope: &scope,
397            relation_type: &typ,
398            allow_aggregates: false,
399            allow_subqueries: false,
400            allow_parameters: true,
401            allow_windows: false,
402        };
403        let table_func_names = BTreeMap::new();
404        let mut output_columns = vec![];
405        let mut new_exprs = vec![];
406        let mut new_type = SqlRelationType::empty();
407        for mut si in returning {
408            transform_ast::transform(scx, &mut si)?;
409            for (select_item, column_name) in expand_select_item(ecx, &si, &table_func_names)? {
410                let expr = match &select_item {
411                    ExpandedSelectItem::InputOrdinal(i) => HirScalarExpr::column(*i),
412                    ExpandedSelectItem::Expr(expr) => plan_expr(ecx, expr)?.type_as_any(ecx)?,
413                };
414                output_columns.push(column_name);
415                let typ = ecx.column_type(&expr);
416                new_type.column_types.push(typ);
417                new_exprs.push(expr);
418            }
419        }
420        let desc = RelationDesc::new(new_type, output_columns);
421        let desc_arity = desc.arity();
422        PlannedRootQuery {
423            expr: new_exprs,
424            desc,
425            finishing: HirRelationExpr::trivial_row_set_finishing_hir(desc_arity),
426            scope,
427        }
428    };
429
430    Ok((
431        table.id(),
432        expr.map(map_exprs).project(project_key),
433        returning,
434    ))
435}
436
437/// Determines the mapping between some external data and a Materialize relation.
438///
439/// Returns the following:
440/// * [`CatalogItemId`] for the destination table.
441/// * [`RelationDesc`] representing the shape of the __input__ data we are copying from.
442/// * The [`ColumnIndex`]es that the source data maps to. TODO(cf2): We don't need this mapping
443///   since we now return a [`MapFilterProject`].
444/// * [`MapFilterProject`] which will map and project the input data to match the shape of the
445///   destination table.
446///
447pub fn plan_copy_item(
448    scx: &StatementContext,
449    item_name: ResolvedItemName,
450    columns: Vec<Ident>,
451) -> Result<
452    (
453        CatalogItemId,
454        RelationDesc,
455        Vec<ColumnIndex>,
456        Option<MapFilterProject>,
457    ),
458    PlanError,
459> {
460    let item = scx.get_item_by_resolved_name(&item_name)?;
461    let fullname = scx.catalog.resolve_full_name(item.name());
462    let table_desc = match item.relation_desc() {
463        Some(desc) => desc.into_owned(),
464        None => {
465            return Err(PlanError::InvalidDependency {
466                name: fullname.to_string(),
467                item_type: item.item_type().to_string(),
468            });
469        }
470    };
471    let mut ordering = Vec::with_capacity(columns.len());
472
473    // TODO(cf2): The logic here to create the `source_desc` and the MFP are a bit duplicated and
474    // should be simplified. The reason they are currently separate code paths is so we can roll
475    // out `COPY ... FROM <url>` without touching the current `COPY ... FROM ... STDIN` behavior.
476
477    // If we're copying data into a table that users can write into (e.g. not a `CREATE TABLE ...
478    // FROM SOURCE ...`), then we generate an MFP.
479    //
480    // Note: This method is called for both `COPY INTO <table> FROM` and `COPY <expr> TO <external>`
481    // so it's not always guaranteed that our `item` is a table.
482    let mfp = if let Some(table_defaults) = item.writable_table_details() {
483        let mut table_defaults = table_defaults.to_vec();
484
485        for default in &mut table_defaults {
486            transform_ast::transform(scx, default)?;
487        }
488
489        // Fill in any omitted columns and rearrange into correct order
490        let source_column_names: Vec<_> = columns
491            .iter()
492            .cloned()
493            .map(normalize::column_name)
494            .collect();
495
496        let mut default_exprs = Vec::new();
497        let mut project_keys = Vec::with_capacity(table_desc.arity());
498
499        // For each column in the destination table, either project it from the source data, or provide
500        // an expression to fill in a default value.
501        let column_details = table_desc.iter().zip_eq(table_defaults);
502        for ((col_name, col_type), col_default) in column_details {
503            let maybe_src_idx = source_column_names.iter().position(|name| name == col_name);
504            if let Some(src_idx) = maybe_src_idx {
505                project_keys.push(src_idx);
506            } else {
507                // If one a column from the table does not exist in the source data, then a default
508                // value will get appended to the end of the input Row from the source data.
509                let hir = plan_default_expr(scx, &col_default, &col_type.scalar_type)?;
510                let mir = hir.lower_uncorrelated(scx.catalog.system_vars())?;
511                project_keys.push(source_column_names.len() + default_exprs.len());
512                default_exprs.push(mir);
513            }
514        }
515
516        let mfp = MapFilterProject::new(source_column_names.len())
517            .map(default_exprs)
518            .project(project_keys);
519        Some(mfp)
520    } else {
521        None
522    };
523
524    // Create a mapping from input data to the table we're copying into.
525    let source_desc = if columns.is_empty() {
526        let indexes = (0..table_desc.arity()).map(ColumnIndex::from_raw);
527        ordering.extend(indexes);
528
529        // The source data should be in the same order as the table.
530        table_desc
531    } else {
532        let columns: Vec<_> = columns.into_iter().map(normalize::column_name).collect();
533        let column_by_name: BTreeMap<&ColumnName, (ColumnIndex, &SqlColumnType)> = table_desc
534            .iter_all()
535            .map(|(idx, name, typ)| (name, (*idx, typ)))
536            .collect();
537
538        let mut names = Vec::with_capacity(columns.len());
539        let mut source_types = Vec::with_capacity(columns.len());
540
541        for c in &columns {
542            if let Some((idx, typ)) = column_by_name.get(c) {
543                ordering.push(*idx);
544                source_types.push((*typ).clone());
545                names.push(c.clone());
546            } else {
547                sql_bail!(
548                    "column {} of relation {} does not exist",
549                    c.quoted(),
550                    item_name.full_name_str().quoted()
551                );
552            }
553        }
554        if let Some(dup) = columns.iter().duplicates().next() {
555            sql_bail!("column {} specified more than once", dup.quoted());
556        }
557
558        // The source data is a different shape than the destination table.
559        RelationDesc::new(SqlRelationType::new(source_types), names)
560    };
561
562    Ok((item.id(), source_desc, ordering, mfp))
563}
564
565/// See the doc comment on [`plan_copy_item`] for the details of what this function returns.
566///
567/// TODO(cf3): Merge this method with [`plan_copy_item`].
568pub fn plan_copy_from(
569    scx: &StatementContext,
570    table_name: ResolvedItemName,
571    columns: Vec<Ident>,
572) -> Result<
573    (
574        CatalogItemId,
575        RelationDesc,
576        Vec<ColumnIndex>,
577        Option<MapFilterProject>,
578    ),
579    PlanError,
580> {
581    let table = scx.get_item_by_resolved_name(&table_name)?;
582
583    // Validate the target of the insert.
584    if table.item_type() != CatalogItemType::Table {
585        sql_bail!(
586            "cannot insert into {} '{}'",
587            table.item_type(),
588            table_name.full_name_str()
589        );
590    }
591
592    let _ = table.writable_table_details().ok_or_else(|| {
593        sql_err!(
594            "cannot insert into non-writeable table '{}'",
595            table_name.full_name_str()
596        )
597    })?;
598
599    if table.id().is_system() {
600        sql_bail!(
601            "cannot insert into system table '{}'",
602            table_name.full_name_str()
603        );
604    }
605    let (id, desc, ordering, mfp) = plan_copy_item(scx, table_name, columns)?;
606
607    Ok((id, desc, ordering, mfp))
608}
609
610/// Builds a plan that adds the default values for the missing columns and re-orders
611/// the datums in the given rows to match the order in the target table.
612pub fn plan_copy_from_rows(
613    pcx: &PlanContext,
614    catalog: &dyn SessionCatalog,
615    target_id: CatalogItemId,
616    target_name: String,
617    columns: Vec<ColumnIndex>,
618    rows: Vec<mz_repr::Row>,
619) -> Result<HirRelationExpr, PlanError> {
620    let scx = StatementContext::new(Some(pcx), catalog);
621
622    // Always copy at the latest version of the table.
623    let table = catalog
624        .try_get_item(&target_id)
625        .ok_or_else(|| PlanError::CopyFromTargetTableDropped { target_name })?
626        .at_version(RelationVersionSelector::Latest);
627
628    let mut defaults = table
629        .writable_table_details()
630        .ok_or_else(|| sql_err!("cannot copy into non-writeable table"))?
631        .to_vec();
632
633    for default in &mut defaults {
634        transform_ast::transform(&scx, default)?;
635    }
636
637    let desc = table
638        .relation_desc()
639        .ok_or_else(|| sql_err!("item does not have a relation description"))?;
640    let column_types = columns
641        .iter()
642        .map(|x| desc.get_type(x).clone())
643        .map(|mut x| {
644            // Null constraint is enforced later, when inserting the row in the table.
645            // Without this, an assert is hit during lowering.
646            x.nullable = true;
647            x
648        })
649        .collect();
650    let typ = SqlRelationType::new(column_types);
651    let expr = HirRelationExpr::Constant {
652        rows,
653        typ: typ.clone(),
654    };
655
656    // Exit early with just the raw constant if we know that all columns are present
657    // and in the correct order. This lets us bypass expensive downstream optimizations
658    // more easily, as at every stage we know this expression is nothing more than
659    // a constant (as opposed to e.g. a constant with with an identity map and identity
660    // projection).
661    let default: Vec<_> = (0..desc.arity()).map(ColumnIndex::from_raw).collect();
662    if columns == default {
663        return Ok(expr);
664    }
665
666    // Fill in any omitted columns and rearrange into correct order
667    let mut map_exprs = vec![];
668    let mut project_key = Vec::with_capacity(desc.arity());
669
670    // Maps from table column index to position in the source query
671    let col_to_source: BTreeMap<_, _> = columns.iter().enumerate().map(|(a, b)| (b, a)).collect();
672
673    let column_details = desc.iter_all().zip_eq(defaults);
674    for ((col_idx, _col_name, col_typ), default) in column_details {
675        if let Some(src_idx) = col_to_source.get(&col_idx) {
676            project_key.push(*src_idx);
677        } else {
678            let hir = plan_default_expr(&scx, &default, &col_typ.scalar_type)?;
679            project_key.push(typ.arity() + map_exprs.len());
680            map_exprs.push(hir);
681        }
682    }
683
684    Ok(expr.map(map_exprs).project(project_key))
685}
686
687/// Common information used for DELETE, UPDATE, and INSERT INTO ... SELECT plans.
688pub struct ReadThenWritePlan {
689    pub id: CatalogItemId,
690    /// Read portion of query.
691    ///
692    /// NOTE: Even if the WHERE filter is left off, we still need to perform a read to generate
693    /// retractions.
694    pub selection: HirRelationExpr,
695    /// Map from column index to SET expression. Empty for DELETE statements.
696    pub assignments: BTreeMap<usize, HirScalarExpr>,
697    pub finishing: RowSetFinishing,
698}
699
700pub fn plan_delete_query(
701    scx: &StatementContext,
702    mut delete_stmt: DeleteStatement<Aug>,
703) -> Result<ReadThenWritePlan, PlanError> {
704    transform_ast::transform(scx, &mut delete_stmt)?;
705
706    let qcx = QueryContext::root(scx, QueryLifetime::OneShot);
707    plan_mutation_query_inner(
708        qcx,
709        delete_stmt.table_name,
710        delete_stmt.alias,
711        delete_stmt.using,
712        vec![],
713        delete_stmt.selection,
714    )
715}
716
717pub fn plan_update_query(
718    scx: &StatementContext,
719    mut update_stmt: UpdateStatement<Aug>,
720) -> Result<ReadThenWritePlan, PlanError> {
721    transform_ast::transform(scx, &mut update_stmt)?;
722
723    let qcx = QueryContext::root(scx, QueryLifetime::OneShot);
724
725    plan_mutation_query_inner(
726        qcx,
727        update_stmt.table_name,
728        update_stmt.alias,
729        vec![],
730        update_stmt.assignments,
731        update_stmt.selection,
732    )
733}
734
735pub fn plan_mutation_query_inner(
736    qcx: QueryContext,
737    table_name: ResolvedItemName,
738    alias: Option<TableAlias>,
739    using: Vec<TableWithJoins<Aug>>,
740    assignments: Vec<Assignment<Aug>>,
741    selection: Option<Expr<Aug>>,
742) -> Result<ReadThenWritePlan, PlanError> {
743    // Get ID and version of the relation desc.
744    let (id, version) = match table_name {
745        ResolvedItemName::Item { id, version, .. } => (id, version),
746        _ => sql_bail!("cannot mutate non-user table"),
747    };
748
749    // Perform checks on item with given ID.
750    let item = qcx.scx.get_item(&id).at_version(version);
751    if item.item_type() != CatalogItemType::Table {
752        sql_bail!(
753            "cannot mutate {} '{}'",
754            item.item_type(),
755            table_name.full_name_str()
756        );
757    }
758    let _ = item.writable_table_details().ok_or_else(|| {
759        sql_err!(
760            "cannot mutate non-writeable table '{}'",
761            table_name.full_name_str()
762        )
763    })?;
764    if id.is_system() {
765        sql_bail!(
766            "cannot mutate system table '{}'",
767            table_name.full_name_str()
768        );
769    }
770
771    // Derive structs for operation from validated table
772    let (mut get, scope) = qcx.resolve_table_name(table_name)?;
773    let scope = plan_table_alias(scope, alias.as_ref())?;
774    let desc = item.relation_desc().expect("table has desc");
775    let relation_type = qcx.relation_type(&get);
776
777    if using.is_empty() {
778        if let Some(expr) = selection {
779            let ecx = &ExprContext {
780                qcx: &qcx,
781                name: "WHERE clause",
782                scope: &scope,
783                relation_type: &relation_type,
784                allow_aggregates: false,
785                allow_subqueries: true,
786                allow_parameters: true,
787                allow_windows: false,
788            };
789            let expr = plan_expr(ecx, &expr)?.type_as(ecx, &SqlScalarType::Bool)?;
790            get = get.filter(vec![expr]);
791        }
792    } else {
793        get = handle_mutation_using_clause(&qcx, selection, using, get, scope.clone())?;
794    }
795
796    let mut sets = BTreeMap::new();
797    for Assignment { id, value } in assignments {
798        // Get the index and type of the column.
799        let name = normalize::column_name(id);
800        match desc.get_by_name(&name) {
801            Some((idx, typ)) => {
802                let ecx = &ExprContext {
803                    qcx: &qcx,
804                    name: "SET clause",
805                    scope: &scope,
806                    relation_type: &relation_type,
807                    allow_aggregates: false,
808                    allow_subqueries: false,
809                    allow_parameters: true,
810                    allow_windows: false,
811                };
812                let expr = plan_expr(ecx, &value)?.cast_to(
813                    ecx,
814                    CastContext::Assignment,
815                    &typ.scalar_type,
816                )?;
817
818                if sets.insert(idx, expr).is_some() {
819                    sql_bail!("column {} set twice", name)
820                }
821            }
822            None => sql_bail!("unknown column {}", name),
823        };
824    }
825
826    let finishing = RowSetFinishing {
827        order_by: vec![],
828        limit: None,
829        offset: 0,
830        project: (0..desc.arity()).collect(),
831    };
832
833    Ok(ReadThenWritePlan {
834        id,
835        selection: get,
836        finishing,
837        assignments: sets,
838    })
839}
840
841// Adjust `get` to perform an existential subquery on `using` accounting for
842// `selection`.
843//
844// If `USING`, we essentially want to rewrite the query as a correlated
845// existential subquery, i.e.
846// ```
847// ...WHERE EXISTS (SELECT 1 FROM <using> WHERE <selection>)
848// ```
849// However, we can't do that directly because of esoteric rules w/r/t `lateral`
850// subqueries.
851// https://github.com/postgres/postgres/commit/158b7fa6a34006bdc70b515e14e120d3e896589b
852fn handle_mutation_using_clause(
853    qcx: &QueryContext,
854    selection: Option<Expr<Aug>>,
855    using: Vec<TableWithJoins<Aug>>,
856    get: HirRelationExpr,
857    outer_scope: Scope,
858) -> Result<HirRelationExpr, PlanError> {
859    // Plan `USING` as a cross-joined `FROM` without knowledge of the
860    // statement's `FROM` target. This prevents `lateral` subqueries from
861    // "seeing" the `FROM` target.
862    let (mut using_rel_expr, using_scope) =
863        using.into_iter().try_fold(plan_join_identity(), |l, twj| {
864            let (left, left_scope) = l;
865            plan_join(
866                qcx,
867                left,
868                left_scope,
869                &Join {
870                    relation: TableFactor::NestedJoin {
871                        join: Box::new(twj),
872                        alias: None,
873                    },
874                    join_operator: JoinOperator::CrossJoin,
875                },
876            )
877        })?;
878
879    if let Some(expr) = selection {
880        // Join `FROM` with `USING` tables, like `USING..., FROM`. This gives us
881        // PG-like semantics e.g. expressing ambiguous column references. We put
882        // `USING...` first for no real reason, but making a different decision
883        // would require adjusting the column references on this relation
884        // differently.
885        let on = HirScalarExpr::literal_true();
886        let joined = using_rel_expr
887            .clone()
888            .join(get.clone(), on, JoinKind::Inner);
889        let joined_scope = using_scope.product(outer_scope)?;
890        let joined_relation_type = qcx.relation_type(&joined);
891
892        let ecx = &ExprContext {
893            qcx,
894            name: "WHERE clause",
895            scope: &joined_scope,
896            relation_type: &joined_relation_type,
897            allow_aggregates: false,
898            allow_subqueries: true,
899            allow_parameters: true,
900            allow_windows: false,
901        };
902
903        // Plan the filter expression on `FROM, USING...`.
904        let mut expr = plan_expr(ecx, &expr)?.type_as(ecx, &SqlScalarType::Bool)?;
905
906        // Rewrite all column referring to the `FROM` section of `joined` (i.e.
907        // those to the right of `using_rel_expr`) to instead be correlated to
908        // the outer relation, i.e. `get`.
909        let using_rel_arity = qcx.relation_type(&using_rel_expr).arity();
910        // local import to not get confused with `mz_sql_parser::ast::visit::Visit`
911        use mz_expr::visit::Visit;
912        expr.visit_mut_post(&mut |e| {
913            if let HirScalarExpr::Column(c, _name) = e {
914                if c.column >= using_rel_arity {
915                    c.level += 1;
916                    c.column -= using_rel_arity;
917                };
918            }
919        });
920
921        // Filter `USING` tables like `<using_rel_expr> WHERE <expr>`. Note that
922        // this filters the `USING` tables, _not_ the joined `USING..., FROM`
923        // relation.
924        using_rel_expr = using_rel_expr.filter(vec![expr]);
925    } else {
926        // Check that scopes are at compatible (i.e. do not double-reference
927        // same table), despite lack of selection
928        let _joined_scope = using_scope.product(outer_scope)?;
929    }
930    // From pg: Since the result [of EXISTS (<subquery>)] depends only on
931    // whether any rows are returned, and not on the contents of those rows,
932    // the output list of the subquery is normally unimportant.
933    //
934    // This means we don't need to worry about projecting/mapping any
935    // additional expressions here.
936    //
937    // https://www.postgresql.org/docs/14/functions-subquery.html
938
939    // Filter `get` like `...WHERE EXISTS (<using_rel_expr>)`.
940    Ok(get.filter(vec![using_rel_expr.exists()]))
941}
942
943#[derive(Debug)]
944pub(crate) struct CastRelationError {
945    pub(crate) column: usize,
946    pub(crate) source_type: SqlScalarType,
947    pub(crate) target_type: SqlScalarType,
948}
949
950/// Cast a relation from one type to another using the specified type of cast.
951///
952/// The length of `target_types` must match the arity of `expr`.
953pub(crate) fn cast_relation<'a, I>(
954    qcx: &QueryContext,
955    ccx: CastContext,
956    expr: HirRelationExpr,
957    target_types: I,
958) -> Result<HirRelationExpr, CastRelationError>
959where
960    I: IntoIterator<Item = &'a SqlScalarType>,
961{
962    let ecx = &ExprContext {
963        qcx,
964        name: "values",
965        scope: &Scope::empty(),
966        relation_type: &qcx.relation_type(&expr),
967        allow_aggregates: false,
968        allow_subqueries: true,
969        allow_parameters: true,
970        allow_windows: false,
971    };
972    let mut map_exprs = vec![];
973    let mut project_key = vec![];
974    for (i, target_typ) in target_types.into_iter().enumerate() {
975        let expr = HirScalarExpr::column(i);
976        // We plan every cast and check the evaluated expressions rather than
977        // checking the types directly because of some complex casting rules
978        // between types not expressed in `SqlScalarType` equality.
979        match typeconv::plan_cast(ecx, ccx, expr.clone(), target_typ) {
980            Ok(cast_expr) => {
981                if expr == cast_expr {
982                    // Cast between types was unnecessary
983                    project_key.push(i);
984                } else {
985                    // Cast between types required
986                    project_key.push(ecx.relation_type.arity() + map_exprs.len());
987                    map_exprs.push(cast_expr);
988                }
989            }
990            Err(_) => {
991                return Err(CastRelationError {
992                    column: i,
993                    source_type: ecx.scalar_type(&expr),
994                    target_type: target_typ.clone(),
995                });
996            }
997        }
998    }
999    Ok(expr.map(map_exprs).project(project_key))
1000}
1001
1002/// Plans an expression in the AS OF position of a `SELECT` or `SUBSCRIBE`, or `CREATE MATERIALIZED
1003/// VIEW` statement.
1004pub fn plan_as_of(
1005    scx: &StatementContext,
1006    as_of: Option<AsOf<Aug>>,
1007) -> Result<QueryWhen, PlanError> {
1008    match as_of {
1009        None => Ok(QueryWhen::Immediately),
1010        Some(as_of) => match as_of {
1011            AsOf::At(expr) => Ok(QueryWhen::AtTimestamp(plan_as_of_or_up_to(scx, expr)?)),
1012            AsOf::AtLeast(expr) => Ok(QueryWhen::AtLeastTimestamp(plan_as_of_or_up_to(scx, expr)?)),
1013        },
1014    }
1015}
1016
1017/// Plans and evaluates a scalar expression in a OneShot context to a non-null MzTimestamp.
1018///
1019/// Produces [`PlanError::InvalidAsOfUpTo`] if the expression is
1020/// - not a constant,
1021/// - not castable to MzTimestamp,
1022/// - is null,
1023/// - contains an unmaterializable function,
1024/// - some other evaluation error occurs, e.g., a division by 0,
1025/// - contains aggregates, subqueries, parameters, or window function calls.
1026pub fn plan_as_of_or_up_to(
1027    scx: &StatementContext,
1028    mut expr: Expr<Aug>,
1029) -> Result<mz_repr::Timestamp, PlanError> {
1030    let scope = Scope::empty();
1031    let desc = RelationDesc::empty();
1032    // (Even for a SUBSCRIBE, we need QueryLifetime::OneShot, because the AS OF or UP TO is
1033    // evaluated only once.)
1034    let qcx = QueryContext::root(scx, QueryLifetime::OneShot);
1035    transform_ast::transform(scx, &mut expr)?;
1036    let ecx = &ExprContext {
1037        qcx: &qcx,
1038        name: "AS OF or UP TO",
1039        scope: &scope,
1040        relation_type: desc.typ(),
1041        allow_aggregates: false,
1042        allow_subqueries: false,
1043        allow_parameters: false,
1044        allow_windows: false,
1045    };
1046    let hir = plan_expr(ecx, &expr)?.cast_to(
1047        ecx,
1048        CastContext::Assignment,
1049        &SqlScalarType::MzTimestamp,
1050    )?;
1051    if hir.contains_unmaterializable() {
1052        bail_unsupported!("calling an unmaterializable function in AS OF or UP TO");
1053    }
1054    // At this point, we definitely have a constant expression:
1055    // - it can't contain any unmaterializable functions;
1056    // - it can't refer to any columns.
1057    // But the following can still fail due to a variety of reasons: most commonly, the cast can
1058    // fail, but also a null might appear, or some other evaluation error can happen, e.g., a
1059    // division by 0.
1060    let timestamp = hir
1061        .into_literal_mz_timestamp()
1062        .ok_or_else(|| PlanError::InvalidAsOfUpTo)?;
1063    Ok(timestamp)
1064}
1065
1066/// Plans an expression in the AS position of a `CREATE SECRET`.
1067pub fn plan_secret_as(
1068    scx: &StatementContext,
1069    mut expr: Expr<Aug>,
1070) -> Result<MirScalarExpr, PlanError> {
1071    let scope = Scope::empty();
1072    let desc = RelationDesc::empty();
1073    let qcx = QueryContext::root(scx, QueryLifetime::OneShot);
1074
1075    transform_ast::transform(scx, &mut expr)?;
1076
1077    let ecx = &ExprContext {
1078        qcx: &qcx,
1079        name: "AS",
1080        scope: &scope,
1081        relation_type: desc.typ(),
1082        allow_aggregates: false,
1083        allow_subqueries: false,
1084        allow_parameters: false,
1085        allow_windows: false,
1086    };
1087    let expr = plan_expr(ecx, &expr)?
1088        .type_as(ecx, &SqlScalarType::Bytes)?
1089        .lower_uncorrelated(scx.catalog.system_vars())?;
1090    Ok(expr)
1091}
1092
1093/// Plans an expression in the CHECK position of a `CREATE SOURCE ... FROM WEBHOOK`.
1094pub fn plan_webhook_validate_using(
1095    scx: &StatementContext,
1096    validate_using: CreateWebhookSourceCheck<Aug>,
1097) -> Result<WebhookValidation, PlanError> {
1098    let qcx = QueryContext::root(scx, QueryLifetime::Source);
1099
1100    let CreateWebhookSourceCheck {
1101        options,
1102        using: mut expr,
1103    } = validate_using;
1104
1105    let mut column_typs = vec![];
1106    let mut column_names = vec![];
1107
1108    let (bodies, headers, secrets) = options
1109        .map(|o| (o.bodies, o.headers, o.secrets))
1110        .unwrap_or_default();
1111
1112    // Append all of the bodies so they can be used in the expression.
1113    let mut body_tuples = vec![];
1114    for CreateWebhookSourceBody { alias, use_bytes } in bodies {
1115        let scalar_type = use_bytes
1116            .then_some(SqlScalarType::Bytes)
1117            .unwrap_or(SqlScalarType::String);
1118        let name = alias
1119            .map(|a| a.into_string())
1120            .unwrap_or_else(|| "body".to_string());
1121
1122        column_typs.push(SqlColumnType {
1123            scalar_type,
1124            nullable: false,
1125        });
1126        column_names.push(name);
1127
1128        // Store the column index so we can be sure to provide this body correctly.
1129        let column_idx = column_typs.len() - 1;
1130        // Double check we're consistent with column names.
1131        assert_eq!(
1132            column_idx,
1133            column_names.len() - 1,
1134            "body column names and types don't match"
1135        );
1136        body_tuples.push((column_idx, use_bytes));
1137    }
1138
1139    // Append all of the headers so they can be used in the expression.
1140    let mut header_tuples = vec![];
1141
1142    for CreateWebhookSourceHeader { alias, use_bytes } in headers {
1143        let value_type = use_bytes
1144            .then_some(SqlScalarType::Bytes)
1145            .unwrap_or(SqlScalarType::String);
1146        let name = alias
1147            .map(|a| a.into_string())
1148            .unwrap_or_else(|| "headers".to_string());
1149
1150        column_typs.push(SqlColumnType {
1151            scalar_type: SqlScalarType::Map {
1152                value_type: Box::new(value_type),
1153                custom_id: None,
1154            },
1155            nullable: false,
1156        });
1157        column_names.push(name);
1158
1159        // Store the column index so we can be sure to provide this body correctly.
1160        let column_idx = column_typs.len() - 1;
1161        // Double check we're consistent with column names.
1162        assert_eq!(
1163            column_idx,
1164            column_names.len() - 1,
1165            "header column names and types don't match"
1166        );
1167        header_tuples.push((column_idx, use_bytes));
1168    }
1169
1170    // Append all secrets so they can be used in the expression.
1171    let mut validation_secrets = vec![];
1172
1173    for CreateWebhookSourceSecret {
1174        secret,
1175        alias,
1176        use_bytes,
1177    } in secrets
1178    {
1179        // Either provide the secret to the validation expression as Bytes or a String.
1180        let scalar_type = use_bytes
1181            .then_some(SqlScalarType::Bytes)
1182            .unwrap_or(SqlScalarType::String);
1183
1184        column_typs.push(SqlColumnType {
1185            scalar_type,
1186            nullable: false,
1187        });
1188        let ResolvedItemName::Item {
1189            id,
1190            full_name: FullItemName { item, .. },
1191            ..
1192        } = secret
1193        else {
1194            return Err(PlanError::InvalidSecret(Box::new(secret)));
1195        };
1196
1197        // Plan the expression using the secret's alias, if one is provided.
1198        let name = if let Some(alias) = alias {
1199            alias.into_string()
1200        } else {
1201            item
1202        };
1203        column_names.push(name);
1204
1205        // Get the column index that corresponds for this secret, so we can make sure to provide the
1206        // secrets in the correct order during evaluation.
1207        let column_idx = column_typs.len() - 1;
1208        // Double check that our column names and types match.
1209        assert_eq!(
1210            column_idx,
1211            column_names.len() - 1,
1212            "column names and types don't match"
1213        );
1214
1215        validation_secrets.push(WebhookValidationSecret {
1216            id,
1217            column_idx,
1218            use_bytes,
1219        });
1220    }
1221
1222    let relation_typ = SqlRelationType::new(column_typs);
1223    let desc = RelationDesc::new(relation_typ, column_names.clone());
1224    let scope = Scope::from_source(None, column_names);
1225
1226    transform_ast::transform(scx, &mut expr)?;
1227
1228    let ecx = &ExprContext {
1229        qcx: &qcx,
1230        name: "CHECK",
1231        scope: &scope,
1232        relation_type: desc.typ(),
1233        allow_aggregates: false,
1234        allow_subqueries: false,
1235        allow_parameters: false,
1236        allow_windows: false,
1237    };
1238    let expr = plan_expr(ecx, &expr)?
1239        .type_as(ecx, &SqlScalarType::Bool)?
1240        .lower_uncorrelated(scx.catalog.system_vars())?;
1241    let validation = WebhookValidation {
1242        expression: expr,
1243        relation_desc: desc,
1244        bodies: body_tuples,
1245        headers: header_tuples,
1246        secrets: validation_secrets,
1247    };
1248    Ok(validation)
1249}
1250
1251pub fn plan_default_expr(
1252    scx: &StatementContext,
1253    expr: &Expr<Aug>,
1254    target_ty: &SqlScalarType,
1255) -> Result<HirScalarExpr, PlanError> {
1256    let qcx = QueryContext::root(scx, QueryLifetime::OneShot);
1257    let ecx = &ExprContext {
1258        qcx: &qcx,
1259        name: "DEFAULT expression",
1260        scope: &Scope::empty(),
1261        relation_type: &SqlRelationType::empty(),
1262        allow_aggregates: false,
1263        allow_subqueries: false,
1264        allow_parameters: false,
1265        allow_windows: false,
1266    };
1267    let hir = plan_expr(ecx, expr)?.cast_to(ecx, CastContext::Assignment, target_ty)?;
1268    Ok(hir)
1269}
1270
1271pub fn plan_params<'a>(
1272    scx: &'a StatementContext,
1273    params: Vec<Expr<Aug>>,
1274    desc: &StatementDesc,
1275) -> Result<Params, PlanError> {
1276    if params.len() != desc.param_types.len() {
1277        sql_bail!(
1278            "expected {} params, got {}",
1279            desc.param_types.len(),
1280            params.len()
1281        );
1282    }
1283
1284    let qcx = QueryContext::root(scx, QueryLifetime::OneShot);
1285
1286    let mut datums = Row::default();
1287    let mut packer = datums.packer();
1288    let mut actual_types = Vec::new();
1289    let temp_storage = &RowArena::new();
1290    for (i, (mut expr, expected_ty)) in params.into_iter().zip_eq(&desc.param_types).enumerate() {
1291        transform_ast::transform(scx, &mut expr)?;
1292
1293        let ecx = execute_expr_context(&qcx);
1294        let ex = plan_expr(&ecx, &expr)?.type_as_any(&ecx)?;
1295        let actual_ty = ecx.scalar_type(&ex);
1296        if plan_hypothetical_cast(&ecx, *EXECUTE_CAST_CONTEXT, &actual_ty, expected_ty).is_none() {
1297            return Err(PlanError::WrongParameterType(
1298                i + 1,
1299                ecx.humanize_sql_scalar_type(expected_ty, false),
1300                ecx.humanize_sql_scalar_type(&actual_ty, false),
1301            ));
1302        }
1303        let ex = ex.lower_uncorrelated(scx.catalog.system_vars())?;
1304        let evaled = ex.eval(&[], temp_storage)?;
1305        packer.push(evaled);
1306        actual_types.push(actual_ty);
1307    }
1308    Ok(Params {
1309        datums,
1310        execute_types: actual_types,
1311        expected_types: desc.param_types.clone(),
1312    })
1313}
1314
1315static EXECUTE_CONTEXT_SCOPE: LazyLock<Scope> = LazyLock::new(Scope::empty);
1316static EXECUTE_CONTEXT_REL_TYPE: LazyLock<SqlRelationType> = LazyLock::new(SqlRelationType::empty);
1317
1318/// Returns an `ExprContext` for the expressions in the parameters of an EXECUTE statement.
1319pub(crate) fn execute_expr_context<'a>(qcx: &'a QueryContext<'a>) -> ExprContext<'a> {
1320    ExprContext {
1321        qcx,
1322        name: "EXECUTE",
1323        scope: &EXECUTE_CONTEXT_SCOPE,
1324        relation_type: &EXECUTE_CONTEXT_REL_TYPE,
1325        allow_aggregates: false,
1326        allow_subqueries: false,
1327        allow_parameters: false,
1328        allow_windows: false,
1329    }
1330}
1331
1332/// The CastContext used when matching up the types of parameters passed to EXECUTE.
1333///
1334/// This is an assignment cast also in Postgres, see
1335/// <https://github.com/MaterializeInc/database-issues/issues/9266>
1336pub(crate) static EXECUTE_CAST_CONTEXT: LazyLock<CastContext> =
1337    LazyLock::new(|| CastContext::Assignment);
1338
1339pub fn plan_index_exprs<'a>(
1340    scx: &'a StatementContext,
1341    on_desc: &RelationDesc,
1342    exprs: Vec<Expr<Aug>>,
1343) -> Result<Vec<mz_expr::MirScalarExpr>, PlanError> {
1344    let scope = Scope::from_source(None, on_desc.iter_names());
1345    let qcx = QueryContext::root(scx, QueryLifetime::Index);
1346
1347    let ecx = &ExprContext {
1348        qcx: &qcx,
1349        name: "CREATE INDEX",
1350        scope: &scope,
1351        relation_type: on_desc.typ(),
1352        allow_aggregates: false,
1353        allow_subqueries: false,
1354        allow_parameters: false,
1355        allow_windows: false,
1356    };
1357    let repr_col_types: Vec<ReprColumnType> = on_desc
1358        .typ()
1359        .column_types
1360        .iter()
1361        .map(ReprColumnType::from)
1362        .collect();
1363    let mut out = vec![];
1364    for mut expr in exprs {
1365        transform_ast::transform(scx, &mut expr)?;
1366        let expr = plan_expr_or_col_index(ecx, &expr)?;
1367        let mut expr = expr.lower_uncorrelated(scx.catalog.system_vars())?;
1368        expr.reduce(&repr_col_types);
1369        out.push(expr);
1370    }
1371    Ok(out)
1372}
1373
1374fn plan_expr_or_col_index(ecx: &ExprContext, e: &Expr<Aug>) -> Result<HirScalarExpr, PlanError> {
1375    match check_col_index(ecx.name, e, ecx.relation_type.column_types.len())? {
1376        Some(column) => Ok(HirScalarExpr::column(column)),
1377        _ => plan_expr(ecx, e)?.type_as_any(ecx),
1378    }
1379}
1380
1381fn check_col_index(name: &str, e: &Expr<Aug>, max: usize) -> Result<Option<usize>, PlanError> {
1382    match e {
1383        Expr::Value(Value::Number(n)) => {
1384            let n = n.parse::<usize>().map_err(|e| {
1385                sql_err!("unable to parse column reference in {}: {}: {}", name, n, e)
1386            })?;
1387            if n < 1 || n > max {
1388                sql_bail!(
1389                    "column reference {} in {} is out of range (1 - {})",
1390                    n,
1391                    name,
1392                    max
1393                );
1394            }
1395            Ok(Some(n - 1))
1396        }
1397        _ => Ok(None),
1398    }
1399}
1400
1401struct PlannedQuery {
1402    expr: HirRelationExpr,
1403    scope: Scope,
1404    order_by: Vec<ColumnOrder>,
1405    limit: Option<HirScalarExpr>,
1406    /// `offset` is either
1407    /// - an Int64 literal
1408    /// - or contains parameters. (If it contains parameters, then after parameter substitution it
1409    ///   should also be `is_constant` and reduce to an Int64 literal, but we check this only
1410    ///   later.)
1411    offset: HirScalarExpr,
1412    project: Vec<usize>,
1413    group_size_hints: GroupSizeHints,
1414}
1415
1416fn plan_query(qcx: &mut QueryContext, q: &Query<Aug>) -> Result<PlannedQuery, PlanError> {
1417    qcx.checked_recur_mut(|qcx| plan_query_inner(qcx, q))
1418}
1419
1420fn plan_query_inner(qcx: &mut QueryContext, q: &Query<Aug>) -> Result<PlannedQuery, PlanError> {
1421    // Plan CTEs and introduce bindings to `qcx.ctes`. Returns shadowed bindings
1422    // for the identifiers, so that they can be re-installed before returning.
1423    let cte_bindings = plan_ctes(qcx, q)?;
1424
1425    let limit = match &q.limit {
1426        None => None,
1427        Some(Limit {
1428            quantity,
1429            with_ties: false,
1430        }) => {
1431            let ecx = &ExprContext {
1432                qcx,
1433                name: "LIMIT",
1434                scope: &Scope::empty(),
1435                relation_type: &SqlRelationType::empty(),
1436                allow_aggregates: false,
1437                allow_subqueries: true,
1438                allow_parameters: true,
1439                allow_windows: false,
1440            };
1441            let limit = plan_expr(ecx, quantity)?;
1442            let limit = limit.cast_to(ecx, CastContext::Explicit, &SqlScalarType::Int64)?;
1443
1444            let limit = if limit.is_constant() {
1445                let arena = RowArena::new();
1446                let limit = limit.lower_uncorrelated(qcx.scx.catalog.system_vars())?;
1447
1448                // TODO: Don't use ? on eval, but instead wrap the error and add the information
1449                // that the error happened in a LIMIT clause, so that we have better error msg for
1450                // something like `SELECT 5 LIMIT 'aaa'`.
1451                match limit.eval(&[], &arena)? {
1452                    d @ Datum::Int64(v) if v >= 0 => {
1453                        HirScalarExpr::literal(d, SqlScalarType::Int64)
1454                    }
1455                    d @ Datum::Null => HirScalarExpr::literal(d, SqlScalarType::Int64),
1456                    Datum::Int64(_) => sql_bail!("LIMIT must not be negative"),
1457                    _ => sql_bail!("constant LIMIT expression must reduce to an INT or NULL value"),
1458                }
1459            } else {
1460                // Gate non-constant LIMIT expressions behind a feature flag
1461                qcx.scx
1462                    .require_feature_flag(&vars::ENABLE_EXPRESSIONS_IN_LIMIT_SYNTAX)?;
1463                limit
1464            };
1465
1466            Some(limit)
1467        }
1468        Some(Limit {
1469            quantity: _,
1470            with_ties: true,
1471        }) => bail_unsupported!("FETCH ... WITH TIES"),
1472    };
1473
1474    let offset = match &q.offset {
1475        None => HirScalarExpr::literal(Datum::Int64(0), SqlScalarType::Int64),
1476        Some(offset) => {
1477            let ecx = &ExprContext {
1478                qcx,
1479                name: "OFFSET",
1480                scope: &Scope::empty(),
1481                relation_type: &SqlRelationType::empty(),
1482                allow_aggregates: false,
1483                allow_subqueries: false,
1484                allow_parameters: true,
1485                allow_windows: false,
1486            };
1487            let offset = plan_expr(ecx, offset)?;
1488            let offset = offset.cast_to(ecx, CastContext::Explicit, &SqlScalarType::Int64)?;
1489
1490            let offset = if offset.is_constant() {
1491                // Simplify it to a literal or error out. (E.g., the cast inserted above may fail.)
1492                let offset_value = offset_into_value(offset)?;
1493                HirScalarExpr::literal(Datum::Int64(offset_value), SqlScalarType::Int64)
1494            } else {
1495                // The only case when this is allowed to not be a constant is if it contains
1496                // parameters. (In which case, we'll later check that it's a constant after
1497                // parameter binding.)
1498                if !offset.contains_parameters() {
1499                    return Err(PlanError::InvalidOffset(format!(
1500                        "must be simplifiable to a constant, possibly after parameter binding, got {}",
1501                        offset
1502                    )));
1503                }
1504                offset
1505            };
1506            offset
1507        }
1508    };
1509
1510    let mut planned_query = match &q.body {
1511        SetExpr::Select(s) => {
1512            // Extract query options.
1513            let select_option_extracted = SelectOptionExtracted::try_from(s.options.clone())?;
1514            let group_size_hints = GroupSizeHints::try_from(select_option_extracted)?;
1515
1516            let plan = plan_select_from_where(qcx, *s.clone(), q.order_by.clone())?;
1517            PlannedQuery {
1518                expr: plan.expr,
1519                scope: plan.scope,
1520                order_by: plan.order_by,
1521                project: plan.project,
1522                limit,
1523                offset,
1524                group_size_hints,
1525            }
1526        }
1527        _ => {
1528            let (expr, scope) = plan_set_expr(qcx, &q.body)?;
1529            let ecx = &ExprContext {
1530                qcx,
1531                name: "ORDER BY clause of a set expression",
1532                scope: &scope,
1533                relation_type: &qcx.relation_type(&expr),
1534                allow_aggregates: false,
1535                allow_subqueries: true,
1536                allow_parameters: true,
1537                allow_windows: false,
1538            };
1539            let output_columns: Vec<_> = scope.column_names().enumerate().collect();
1540            let (order_by, map_exprs) = plan_order_by_exprs(ecx, &q.order_by, &output_columns)?;
1541            let project = (0..ecx.relation_type.arity()).collect();
1542            PlannedQuery {
1543                expr: expr.map(map_exprs),
1544                scope,
1545                order_by,
1546                limit,
1547                project,
1548                offset,
1549                group_size_hints: GroupSizeHints::default(),
1550            }
1551        }
1552    };
1553
1554    // Both introduce `Let` bindings atop `result` and re-install shadowed bindings.
1555    match &q.ctes {
1556        CteBlock::Simple(_) => {
1557            for (id, value, shadowed_val) in cte_bindings.into_iter().rev() {
1558                if let Some(cte) = qcx.ctes.remove(&id) {
1559                    planned_query.expr = HirRelationExpr::Let {
1560                        name: cte.name,
1561                        id: id.clone(),
1562                        value: Box::new(value),
1563                        body: Box::new(planned_query.expr),
1564                    };
1565                }
1566                if let Some(shadowed_val) = shadowed_val {
1567                    qcx.ctes.insert(id, shadowed_val);
1568                }
1569            }
1570        }
1571        CteBlock::MutuallyRecursive(MutRecBlock { options, ctes: _ }) => {
1572            let MutRecBlockOptionExtracted {
1573                recursion_limit,
1574                return_at_recursion_limit,
1575                error_at_recursion_limit,
1576                seen: _,
1577            } = MutRecBlockOptionExtracted::try_from(options.clone())?;
1578            let limit = match (
1579                recursion_limit,
1580                return_at_recursion_limit,
1581                error_at_recursion_limit,
1582            ) {
1583                (None, None, None) => None,
1584                (Some(max_iters), None, None) => {
1585                    Some((max_iters, LetRecLimit::RETURN_AT_LIMIT_DEFAULT))
1586                }
1587                (None, Some(max_iters), None) => Some((max_iters, true)),
1588                (None, None, Some(max_iters)) => Some((max_iters, false)),
1589                _ => {
1590                    return Err(InvalidWmrRecursionLimit(
1591                        "More than one recursion limit given. \
1592                         Please give at most one of RECURSION LIMIT, \
1593                         ERROR AT RECURSION LIMIT, \
1594                         RETURN AT RECURSION LIMIT."
1595                            .to_owned(),
1596                    ));
1597                }
1598            }
1599            .try_map(|(max_iters, return_at_limit)| {
1600                Ok::<LetRecLimit, PlanError>(LetRecLimit {
1601                    max_iters: NonZeroU64::new(*max_iters).ok_or(InvalidWmrRecursionLimit(
1602                        "Recursion limit has to be greater than 0.".to_owned(),
1603                    ))?,
1604                    return_at_limit: *return_at_limit,
1605                })
1606            })?;
1607
1608            let mut bindings = Vec::new();
1609            for (id, value, shadowed_val) in cte_bindings.into_iter() {
1610                if let Some(cte) = qcx.ctes.remove(&id) {
1611                    bindings.push((cte.name, id, value, cte.desc.into_typ()));
1612                }
1613                if let Some(shadowed_val) = shadowed_val {
1614                    qcx.ctes.insert(id, shadowed_val);
1615                }
1616            }
1617            if !bindings.is_empty() {
1618                planned_query.expr = HirRelationExpr::LetRec {
1619                    limit,
1620                    bindings,
1621                    body: Box::new(planned_query.expr),
1622                }
1623            }
1624        }
1625    }
1626
1627    Ok(planned_query)
1628}
1629
1630/// Converts an OFFSET expression into a value.
1631pub(crate) fn offset_into_value(offset: HirScalarExpr) -> Result<i64, PlanError> {
1632    let offset = offset
1633        .try_into_literal_int64()
1634        .map_err(|err| PlanError::InvalidOffset(err.to_string_with_causes()))?;
1635    if offset < 0 {
1636        return Err(negative_offset_error(offset));
1637    }
1638    Ok(offset)
1639}
1640
1641pub(crate) fn negative_offset_error(offset: i64) -> PlanError {
1642    PlanError::InvalidOffset(format!("must not be negative, got {}", offset))
1643}
1644
1645generate_extracted_config!(
1646    MutRecBlockOption,
1647    (RecursionLimit, u64),
1648    (ReturnAtRecursionLimit, u64),
1649    (ErrorAtRecursionLimit, u64)
1650);
1651
1652/// Creates plans for CTEs and introduces them to `qcx.ctes`.
1653///
1654/// Returns for each identifier a planned `HirRelationExpr` value, and an optional
1655/// shadowed value that can be reinstalled once the planning has completed.
1656pub fn plan_ctes(
1657    qcx: &mut QueryContext,
1658    q: &Query<Aug>,
1659) -> Result<Vec<(LocalId, HirRelationExpr, Option<CteDesc>)>, PlanError> {
1660    // Accumulate planned expressions and shadowed descriptions.
1661    let mut result = Vec::new();
1662    // Retain the old descriptions of CTE bindings so that we can restore them
1663    // after we're done planning this SELECT.
1664    let mut shadowed_descs = BTreeMap::new();
1665
1666    // A reused identifier indicates a reused name.
1667    if let Some(ident) = q.ctes.bound_identifiers().duplicates().next() {
1668        sql_bail!(
1669            "WITH query name {} specified more than once",
1670            normalize::ident_ref(ident).quoted()
1671        )
1672    }
1673
1674    match &q.ctes {
1675        CteBlock::Simple(ctes) => {
1676            // Plan all CTEs, introducing the types for non-recursive CTEs as we go.
1677            for cte in ctes.iter() {
1678                let cte_name = normalize::ident(cte.alias.name.clone());
1679                let (val, scope) = plan_nested_query(qcx, &cte.query)?;
1680                let typ = qcx.relation_type(&val);
1681                let mut desc = RelationDesc::new(typ, scope.column_names());
1682                plan_utils::maybe_rename_columns(
1683                    format!("CTE {}", cte.alias.name),
1684                    &mut desc,
1685                    &cte.alias.columns,
1686                )?;
1687                // Capture the prior value if it exists, so that it can be re-installed.
1688                let shadowed = qcx.ctes.insert(
1689                    cte.id,
1690                    CteDesc {
1691                        name: cte_name,
1692                        desc,
1693                    },
1694                );
1695
1696                result.push((cte.id, val, shadowed));
1697            }
1698        }
1699        CteBlock::MutuallyRecursive(MutRecBlock { options: _, ctes }) => {
1700            // Insert column types into `qcx.ctes` first for recursive bindings.
1701            for cte in ctes.iter() {
1702                let cte_name = normalize::ident(cte.name.clone());
1703                let mut desc_columns = Vec::with_capacity(cte.columns.capacity());
1704                for column in cte.columns.iter() {
1705                    desc_columns.push((
1706                        normalize::column_name(column.name.clone()),
1707                        SqlColumnType {
1708                            scalar_type: scalar_type_from_sql(qcx.scx, &column.data_type)?,
1709                            nullable: true,
1710                        },
1711                    ));
1712                }
1713                let desc = RelationDesc::from_names_and_types(desc_columns);
1714                let shadowed = qcx.ctes.insert(
1715                    cte.id,
1716                    CteDesc {
1717                        name: cte_name,
1718                        desc,
1719                    },
1720                );
1721                // Capture the prior value if it exists, so that it can be re-installed.
1722                if let Some(shadowed) = shadowed {
1723                    shadowed_descs.insert(cte.id, shadowed);
1724                }
1725            }
1726
1727            // Plan all CTEs and validate the proposed types.
1728            for cte in ctes.iter() {
1729                let (val, _scope) = plan_nested_query(qcx, &cte.query)?;
1730
1731                let proposed_typ = qcx.ctes[&cte.id].desc.typ();
1732
1733                if proposed_typ.column_types.iter().any(|c| !c.nullable) {
1734                    // Once WMR CTEs support NOT NULL constraints, check that
1735                    // nullability of derived column types are compatible.
1736                    sql_bail!(
1737                        "[internal error]: WMR CTEs do not support NOT NULL constraints on proposed column types"
1738                    );
1739                }
1740
1741                if !proposed_typ.keys.is_empty() {
1742                    // Once WMR CTEs support keys, check that keys exactly
1743                    // overlap.
1744                    sql_bail!("[internal error]: WMR CTEs do not support keys");
1745                }
1746
1747                // Validate that the derived and proposed types are the same.
1748                let derived_typ = qcx.relation_type(&val);
1749
1750                let type_err = |proposed_typ: &SqlRelationType, derived_typ: SqlRelationType| {
1751                    let cte_name = normalize::ident(cte.name.clone());
1752                    let proposed_typ = proposed_typ
1753                        .column_types
1754                        .iter()
1755                        .map(|ty| qcx.humanize_sql_scalar_type(&ty.scalar_type, false))
1756                        .collect::<Vec<_>>();
1757                    let inferred_typ = derived_typ
1758                        .column_types
1759                        .iter()
1760                        .map(|ty| qcx.humanize_sql_scalar_type(&ty.scalar_type, false))
1761                        .collect::<Vec<_>>();
1762                    Err(PlanError::RecursiveTypeMismatch(
1763                        cte_name,
1764                        proposed_typ,
1765                        inferred_typ,
1766                    ))
1767                };
1768
1769                if derived_typ.column_types.len() != proposed_typ.column_types.len() {
1770                    return type_err(proposed_typ, derived_typ);
1771                }
1772
1773                // Cast derived types to proposed types or error.
1774                let val = match cast_relation(
1775                    qcx,
1776                    // Choose `CastContext::Assignment`` because the user has
1777                    // been explicit about the types they expect. Choosing
1778                    // `CastContext::Implicit` is not "strong" enough to impose
1779                    // typmods from proposed types onto values.
1780                    CastContext::Assignment,
1781                    val,
1782                    proposed_typ.column_types.iter().map(|c| &c.scalar_type),
1783                ) {
1784                    Ok(val) => val,
1785                    Err(_) => return type_err(proposed_typ, derived_typ),
1786                };
1787
1788                result.push((cte.id, val, shadowed_descs.remove(&cte.id)));
1789            }
1790        }
1791    }
1792
1793    Ok(result)
1794}
1795
1796pub fn plan_nested_query(
1797    qcx: &mut QueryContext,
1798    q: &Query<Aug>,
1799) -> Result<(HirRelationExpr, Scope), PlanError> {
1800    let PlannedQuery {
1801        mut expr,
1802        scope,
1803        order_by,
1804        limit,
1805        offset,
1806        project,
1807        group_size_hints,
1808    } = qcx.checked_recur_mut(|qcx| plan_query(qcx, q))?;
1809    // A nested query is an unordered relation. Its `ORDER BY` is only observable
1810    // in combination with a row-limiting clause (`LIMIT`/`OFFSET`), which selects
1811    // which rows survive. Without such a clause the ordering has no defined
1812    // meaning, so it is dropped rather than materialized into a `TopK`.
1813    //
1814    // NOTE: This diverges from PostgreSQL, where an order-sensitive aggregate
1815    // (`array_agg`, `string_agg`, ...) in the outer query observes a sorted
1816    // subquery's output as an executor artifact. That behavior is not guaranteed
1817    // by the SQL standard and PostgreSQL itself documents it as fragile. Callers
1818    // that need a specific aggregation order must use the in-aggregate
1819    // `agg(value ORDER BY ...)` form instead.
1820    if limit.is_some()
1821        || !offset
1822            .clone()
1823            .try_into_literal_int64()
1824            .is_ok_and(|offset| offset == 0)
1825    {
1826        expr = HirRelationExpr::top_k(
1827            expr,
1828            vec![],
1829            order_by,
1830            limit,
1831            offset,
1832            group_size_hints.limit_input_group_size,
1833        );
1834    }
1835    Ok((expr.project(project), scope))
1836}
1837
1838fn plan_set_expr(
1839    qcx: &mut QueryContext,
1840    q: &SetExpr<Aug>,
1841) -> Result<(HirRelationExpr, Scope), PlanError> {
1842    match q {
1843        SetExpr::Select(select) => {
1844            let order_by_exprs = Vec::new();
1845            let plan = plan_select_from_where(qcx, *select.clone(), order_by_exprs)?;
1846            // We didn't provide any `order_by_exprs`, so `plan_select_from_where`
1847            // should not have planned any ordering.
1848            assert!(plan.order_by.is_empty());
1849            Ok((plan.expr.project(plan.project), plan.scope))
1850        }
1851        SetExpr::SetOperation {
1852            op,
1853            all,
1854            left,
1855            right,
1856        } => {
1857            // Plan the LHS and RHS.
1858            let (left_expr, left_scope) = qcx.checked_recur_mut(|qcx| plan_set_expr(qcx, left))?;
1859            let (right_expr, right_scope) =
1860                qcx.checked_recur_mut(|qcx| plan_set_expr(qcx, right))?;
1861
1862            // Validate that the LHS and RHS are the same width.
1863            let left_type = qcx.relation_type(&left_expr);
1864            let right_type = qcx.relation_type(&right_expr);
1865            if left_type.arity() != right_type.arity() {
1866                sql_bail!(
1867                    "each {} query must have the same number of columns: {} vs {}",
1868                    op,
1869                    left_type.arity(),
1870                    right_type.arity(),
1871                );
1872            }
1873
1874            // Match the types of the corresponding columns on the LHS and RHS
1875            // using the normal type coercion rules. This is equivalent to
1876            // `coerce_homogeneous_exprs`, but implemented in terms of
1877            // `HirRelationExpr` rather than `HirScalarExpr`.
1878            let left_ecx = &ExprContext {
1879                qcx,
1880                name: &op.to_string(),
1881                scope: &left_scope,
1882                relation_type: &left_type,
1883                allow_aggregates: false,
1884                allow_subqueries: false,
1885                allow_parameters: false,
1886                allow_windows: false,
1887            };
1888            let right_ecx = &ExprContext {
1889                qcx,
1890                name: &op.to_string(),
1891                scope: &right_scope,
1892                relation_type: &right_type,
1893                allow_aggregates: false,
1894                allow_subqueries: false,
1895                allow_parameters: false,
1896                allow_windows: false,
1897            };
1898            let mut left_casts = vec![];
1899            let mut right_casts = vec![];
1900            for (i, (left_type, right_type)) in left_type
1901                .column_types
1902                .iter()
1903                .zip_eq(right_type.column_types.iter())
1904                .enumerate()
1905            {
1906                let types = &[
1907                    CoercibleScalarType::Coerced(left_type.scalar_type.clone()),
1908                    CoercibleScalarType::Coerced(right_type.scalar_type.clone()),
1909                ];
1910                let target =
1911                    typeconv::guess_best_common_type(&left_ecx.with_name(&op.to_string()), types)?;
1912                match typeconv::plan_cast(
1913                    left_ecx,
1914                    CastContext::Implicit,
1915                    HirScalarExpr::column(i),
1916                    &target,
1917                ) {
1918                    Ok(expr) => left_casts.push(expr),
1919                    Err(_) => sql_bail!(
1920                        "{} types {} and {} cannot be matched",
1921                        op,
1922                        qcx.humanize_sql_scalar_type(&left_type.scalar_type, false),
1923                        qcx.humanize_sql_scalar_type(&target, false),
1924                    ),
1925                }
1926                match typeconv::plan_cast(
1927                    right_ecx,
1928                    CastContext::Implicit,
1929                    HirScalarExpr::column(i),
1930                    &target,
1931                ) {
1932                    Ok(expr) => right_casts.push(expr),
1933                    Err(_) => sql_bail!(
1934                        "{} types {} and {} cannot be matched",
1935                        op,
1936                        qcx.humanize_sql_scalar_type(&target, false),
1937                        qcx.humanize_sql_scalar_type(&right_type.scalar_type, false),
1938                    ),
1939                }
1940            }
1941            let lhs = if left_casts
1942                .iter()
1943                .enumerate()
1944                .any(|(i, e)| e != &HirScalarExpr::column(i))
1945            {
1946                let project_key: Vec<_> = (left_type.arity()..left_type.arity() * 2).collect();
1947                left_expr.map(left_casts).project(project_key)
1948            } else {
1949                left_expr
1950            };
1951            let rhs = if right_casts
1952                .iter()
1953                .enumerate()
1954                .any(|(i, e)| e != &HirScalarExpr::column(i))
1955            {
1956                let project_key: Vec<_> = (right_type.arity()..right_type.arity() * 2).collect();
1957                right_expr.map(right_casts).project(project_key)
1958            } else {
1959                right_expr
1960            };
1961
1962            let relation_expr = match op {
1963                SetOperator::Union => {
1964                    if *all {
1965                        lhs.union(rhs)
1966                    } else {
1967                        lhs.union(rhs).distinct()
1968                    }
1969                }
1970                SetOperator::Except => Hir::except(all, lhs, rhs),
1971                SetOperator::Intersect => {
1972                    // Planning below duplicates whichever input ends up on the left, so a
1973                    // left-deep chain of INTERSECTs doubles the plan at every level, i.e. would be
1974                    // exponential. INTERSECT is commutative, so put the cheaper input on the left.
1975                    // A subtree is then only duplicated when it is the smaller of the two, so plan
1976                    // size obeys T(a + b) <= 2*T(a) + T(b) for input sizes a <= b. The worst case
1977                    // is balanced trees, where this solves to O(n^log2(3)) instead of O(2^n).
1978                    let (lhs, rhs) = if lhs.relation_node_count() > rhs.relation_node_count() {
1979                        (rhs, lhs)
1980                    } else {
1981                        (lhs, rhs)
1982                    };
1983                    // TODO: Let's not duplicate the left-hand expression into TWO dataflows!
1984                    // The optimizer de-duplicates at some point, but it would be good to already
1985                    // not duplicate here.
1986                    //
1987                    // Also note that we do *not* need another threshold() at the end of the method chain
1988                    // because the right-hand side of the outer union only produces existing records,
1989                    // i.e., the record counts for differential data flow definitely remain non-negative.
1990                    let left_clone = lhs.clone();
1991                    if *all {
1992                        lhs.union(left_clone.union(rhs.negate()).threshold().negate())
1993                    } else {
1994                        lhs.union(left_clone.union(rhs.negate()).threshold().negate())
1995                            .distinct()
1996                    }
1997                }
1998            };
1999            let scope = Scope::from_source(
2000                None,
2001                // Column names are taken from the left, as in Postgres.
2002                left_scope.column_names(),
2003            );
2004
2005            Ok((relation_expr, scope))
2006        }
2007        SetExpr::Values(Values(values)) => plan_values(qcx, values),
2008        SetExpr::Table(name) => {
2009            let (expr, scope) = qcx.resolve_table_name(name.clone())?;
2010            Ok((expr, scope))
2011        }
2012        SetExpr::Query(query) => {
2013            let (expr, scope) = plan_nested_query(qcx, query)?;
2014            Ok((expr, scope))
2015        }
2016        SetExpr::Show(stmt) => {
2017            // The create SQL definition of involving this query, will have the explicit `SHOW`
2018            // command in it. Many `SHOW` commands will expand into a sub-query that involves the
2019            // current schema of the executing user. When Materialize restarts and tries to re-plan
2020            // these queries, it will only have access to the raw `SHOW` command and have no idea
2021            // what schema to use. As a result Materialize will fail to boot.
2022            //
2023            // Some `SHOW` commands are ok, like `SHOW CLUSTERS`, and there are probably other ways
2024            // around this issue. Such as expanding the `SHOW` command in the SQL definition.
2025            // However, banning show commands in views gives us more flexibility to change their
2026            // output.
2027            //
2028            // TODO(jkosh44) Add message to error that prints out an equivalent view definition
2029            // with all show commands expanded into their equivalent SELECT statements.
2030            if !qcx.lifetime.allow_show() {
2031                return Err(PlanError::ShowCommandInView);
2032            }
2033
2034            // Some SHOW statements are a SELECT query. Others produces Rows
2035            // directly. Convert both of these to the needed Hir and Scope.
2036            fn to_hirscope(
2037                plan: ShowCreatePlan,
2038                desc: StatementDesc,
2039            ) -> Result<(HirRelationExpr, Scope), PlanError> {
2040                let rows = vec![plan.row.iter().collect::<Vec<_>>()];
2041                let desc = desc.relation_desc.ok_or_else(|| {
2042                    internal_err!("statement description missing relation descriptor")
2043                })?;
2044                let scope = Scope::from_source(None, desc.iter_names());
2045                let expr = HirRelationExpr::constant(rows, desc.into_typ());
2046                Ok((expr, scope))
2047            }
2048
2049            match stmt.clone() {
2050                ShowStatement::ShowColumns(stmt) => {
2051                    show::show_columns(qcx.scx, stmt)?.plan_hir(qcx)
2052                }
2053                ShowStatement::ShowCreateConnection(stmt) => to_hirscope(
2054                    show::plan_show_create_connection(qcx.scx, stmt.clone())?,
2055                    show::describe_show_create_connection(qcx.scx, stmt)?,
2056                ),
2057                ShowStatement::ShowCreateCluster(stmt) => to_hirscope(
2058                    show::plan_show_create_cluster(qcx.scx, stmt.clone())?,
2059                    show::describe_show_create_cluster(qcx.scx, stmt)?,
2060                ),
2061                ShowStatement::ShowCreateIndex(stmt) => to_hirscope(
2062                    show::plan_show_create_index(qcx.scx, stmt.clone())?,
2063                    show::describe_show_create_index(qcx.scx, stmt)?,
2064                ),
2065                ShowStatement::ShowCreateSink(stmt) => to_hirscope(
2066                    show::plan_show_create_sink(qcx.scx, stmt.clone())?,
2067                    show::describe_show_create_sink(qcx.scx, stmt)?,
2068                ),
2069                ShowStatement::ShowCreateSource(stmt) => to_hirscope(
2070                    show::plan_show_create_source(qcx.scx, stmt.clone())?,
2071                    show::describe_show_create_source(qcx.scx, stmt)?,
2072                ),
2073                ShowStatement::ShowCreateTable(stmt) => to_hirscope(
2074                    show::plan_show_create_table(qcx.scx, stmt.clone())?,
2075                    show::describe_show_create_table(qcx.scx, stmt)?,
2076                ),
2077                ShowStatement::ShowCreateView(stmt) => to_hirscope(
2078                    show::plan_show_create_view(qcx.scx, stmt.clone())?,
2079                    show::describe_show_create_view(qcx.scx, stmt)?,
2080                ),
2081                ShowStatement::ShowCreateMaterializedView(stmt) => to_hirscope(
2082                    show::plan_show_create_materialized_view(qcx.scx, stmt.clone())?,
2083                    show::describe_show_create_materialized_view(qcx.scx, stmt)?,
2084                ),
2085                ShowStatement::ShowCreateType(stmt) => to_hirscope(
2086                    show::plan_show_create_type(qcx.scx, stmt.clone())?,
2087                    show::describe_show_create_type(qcx.scx, stmt)?,
2088                ),
2089                ShowStatement::ShowObjects(stmt) => {
2090                    show::show_objects(qcx.scx, stmt)?.plan_hir(qcx)
2091                }
2092                ShowStatement::ShowVariable(_) => bail_unsupported!("SHOW variable in subqueries"),
2093                ShowStatement::InspectShard(_) => sql_bail!("unsupported INSPECT statement"),
2094            }
2095        }
2096    }
2097}
2098
2099/// Plans a `VALUES` clause that appears in a `SELECT` statement.
2100fn plan_values(
2101    qcx: &QueryContext,
2102    values: &[Vec<Expr<Aug>>],
2103) -> Result<(HirRelationExpr, Scope), PlanError> {
2104    assert!(!values.is_empty());
2105
2106    let ecx = &ExprContext {
2107        qcx,
2108        name: "VALUES",
2109        scope: &Scope::empty(),
2110        relation_type: &SqlRelationType::empty(),
2111        allow_aggregates: false,
2112        allow_subqueries: true,
2113        allow_parameters: true,
2114        allow_windows: false,
2115    };
2116
2117    let ncols = values[0].len();
2118    let nrows = values.len();
2119
2120    // Arrange input expressions by columns, not rows, so that we can
2121    // call `coerce_homogeneous_exprs` on each column.
2122    let mut cols = vec![vec![]; ncols];
2123    for row in values {
2124        if row.len() != ncols {
2125            sql_bail!(
2126                "VALUES expression has varying number of columns: {} vs {}",
2127                row.len(),
2128                ncols
2129            );
2130        }
2131        for (i, v) in row.iter().enumerate() {
2132            cols[i].push(v);
2133        }
2134    }
2135
2136    // Plan each column.
2137    let mut col_iters = Vec::with_capacity(ncols);
2138    let mut col_types = Vec::with_capacity(ncols);
2139    for col in &cols {
2140        let col = coerce_homogeneous_exprs(ecx, plan_exprs(ecx, col)?, None)?;
2141        let mut col_type = ecx.column_type(&col[0]);
2142        for val in &col[1..] {
2143            col_type = col_type.sql_union(&ecx.column_type(val))?; // HIR deliberately not using `union`
2144        }
2145        col_types.push(col_type);
2146        col_iters.push(col.into_iter());
2147    }
2148
2149    // Build constant relation.
2150    let mut exprs = vec![];
2151    for _ in 0..nrows {
2152        for i in 0..ncols {
2153            exprs.push(col_iters[i].next().unwrap());
2154        }
2155    }
2156    let out = HirRelationExpr::CallTable {
2157        func: TableFunc::Wrap {
2158            width: ncols,
2159            types: col_types,
2160        },
2161        exprs,
2162    };
2163
2164    // Build column names.
2165    let mut scope = Scope::empty();
2166    for i in 0..ncols {
2167        let name = format!("column{}", i + 1);
2168        scope.items.push(ScopeItem::from_column_name(name));
2169    }
2170
2171    Ok((out, scope))
2172}
2173
2174/// Plans a `VALUES` clause that appears at the top level of an `INSERT`
2175/// statement.
2176///
2177/// This is special-cased in PostgreSQL and different enough from `plan_values`
2178/// that it is easier to use a separate function entirely. Unlike a normal
2179/// `VALUES` clause, each value is coerced to the type of the target table
2180/// via an assignment cast.
2181///
2182/// See: <https://github.com/postgres/postgres/blob/ad77039fa/src/backend/parser/analyze.c#L504-L518>
2183fn plan_values_insert(
2184    qcx: &QueryContext,
2185    target_names: &[&ColumnName],
2186    target_types: &[&SqlScalarType],
2187    values: &[Vec<Expr<Aug>>],
2188) -> Result<HirRelationExpr, PlanError> {
2189    assert!(!values.is_empty());
2190
2191    if !values.iter().map(|row| row.len()).all_equal() {
2192        sql_bail!("VALUES lists must all be the same length");
2193    }
2194
2195    let ecx = &ExprContext {
2196        qcx,
2197        name: "VALUES",
2198        scope: &Scope::empty(),
2199        relation_type: &SqlRelationType::empty(),
2200        allow_aggregates: false,
2201        allow_subqueries: true,
2202        allow_parameters: true,
2203        allow_windows: false,
2204    };
2205
2206    let mut exprs = vec![];
2207    let mut types = vec![];
2208    for row in values {
2209        if row.len() > target_names.len() {
2210            sql_bail!("INSERT has more expressions than target columns");
2211        }
2212        for (column, val) in row.into_iter().enumerate() {
2213            let target_type = &target_types[column];
2214            let val = plan_expr(ecx, val)?;
2215            let val = typeconv::plan_coerce(ecx, val, target_type)?;
2216            let source_type = &ecx.scalar_type(&val);
2217            let val = match typeconv::plan_cast(ecx, CastContext::Assignment, val, target_type) {
2218                Ok(val) => val,
2219                Err(_) => sql_bail!(
2220                    "column {} is of type {} but expression is of type {}",
2221                    target_names[column].quoted(),
2222                    qcx.humanize_sql_scalar_type(target_type, false),
2223                    qcx.humanize_sql_scalar_type(source_type, false),
2224                ),
2225            };
2226            if column >= types.len() {
2227                types.push(ecx.column_type(&val));
2228            } else {
2229                types[column] = types[column].sql_union(&ecx.column_type(&val))?; // HIR deliberately not using `union`
2230            }
2231            exprs.push(val);
2232        }
2233    }
2234
2235    Ok(HirRelationExpr::CallTable {
2236        func: TableFunc::Wrap {
2237            width: values[0].len(),
2238            types,
2239        },
2240        exprs,
2241    })
2242}
2243
2244fn plan_join_identity() -> (HirRelationExpr, Scope) {
2245    let typ = SqlRelationType::new(vec![]);
2246    let expr = HirRelationExpr::constant(vec![vec![]], typ);
2247    let scope = Scope::empty();
2248    (expr, scope)
2249}
2250
2251/// Describes how to execute a SELECT query.
2252///
2253/// `order_by` describes how to order the rows in `expr` *before* applying the
2254/// projection. The `scope` describes the columns in `expr` *after* the
2255/// projection has been applied.
2256#[derive(Debug)]
2257struct SelectPlan {
2258    expr: HirRelationExpr,
2259    scope: Scope,
2260    order_by: Vec<ColumnOrder>,
2261    project: Vec<usize>,
2262}
2263
2264generate_extracted_config!(
2265    SelectOption,
2266    (ExpectedGroupSize, u64),
2267    (AggregateInputGroupSize, u64),
2268    (DistinctOnInputGroupSize, u64),
2269    (LimitInputGroupSize, u64)
2270);
2271
2272/// Plans a SELECT query. The SELECT query may contain an intrusive ORDER BY clause.
2273///
2274/// Normally, the ORDER BY clause occurs after the columns specified in the
2275/// SELECT list have been projected. In a query like
2276///
2277///   CREATE TABLE (a int, b int)
2278///   (SELECT a FROM t) UNION (SELECT a FROM t) ORDER BY a
2279///
2280/// it is valid to refer to `a`, because it is explicitly selected, but it would
2281/// not be valid to refer to unselected column `b`.
2282///
2283/// But PostgreSQL extends the standard to permit queries like
2284///
2285///   SELECT a FROM t ORDER BY b
2286///
2287/// where expressions in the ORDER BY clause can refer to *both* input columns
2288/// and output columns.
2289fn plan_select_from_where(
2290    qcx: &QueryContext,
2291    mut s: Select<Aug>,
2292    mut order_by_exprs: Vec<OrderByExpr<Aug>>,
2293) -> Result<SelectPlan, PlanError> {
2294    // TODO: Both `s` and `order_by_exprs` are not references because the
2295    // AggregateTableFuncVisitor needs to be able to rewrite the expressions for
2296    // table function support (the UUID mapping). Attempt to change this so callers
2297    // don't need to clone the Select.
2298
2299    // Extract query options.
2300    let select_option_extracted = SelectOptionExtracted::try_from(s.options.clone())?;
2301    let group_size_hints = GroupSizeHints::try_from(select_option_extracted)?;
2302
2303    // Step 1. Handle FROM clause, including joins.
2304    let (mut relation_expr, mut from_scope) =
2305        s.from.iter().try_fold(plan_join_identity(), |l, twj| {
2306            let (left, left_scope) = l;
2307            plan_join(
2308                qcx,
2309                left,
2310                left_scope,
2311                &Join {
2312                    relation: TableFactor::NestedJoin {
2313                        join: Box::new(twj.clone()),
2314                        alias: None,
2315                    },
2316                    join_operator: JoinOperator::CrossJoin,
2317                },
2318            )
2319        })?;
2320
2321    // Step 2. Handle WHERE clause.
2322    if let Some(selection) = &s.selection {
2323        let ecx = &ExprContext {
2324            qcx,
2325            name: "WHERE clause",
2326            scope: &from_scope,
2327            relation_type: &qcx.relation_type(&relation_expr),
2328            allow_aggregates: false,
2329            allow_subqueries: true,
2330            allow_parameters: true,
2331            allow_windows: false,
2332        };
2333        let expr = plan_expr(ecx, selection)
2334            .map_err(|e| sql_err!("WHERE clause error: {}", e))?
2335            .type_as(ecx, &SqlScalarType::Bool)?;
2336        relation_expr = relation_expr.filter(vec![expr]);
2337    }
2338
2339    // Step 3. Gather aggregates and table functions.
2340    // (But skip window aggregates.)
2341    let (aggregates, table_funcs) = {
2342        let mut visitor = AggregateTableFuncVisitor::new(qcx.scx);
2343        visitor.visit_select_mut(&mut s);
2344        for o in order_by_exprs.iter_mut() {
2345            visitor.visit_order_by_expr_mut(o);
2346        }
2347        visitor.into_result()?
2348    };
2349    let mut table_func_names: BTreeMap<String, Ident> = BTreeMap::new();
2350    // Table functions in the SELECT list apply to the output of the reduce
2351    // (GROUP BY, aggregates, HAVING), but their columns must already be in
2352    // scope when the SELECT list is expanded and GROUP BY items are planned,
2353    // so the join is planned here regardless. Step 5 decides whether the
2354    // reduce consumes this join or the saved pre-join relation, and in the
2355    // latter case Step 8.5 plans the join again on top of the reduce.
2356    let pre_table_funcs_arity = from_scope.len();
2357    let mut pre_table_funcs_relation = None;
2358    let mut table_funcs_deferred = false;
2359    if !table_funcs.is_empty() {
2360        let (expr, scope) = plan_scalar_table_funcs(
2361            qcx,
2362            &table_funcs,
2363            &mut table_func_names,
2364            &relation_expr,
2365            &from_scope,
2366        )?;
2367        if !aggregates.is_empty() || !s.group_by.is_empty() || s.having.is_some() {
2368            pre_table_funcs_relation = Some(relation_expr.clone());
2369        }
2370        relation_expr = relation_expr.join(expr, HirScalarExpr::literal_true(), JoinKind::Inner);
2371        from_scope = from_scope.product(scope)?;
2372    }
2373
2374    // Step 4. Expand SELECT clause.
2375    let projection = {
2376        let ecx = &ExprContext {
2377            qcx,
2378            name: "SELECT clause",
2379            scope: &from_scope,
2380            relation_type: &qcx.relation_type(&relation_expr),
2381            allow_aggregates: true,
2382            allow_subqueries: true,
2383            allow_parameters: true,
2384            allow_windows: true,
2385        };
2386        let mut out = vec![];
2387        for si in &s.projection {
2388            if *si == SelectItem::Wildcard && s.from.is_empty() {
2389                sql_bail!("SELECT * with no tables specified is not valid");
2390            }
2391            out.extend(expand_select_item(ecx, si, &table_func_names)?);
2392        }
2393        out
2394    };
2395
2396    // Step 5. Handle GROUP BY clause.
2397    // This will also plan the aggregates gathered in Step 3.
2398    // See an overview of how aggregates are planned in the doc comment at the top of the file.
2399    let (mut group_scope, select_all_mapping) = {
2400        // Compute GROUP BY expressions.
2401        let ecx = &ExprContext {
2402            qcx,
2403            name: "GROUP BY clause",
2404            scope: &from_scope,
2405            relation_type: &qcx.relation_type(&relation_expr),
2406            allow_aggregates: false,
2407            allow_subqueries: true,
2408            allow_parameters: true,
2409            allow_windows: false,
2410        };
2411        let mut group_key = vec![];
2412        let mut group_exprs: BTreeMap<HirScalarExpr, ScopeItem> = BTreeMap::new();
2413        let mut group_hir_exprs = vec![];
2414        let mut group_scope = Scope::empty();
2415        let mut select_all_mapping = BTreeMap::new();
2416
2417        for group_expr in &s.group_by {
2418            let (group_expr, expr) = plan_group_by_expr(ecx, group_expr, &projection)?;
2419            let new_column = group_key.len();
2420
2421            // Multiple AST expressions can map to the same HIR expression, e.g.
2422            // `GROUP BY 1, 1` or `GROUP BY a, 1` where the positional reference
2423            // `1` resolves to the same column as `a`. When we already have a
2424            // ScopeItem for this HIR expression we must deduplicate: skip adding
2425            // a second group key for it. We must not gate this on `group_expr`
2426            // being `Some`, because a positional reference to an input column
2427            // (e.g. `GROUP BY 1`) has no AST expression to record yet still
2428            // needs to dedup against the existing key; gating on `Some` here is
2429            // what made `GROUP BY 1, 1` panic on the `group_hir_exprs.len() ==
2430            // group_exprs.len()` assertion below.
2431            if let Some(existing_scope_item) = group_exprs.get_mut(&expr) {
2432                // If this AST expression is a named expression (not a bare
2433                // positional reference), record it on the existing ScopeItem so
2434                // name resolution can find it.
2435                if let Some(group_expr) = group_expr {
2436                    existing_scope_item.exprs.insert(group_expr.clone());
2437                }
2438                continue;
2439            }
2440
2441            let mut scope_item = if let HirScalarExpr::Column(
2442                ColumnRef {
2443                    level: 0,
2444                    column: old_column,
2445                },
2446                _name,
2447            ) = &expr
2448            {
2449                // If we later have `SELECT foo.*` then we have to find all
2450                // the `foo` items in `from_scope` and figure out where they
2451                // ended up in `group_scope`. This is really hard to do
2452                // right using SQL name resolution, so instead we just track
2453                // the movement here.
2454                select_all_mapping.insert(*old_column, new_column);
2455                let scope_item = ecx.scope.items[*old_column].clone();
2456                scope_item
2457            } else {
2458                ScopeItem::empty()
2459            };
2460
2461            if let Some(group_expr) = group_expr.cloned() {
2462                scope_item.exprs.insert(group_expr);
2463            }
2464
2465            group_key.push(from_scope.len() + group_exprs.len());
2466            group_hir_exprs.push(expr.clone());
2467            group_exprs.insert(expr, scope_item);
2468        }
2469
2470        assert_eq!(group_hir_exprs.len(), group_exprs.len());
2471        for expr in &group_hir_exprs {
2472            if let Some(scope_item) = group_exprs.remove(expr) {
2473                group_scope.items.push(scope_item);
2474            }
2475        }
2476
2477        // Plan aggregates.
2478        let ecx = &ExprContext {
2479            qcx,
2480            name: "aggregate function",
2481            scope: &from_scope,
2482            relation_type: &qcx.relation_type(&relation_expr.clone().map(group_hir_exprs.clone())),
2483            allow_aggregates: false,
2484            allow_subqueries: true,
2485            allow_parameters: true,
2486            allow_windows: false,
2487        };
2488        let mut agg_exprs = vec![];
2489        for sql_function in aggregates {
2490            if sql_function.over.is_some() {
2491                unreachable!(
2492                    "Window aggregate; AggregateTableFuncVisitor explicitly filters these out"
2493                );
2494            }
2495            agg_exprs.push(plan_aggregate_common(ecx, &sql_function)?);
2496            group_scope
2497                .items
2498                .push(ScopeItem::from_expr(Expr::Function(sql_function.clone())));
2499        }
2500        if !agg_exprs.is_empty() || !group_key.is_empty() || s.having.is_some() {
2501            // Table functions join after the reduce only when no group key or
2502            // aggregate references their columns, e.g. GROUP BY on a SELECT
2503            // list alias of a table function.
2504            if let Some(pre_relation_expr) = pre_table_funcs_relation.take() {
2505                let mut references_table_funcs = false;
2506                let mut check = |column: usize| {
2507                    if column >= pre_table_funcs_arity {
2508                        references_table_funcs = true;
2509                    }
2510                };
2511                for expr in &group_hir_exprs {
2512                    expr.visit_columns_referring_to_root_level(&mut check);
2513                }
2514                for agg_expr in &agg_exprs {
2515                    agg_expr
2516                        .expr
2517                        .visit_columns_referring_to_root_level(&mut check);
2518                }
2519                if !references_table_funcs {
2520                    relation_expr = pre_relation_expr;
2521                    // The group keys point past the table functions' columns,
2522                    // which the saved relation does not have.
2523                    for (i, key) in group_key.iter_mut().enumerate() {
2524                        *key = pre_table_funcs_arity + i;
2525                    }
2526                    table_funcs_deferred = true;
2527                }
2528            }
2529
2530            // apply GROUP BY / aggregates
2531            relation_expr = relation_expr.map(group_hir_exprs).reduce(
2532                group_key,
2533                agg_exprs,
2534                group_size_hints.aggregate_input_group_size,
2535            );
2536
2537            // For every old column that wasn't a group key, add a scope item
2538            // that errors when referenced. We can't simply drop these items
2539            // from scope. These items need to *exist* because they might shadow
2540            // variables in outer scopes that would otherwise be valid to
2541            // reference, but accessing them needs to produce an error.
2542            // Deferred table functions' columns come back into scope in Step
2543            // 8.5, so they must not be recorded as ungrouped.
2544            let ungrouped_arity = if table_funcs_deferred {
2545                pre_table_funcs_arity
2546            } else {
2547                from_scope.len()
2548            };
2549            for i in 0..ungrouped_arity {
2550                if !select_all_mapping.contains_key(&i) {
2551                    let scope_item = &ecx.scope.items[i];
2552                    group_scope.ungrouped_columns.push(ScopeUngroupedColumn {
2553                        table_name: scope_item.table_name.clone(),
2554                        column_name: scope_item.column_name.clone(),
2555                        allow_unqualified_references: scope_item.allow_unqualified_references,
2556                    });
2557                }
2558            }
2559
2560            (group_scope, select_all_mapping)
2561        } else {
2562            // if no GROUP BY, aggregates or having then all columns remain in scope
2563            (
2564                from_scope.clone(),
2565                (0..from_scope.len()).map(|i| (i, i)).collect(),
2566            )
2567        }
2568    };
2569
2570    // Step 6. Handle HAVING clause.
2571    if let Some(ref having) = s.having {
2572        let ecx = &ExprContext {
2573            qcx,
2574            name: "HAVING clause",
2575            scope: &group_scope,
2576            relation_type: &qcx.relation_type(&relation_expr),
2577            allow_aggregates: true,
2578            allow_subqueries: true,
2579            allow_parameters: true,
2580            allow_windows: false,
2581        };
2582        let expr = plan_expr(ecx, having)?.type_as(ecx, &SqlScalarType::Bool)?;
2583        relation_expr = relation_expr.filter(vec![expr]);
2584    }
2585
2586    // Step 7. Gather window functions from SELECT, ORDER BY, and QUALIFY, and plan them.
2587    // (This includes window aggregations.)
2588    //
2589    // Note that window functions can be present only in SELECT, ORDER BY, or QUALIFY (including
2590    // DISTINCT ON), because they are executed after grouped aggregations and HAVING.
2591    //
2592    // Also note that window functions in the ORDER BY can't refer to columns introduced in the
2593    // SELECT. This is because when an output column appears in ORDER BY, it can only stand alone,
2594    // and can't be part of a bigger expression.
2595    // See https://www.postgresql.org/docs/current/queries-order.html:
2596    // "Note that an output column name has to stand alone, that is, it cannot be used in an
2597    // expression"
2598    let window_funcs = {
2599        let mut visitor = WindowFuncCollector::default();
2600        // The `visit_select` call visits both `SELECT` and `QUALIFY` (and many other things, but
2601        // window functions are excluded from other things by `allow_windows` being false when
2602        // planning those before this code).
2603        visitor.visit_select(&s);
2604        for o in order_by_exprs.iter() {
2605            visitor.visit_order_by_expr(o);
2606        }
2607        visitor.into_result()
2608    };
2609    for window_func in window_funcs {
2610        let ecx = &ExprContext {
2611            qcx,
2612            name: "window function",
2613            scope: &group_scope,
2614            relation_type: &qcx.relation_type(&relation_expr),
2615            allow_aggregates: true,
2616            allow_subqueries: true,
2617            allow_parameters: true,
2618            allow_windows: true,
2619        };
2620        relation_expr = relation_expr.map(vec![plan_expr(ecx, &window_func)?.type_as_any(ecx)?]);
2621        group_scope.items.push(ScopeItem::from_expr(window_func));
2622    }
2623    // From this point on, we shouldn't encounter _valid_ window function calls, because those have
2624    // been already planned now. However, we should still set `allow_windows: true` for the
2625    // remaining planning of `QUALIFY`, `SELECT`, and `ORDER BY`, in order to have a correct error
2626    // msg if an OVER clause is missing from a window function.
2627
2628    // Step 8. Handle QUALIFY clause. (very similar to HAVING)
2629    if let Some(ref qualify) = s.qualify {
2630        let ecx = &ExprContext {
2631            qcx,
2632            name: "QUALIFY clause",
2633            scope: &group_scope,
2634            relation_type: &qcx.relation_type(&relation_expr),
2635            allow_aggregates: true,
2636            allow_subqueries: true,
2637            allow_parameters: true,
2638            allow_windows: true,
2639        };
2640        let expr = plan_expr(ecx, qualify)?.type_as(ecx, &SqlScalarType::Bool)?;
2641        relation_expr = relation_expr.filter(vec![expr]);
2642    }
2643
2644    // Step 8.5. Join the table functions deferred in Step 5. Planning them
2645    // again rebinds their arguments' column references to the reduced
2646    // relation.
2647    if table_funcs_deferred {
2648        let (expr, scope) = plan_scalar_table_funcs(
2649            qcx,
2650            &table_funcs,
2651            &mut table_func_names,
2652            &relation_expr,
2653            &group_scope,
2654        )?;
2655        relation_expr = relation_expr.join(expr, HirScalarExpr::literal_true(), JoinKind::Inner);
2656        // `product` resets `ungrouped_columns`, but the ungrouped column
2657        // errors from the reduce must survive for the SELECT list.
2658        let ungrouped_columns = mem::take(&mut group_scope.ungrouped_columns);
2659        group_scope = group_scope.product(scope)?;
2660        group_scope.ungrouped_columns = ungrouped_columns;
2661    }
2662
2663    // Step 9. Handle SELECT clause.
2664    let output_columns = {
2665        let mut new_exprs = vec![];
2666        let mut new_type = qcx.relation_type(&relation_expr);
2667        let mut output_columns = vec![];
2668        for (select_item, column_name) in &projection {
2669            let ecx = &ExprContext {
2670                qcx,
2671                name: "SELECT clause",
2672                scope: &group_scope,
2673                relation_type: &new_type,
2674                allow_aggregates: true,
2675                allow_subqueries: true,
2676                allow_parameters: true,
2677                allow_windows: true,
2678            };
2679            let expr = match select_item {
2680                ExpandedSelectItem::InputOrdinal(i) => {
2681                    if let Some(column) = select_all_mapping.get(i).copied() {
2682                        HirScalarExpr::column(column)
2683                    } else {
2684                        return Err(PlanError::ungrouped_column(&from_scope.items[*i]));
2685                    }
2686                }
2687                ExpandedSelectItem::Expr(expr) => plan_expr(ecx, expr)?.type_as_any(ecx)?,
2688            };
2689            if let HirScalarExpr::Column(ColumnRef { level: 0, column }, _name) = expr {
2690                // Simple column reference; no need to map on a new expression.
2691                output_columns.push((column, column_name));
2692            } else {
2693                // Complicated expression that requires a map expression. We
2694                // update `group_scope` as we go so that future expressions that
2695                // are textually identical to this one can reuse it. This
2696                // duplicate detection is required for proper determination of
2697                // ambiguous column references with SQL92-style `ORDER BY`
2698                // items. See `plan_order_by_or_distinct_expr` for more.
2699                let typ = ecx.column_type(&expr);
2700                new_type.column_types.push(typ);
2701                new_exprs.push(expr);
2702                output_columns.push((group_scope.len(), column_name));
2703                group_scope
2704                    .items
2705                    .push(ScopeItem::from_expr(select_item.as_expr().cloned()));
2706            }
2707        }
2708        relation_expr = relation_expr.map(new_exprs);
2709        output_columns
2710    };
2711    let mut project_key: Vec<_> = output_columns.iter().map(|(i, _name)| *i).collect();
2712
2713    // Step 10. Handle intrusive ORDER BY and DISTINCT.
2714    let order_by = {
2715        let relation_type = qcx.relation_type(&relation_expr);
2716        let (mut order_by, mut map_exprs) = plan_order_by_exprs(
2717            &ExprContext {
2718                qcx,
2719                name: "ORDER BY clause",
2720                scope: &group_scope,
2721                relation_type: &relation_type,
2722                allow_aggregates: true,
2723                allow_subqueries: true,
2724                allow_parameters: true,
2725                allow_windows: true,
2726            },
2727            &order_by_exprs,
2728            &output_columns,
2729        )?;
2730
2731        match s.distinct {
2732            None => relation_expr = relation_expr.map(map_exprs),
2733            Some(Distinct::EntireRow) => {
2734                if relation_type.arity() == 0 {
2735                    sql_bail!("SELECT DISTINCT must have at least one column");
2736                }
2737                // `SELECT DISTINCT` only distincts on the columns in the SELECT
2738                // list, so we can't proceed if `ORDER BY` has introduced any
2739                // columns for arbitrary expressions. This matches PostgreSQL.
2740                if !try_push_projection_order_by(
2741                    &mut relation_expr,
2742                    &mut project_key,
2743                    &mut order_by,
2744                ) {
2745                    sql_bail!(
2746                        "for SELECT DISTINCT, ORDER BY expressions must appear in select list"
2747                    );
2748                }
2749                assert!(map_exprs.is_empty());
2750                relation_expr = relation_expr.distinct();
2751            }
2752            Some(Distinct::On(exprs)) => {
2753                // The table functions deferred in Step 5 join below this TopK,
2754                // so the distinct would collapse their expansion rather than
2755                // expand the rows the distinct picks. PostgreSQL instead
2756                // evaluates a SELECT list table function after the distinct
2757                // whenever the query has an ORDER BY and the function's output
2758                // is not itself a distinct or sort key. Reject these queries
2759                // rather than answer them differently.
2760                if table_funcs_deferred && !order_by_exprs.is_empty() {
2761                    bail_unsupported!(
2762                        "SELECT list table function with DISTINCT ON and ORDER BY over an aggregation"
2763                    );
2764                }
2765
2766                let ecx = &ExprContext {
2767                    qcx,
2768                    name: "DISTINCT ON clause",
2769                    scope: &group_scope,
2770                    relation_type: &qcx.relation_type(&relation_expr),
2771                    allow_aggregates: true,
2772                    allow_subqueries: true,
2773                    allow_parameters: true,
2774                    allow_windows: true,
2775                };
2776
2777                let mut distinct_exprs = vec![];
2778                for expr in &exprs {
2779                    let expr = plan_order_by_or_distinct_expr(ecx, expr, &output_columns)?;
2780                    distinct_exprs.push(expr);
2781                }
2782
2783                let mut distinct_key = vec![];
2784
2785                // If both `DISTINCT ON` and `ORDER BY` are specified, then the
2786                // `DISTINCT ON` expressions must match the initial `ORDER BY`
2787                // expressions, though the order of `DISTINCT ON` expressions
2788                // does not matter. This matches PostgreSQL and leaves the door
2789                // open to a future optimization where the `DISTINCT ON` and
2790                // `ORDER BY` operations happen in one pass.
2791                //
2792                // On the bright side, any columns that have already been
2793                // computed by `ORDER BY` can be reused in the distinct key.
2794                let arity = relation_type.arity();
2795                for ord in order_by.iter().take(distinct_exprs.len()) {
2796                    // The unusual construction of `expr` here is to ensure the
2797                    // temporary column expression lives long enough.
2798                    let mut expr = &HirScalarExpr::column(ord.column);
2799                    if ord.column >= arity {
2800                        expr = &map_exprs[ord.column - arity];
2801                    };
2802                    match distinct_exprs.iter().position(move |e| e == expr) {
2803                        None => sql_bail!(
2804                            "SELECT DISTINCT ON expressions must match initial ORDER BY expressions"
2805                        ),
2806                        Some(pos) => {
2807                            distinct_exprs.remove(pos);
2808                        }
2809                    }
2810                    distinct_key.push(ord.column);
2811                }
2812
2813                // Add any remaining `DISTINCT ON` expressions to the key.
2814                for expr in distinct_exprs {
2815                    // If the expression is a reference to an existing column,
2816                    // do not introduce a new column to support it.
2817                    let column = match expr {
2818                        HirScalarExpr::Column(ColumnRef { level: 0, column }, _name) => column,
2819                        _ => {
2820                            map_exprs.push(expr);
2821                            arity + map_exprs.len() - 1
2822                        }
2823                    };
2824                    distinct_key.push(column);
2825                }
2826
2827                // `DISTINCT ON` is semantically a TopK with limit 1. The
2828                // columns in `ORDER BY` that are not part of the distinct key,
2829                // if there are any, determine the ordering within each group,
2830                // per PostgreSQL semantics.
2831                let distinct_len = distinct_key.len();
2832                relation_expr = HirRelationExpr::top_k(
2833                    relation_expr.map(map_exprs),
2834                    distinct_key,
2835                    order_by.iter().skip(distinct_len).cloned().collect(),
2836                    Some(HirScalarExpr::literal(
2837                        Datum::Int64(1),
2838                        SqlScalarType::Int64,
2839                    )),
2840                    HirScalarExpr::literal(Datum::Int64(0), SqlScalarType::Int64),
2841                    group_size_hints.distinct_on_input_group_size,
2842                );
2843            }
2844        }
2845
2846        order_by
2847    };
2848
2849    // Construct a clean scope to expose outwards, where all of the state that
2850    // accumulated in the scope during planning of this SELECT is erased. The
2851    // clean scope has at most one name for each column, and the names are not
2852    // associated with any table.
2853    let scope = Scope::from_source(None, projection.into_iter().map(|(_expr, name)| name));
2854
2855    Ok(SelectPlan {
2856        expr: relation_expr,
2857        scope,
2858        order_by,
2859        project: project_key,
2860    })
2861}
2862
2863fn plan_scalar_table_funcs(
2864    qcx: &QueryContext,
2865    table_funcs: &BTreeMap<Function<Aug>, String>,
2866    table_func_names: &mut BTreeMap<String, Ident>,
2867    relation_expr: &HirRelationExpr,
2868    from_scope: &Scope,
2869) -> Result<(HirRelationExpr, Scope), PlanError> {
2870    let rows_from_qcx = qcx.derived_context(from_scope.clone(), qcx.relation_type(relation_expr));
2871
2872    for (table_func, id) in table_funcs.iter() {
2873        table_func_names.insert(
2874            id.clone(),
2875            // TODO(parkmycar): Re-visit after having `FullItemName` use `Ident`s.
2876            Ident::new_unchecked(table_func.name.full_item_name().item.clone()),
2877        );
2878    }
2879    // If there's only a single table function, we can skip generating
2880    // ordinality columns.
2881    if table_funcs.len() == 1 {
2882        let (table_func, id) = table_funcs.iter().next().unwrap();
2883        let (expr, mut scope) =
2884            plan_solitary_table_function(&rows_from_qcx, table_func, None, false)?;
2885
2886        // A single table-function might return several columns as a record
2887        let num_cols = scope.len();
2888        for i in 0..scope.len() {
2889            scope.items[i].table_name = Some(PartialItemName {
2890                database: None,
2891                schema: None,
2892                item: id.clone(),
2893            });
2894            scope.items[i].from_single_column_function = num_cols == 1;
2895            scope.items[i].allow_unqualified_references = false;
2896        }
2897        return Ok((expr, scope));
2898    }
2899    if table_funcs.keys().any(is_repeat_row) {
2900        // Note: Would be also caught by WITH ORDINALITY checking for `repeat_row`, but then the
2901        // error message would be misleading, because it would refer to WITH ORDINALITY.
2902        bail_unsupported!(format!(
2903            "{} in a SELECT clause with multiple table functions",
2904            REPEAT_ROW_NAME
2905        ));
2906    }
2907    // Otherwise, plan as usual, emulating the ROWS FROM behavior
2908    let (expr, mut scope, num_cols) =
2909        plan_rows_from_internal(&rows_from_qcx, table_funcs.keys(), None)?;
2910
2911    // Munge the scope so table names match with the generated ids.
2912    let mut i = 0;
2913    for (id, num_cols) in table_funcs.values().zip_eq(num_cols) {
2914        for _ in 0..num_cols {
2915            scope.items[i].table_name = Some(PartialItemName {
2916                database: None,
2917                schema: None,
2918                item: id.clone(),
2919            });
2920            scope.items[i].from_single_column_function = num_cols == 1;
2921            scope.items[i].allow_unqualified_references = false;
2922            i += 1;
2923        }
2924        // Ordinality column. This doubles as the
2925        // `is_exists_column_for_a_table_function_that_was_in_the_target_list` later on
2926        // because it only needs to be NULL or not.
2927        scope.items[i].table_name = Some(PartialItemName {
2928            database: None,
2929            schema: None,
2930            item: id.clone(),
2931        });
2932        scope.items[i].is_exists_column_for_a_table_function_that_was_in_the_target_list = true;
2933        scope.items[i].allow_unqualified_references = false;
2934        i += 1;
2935    }
2936    // Coalesced ordinality column.
2937    scope.items[i].allow_unqualified_references = false;
2938    Ok((expr, scope))
2939}
2940
2941/// Plans an expression in a `GROUP BY` clause.
2942///
2943/// For historical reasons, PostgreSQL allows `GROUP BY` expressions to refer to
2944/// names/expressions defined in the `SELECT` clause. These special cases are
2945/// handled by this function; see comments within the implementation for
2946/// details.
2947fn plan_group_by_expr<'a>(
2948    ecx: &ExprContext,
2949    group_expr: &'a Expr<Aug>,
2950    projection: &'a [(ExpandedSelectItem, ColumnName)],
2951) -> Result<(Option<&'a Expr<Aug>>, HirScalarExpr), PlanError> {
2952    let plan_projection = |column: usize| match &projection[column].0 {
2953        ExpandedSelectItem::InputOrdinal(column) => Ok((None, HirScalarExpr::column(*column))),
2954        ExpandedSelectItem::Expr(expr) => {
2955            Ok((Some(expr.as_ref()), plan_expr(ecx, expr)?.type_as_any(ecx)?))
2956        }
2957    };
2958
2959    // Check if the expression is a numeric literal, as in `GROUP BY 1`. This is
2960    // a special case that means to use the ith item in the SELECT clause.
2961    if let Some(column) = check_col_index(ecx.name, group_expr, projection.len())? {
2962        return plan_projection(column);
2963    }
2964
2965    // Check if the expression is a simple identifier, as in `GROUP BY foo`.
2966    // The `foo` can refer to *either* an input column or an output column. If
2967    // both exist, the input column is preferred.
2968    match group_expr {
2969        Expr::Identifier(names) => match plan_identifier(ecx, names) {
2970            Err(PlanError::UnknownColumn {
2971                table: None,
2972                column,
2973                similar,
2974            }) => {
2975                // The expression was a simple identifier that did not match an
2976                // input column. See if it matches an output column.
2977                let mut iter = projection.iter().map(|(_expr, name)| name);
2978                if let Some(i) = iter.position(|n| *n == column) {
2979                    if iter.any(|n| *n == column) {
2980                        Err(PlanError::AmbiguousColumn(column))
2981                    } else {
2982                        plan_projection(i)
2983                    }
2984                } else {
2985                    // The name didn't match an output column either. Return the
2986                    // "unknown column" error.
2987                    Err(PlanError::UnknownColumn {
2988                        table: None,
2989                        column,
2990                        similar,
2991                    })
2992                }
2993            }
2994            res => Ok((Some(group_expr), res?)),
2995        },
2996        _ => Ok((
2997            Some(group_expr),
2998            plan_expr(ecx, group_expr)?.type_as_any(ecx)?,
2999        )),
3000    }
3001}
3002
3003/// Plans a slice of `ORDER BY` expressions.
3004///
3005/// See `plan_order_by_or_distinct_expr` for details on the `output_columns`
3006/// parameter.
3007///
3008/// Returns the determined column orderings and a list of scalar expressions
3009/// that must be mapped onto the underlying relation expression.
3010pub(crate) fn plan_order_by_exprs(
3011    ecx: &ExprContext,
3012    order_by_exprs: &[OrderByExpr<Aug>],
3013    output_columns: &[(usize, &ColumnName)],
3014) -> Result<(Vec<ColumnOrder>, Vec<HirScalarExpr>), PlanError> {
3015    let mut order_by = vec![];
3016    let mut map_exprs = vec![];
3017    for obe in order_by_exprs {
3018        let expr = plan_order_by_or_distinct_expr(ecx, &obe.expr, output_columns)?;
3019        // If the expression is a reference to an existing column,
3020        // do not introduce a new column to support it.
3021        let column = match expr {
3022            HirScalarExpr::Column(ColumnRef { level: 0, column }, _name) => column,
3023            _ => {
3024                map_exprs.push(expr);
3025                ecx.relation_type.arity() + map_exprs.len() - 1
3026            }
3027        };
3028        order_by.push(resolve_desc_and_nulls_last(obe, column));
3029    }
3030    Ok((order_by, map_exprs))
3031}
3032
3033/// Plans an expression that appears in an `ORDER BY` or `DISTINCT ON` clause.
3034///
3035/// The `output_columns` parameter describes, in order, the physical index and
3036/// name of each expression in the `SELECT` list. For example, `[(3, "a")]`
3037/// corresponds to a `SELECT` list with a single entry named "a" that can be
3038/// found at index 3 in the underlying relation expression.
3039///
3040/// There are three cases to handle.
3041///
3042///    1. A simple numeric literal, as in `ORDER BY 1`. This is an ordinal
3043///       reference to the specified output column.
3044///    2. An unqualified identifier, as in `ORDER BY a`. This is a reference to
3045///       an output column, if it exists; otherwise it is a reference to an
3046///       input column.
3047///    3. An arbitrary expression, as in `ORDER BY -a`. Column references in
3048///       arbitrary expressions exclusively refer to input columns, never output
3049///       columns.
3050fn plan_order_by_or_distinct_expr(
3051    ecx: &ExprContext,
3052    expr: &Expr<Aug>,
3053    output_columns: &[(usize, &ColumnName)],
3054) -> Result<HirScalarExpr, PlanError> {
3055    if let Some(i) = check_col_index(ecx.name, expr, output_columns.len())? {
3056        return Ok(HirScalarExpr::column(output_columns[i].0));
3057    }
3058
3059    if let Expr::Identifier(names) = expr {
3060        if let [name] = &names[..] {
3061            let name = normalize::column_name(name.clone());
3062            let mut iter = output_columns.iter().filter(|(_, n)| **n == name);
3063            if let Some((i, _)) = iter.next() {
3064                match iter.next() {
3065                    // Per SQL92, names are not considered ambiguous if they
3066                    // refer to identical target list expressions, as in
3067                    // `SELECT a + 1 AS foo, a + 1 AS foo ... ORDER BY foo`.
3068                    Some((i2, _)) if i != i2 => return Err(PlanError::AmbiguousColumn(name)),
3069                    _ => return Ok(HirScalarExpr::column(*i)),
3070                }
3071            }
3072        }
3073    }
3074
3075    plan_expr(ecx, expr)?.type_as_any(ecx)
3076}
3077
3078fn plan_table_with_joins(
3079    qcx: &QueryContext,
3080    table_with_joins: &TableWithJoins<Aug>,
3081) -> Result<(HirRelationExpr, Scope), PlanError> {
3082    let (mut expr, mut scope) = plan_table_factor(qcx, &table_with_joins.relation)?;
3083    for join in &table_with_joins.joins {
3084        let (new_expr, new_scope) = plan_join(qcx, expr, scope, join)?;
3085        expr = new_expr;
3086        scope = new_scope;
3087    }
3088    Ok((expr, scope))
3089}
3090
3091fn plan_table_factor(
3092    qcx: &QueryContext,
3093    table_factor: &TableFactor<Aug>,
3094) -> Result<(HirRelationExpr, Scope), PlanError> {
3095    match table_factor {
3096        TableFactor::Table { name, alias } => {
3097            let (expr, scope) = qcx.resolve_table_name(name.clone())?;
3098            let scope = plan_table_alias(scope, alias.as_ref())?;
3099            Ok((expr, scope))
3100        }
3101
3102        TableFactor::Function {
3103            function,
3104            alias,
3105            with_ordinality,
3106        } => plan_solitary_table_function(qcx, function, alias.as_ref(), *with_ordinality),
3107
3108        TableFactor::RowsFrom {
3109            functions,
3110            alias,
3111            with_ordinality,
3112        } => plan_rows_from(qcx, functions, alias.as_ref(), *with_ordinality),
3113
3114        TableFactor::Derived {
3115            lateral,
3116            subquery,
3117            alias,
3118        } => {
3119            let mut qcx = (*qcx).clone();
3120            if !lateral {
3121                // Since this derived table was not marked as `LATERAL`,
3122                // make elements in outer scopes invisible until we reach the
3123                // next lateral barrier.
3124                for scope in &mut qcx.outer_scopes {
3125                    if scope.lateral_barrier {
3126                        break;
3127                    }
3128                    scope.items.clear();
3129                }
3130            }
3131            qcx.outer_scopes[0].lateral_barrier = true;
3132            let (expr, scope) = plan_nested_query(&mut qcx, subquery)?;
3133            let scope = plan_table_alias(scope, alias.as_ref())?;
3134            Ok((expr, scope))
3135        }
3136
3137        TableFactor::NestedJoin { join, alias } => {
3138            let (expr, scope) = plan_table_with_joins(qcx, join)?;
3139            let scope = plan_table_alias(scope, alias.as_ref())?;
3140            Ok((expr, scope))
3141        }
3142    }
3143}
3144
3145/// Plans a `ROWS FROM` expression.
3146///
3147/// `ROWS FROM` concatenates table functions into a single table, filling in
3148/// `NULL`s in places where one table function has fewer rows than another. We
3149/// can achieve this by augmenting each table function with a row number, doing
3150/// a `FULL JOIN` between each table function on the row number and eventually
3151/// projecting away the row number columns. Concretely, the following query
3152/// using `ROWS FROM`
3153///
3154/// ```sql
3155/// SELECT
3156///     *
3157/// FROM
3158///     ROWS FROM (
3159///         generate_series(1, 2),
3160///         information_schema._pg_expandarray(ARRAY[9]),
3161///         generate_series(3, 6)
3162///     );
3163/// ```
3164///
3165/// is equivalent to the following query that does not use `ROWS FROM`:
3166///
3167/// ```sql
3168/// SELECT
3169///     gs1.generate_series, expand.x, expand.n, gs2.generate_series
3170/// FROM
3171///     generate_series(1, 2) WITH ORDINALITY AS gs1
3172///     FULL JOIN information_schema._pg_expandarray(ARRAY[9]) WITH ORDINALITY AS expand
3173///         ON gs1.ordinality = expand.ordinality
3174///     FULL JOIN generate_series(3, 6) WITH ORDINALITY AS gs3
3175///         ON coalesce(gs1.ordinality, expand.ordinality) = gs3.ordinality;
3176/// ```
3177///
3178/// Note the call to `coalesce` in the last join condition, which ensures that
3179/// `gs3` will align with whichever of `gs1` or `expand` has more rows.
3180///
3181/// This function creates a HirRelationExpr that follows the structure of the
3182/// latter query.
3183///
3184/// `with_ordinality` can be used to have the output expression contain a
3185/// single coalesced ordinality column at the end of the entire expression.
3186fn plan_rows_from(
3187    qcx: &QueryContext,
3188    functions: &[Function<Aug>],
3189    alias: Option<&TableAlias>,
3190    with_ordinality: bool,
3191) -> Result<(HirRelationExpr, Scope), PlanError> {
3192    // The `repeat_row` function is not supported in ROWS FROM.
3193    if functions.iter().any(is_repeat_row) {
3194        // Note: Would be also caught by WITH ORDINALITY checking for `repeat_row`, but then the
3195        // error message would be misleading, because it would refer to WITH ORDINALITY instead of
3196        // ROWS FROM.
3197        bail_unsupported!(format!("{} in ROWS FROM", REPEAT_ROW_NAME));
3198    }
3199
3200    // If there's only a single table function, planning proceeds as if `ROWS
3201    // FROM` hadn't been written at all.
3202    if let [function] = functions {
3203        return plan_solitary_table_function(qcx, function, alias, with_ordinality);
3204    }
3205
3206    // Per PostgreSQL, all scope items take the name of the first function
3207    // (unless aliased).
3208    // See: https://github.com/postgres/postgres/blob/639a86e36/src/backend/parser/parse_relation.c#L1701-L1705
3209    let (expr, mut scope, num_cols) = plan_rows_from_internal(
3210        qcx,
3211        functions,
3212        Some(functions[0].name.full_item_name().clone()),
3213    )?;
3214
3215    // Columns tracks the set of columns we will keep in the projection.
3216    let mut columns = Vec::new();
3217    let mut offset = 0;
3218    // Retain table function's non-ordinality columns.
3219    for (idx, cols) in num_cols.into_iter().enumerate() {
3220        for i in 0..cols {
3221            columns.push(offset + i);
3222        }
3223        offset += cols + 1;
3224
3225        // Remove the ordinality column from the scope, accounting for previous scope
3226        // changes from this loop.
3227        scope.items.remove(offset - idx - 1);
3228    }
3229
3230    // If `WITH ORDINALITY` was specified, include the coalesced ordinality
3231    // column. Otherwise remove it from the scope.
3232    if with_ordinality {
3233        columns.push(offset);
3234    } else {
3235        scope.items.pop();
3236    }
3237
3238    let expr = expr.project(columns);
3239
3240    let scope = plan_table_alias(scope, alias)?;
3241    Ok((expr, scope))
3242}
3243
3244fn is_repeat_row(f: &Function<Aug>) -> bool {
3245    f.name.full_name_str().as_str() == format!("{}.{}", MZ_CATALOG_SCHEMA, REPEAT_ROW_NAME)
3246}
3247
3248/// Plans an expression coalescing multiple table functions. Each table
3249/// function is followed by its row ordinality. The entire expression is
3250/// followed by the coalesced row ordinality.
3251///
3252/// The returned Scope will set all item's table_name's to the `table_name`
3253/// parameter if it is `Some`. If `None`, they will be the name of each table
3254/// function.
3255///
3256/// The returned `Vec<usize>` is the number of (non-ordinality) columns from
3257/// each table function.
3258///
3259/// For example, with table functions tf1 returning 1 column (a) and tf2
3260/// returning 2 columns (b, c), this function will return an expr 6 columns:
3261///
3262/// - tf1.a
3263/// - tf1.ordinality
3264/// - tf2.b
3265/// - tf2.c
3266/// - tf2.ordinality
3267/// - coalesced_ordinality
3268///
3269/// And a `Vec<usize>` of `[1, 2]`.
3270fn plan_rows_from_internal<'a>(
3271    qcx: &QueryContext,
3272    functions: impl IntoIterator<Item = &'a Function<Aug>>,
3273    table_name: Option<FullItemName>,
3274) -> Result<(HirRelationExpr, Scope, Vec<usize>), PlanError> {
3275    let mut functions = functions.into_iter();
3276    let mut num_cols = Vec::new();
3277
3278    // Join together each of the table functions in turn. The last column is
3279    // always the column to join against and is maintained to be the coalescence
3280    // of the row number column for all prior functions.
3281    let (mut left_expr, mut left_scope) =
3282        plan_table_function_internal(qcx, functions.next().unwrap(), true, table_name.clone())?;
3283    num_cols.push(left_scope.len() - 1);
3284    // Create the coalesced ordinality column.
3285    left_expr = left_expr.map(vec![HirScalarExpr::column(left_scope.len() - 1)]);
3286    left_scope
3287        .items
3288        .push(ScopeItem::from_column_name(ORDINALITY_COL_NAME));
3289
3290    for function in functions {
3291        // The right hand side of a join must be planned in a new scope.
3292        let qcx = qcx.empty_derived_context();
3293        let (right_expr, mut right_scope) =
3294            plan_table_function_internal(&qcx, function, true, table_name.clone())?;
3295        num_cols.push(right_scope.len() - 1);
3296        let left_col = left_scope.len() - 1;
3297        let right_col = left_scope.len() + right_scope.len() - 1;
3298        let on = HirScalarExpr::call_binary(
3299            HirScalarExpr::column(left_col),
3300            HirScalarExpr::column(right_col),
3301            expr_func::Eq,
3302        );
3303        left_expr = left_expr
3304            .join(right_expr, on, JoinKind::FullOuter)
3305            .map(vec![HirScalarExpr::call_variadic(
3306                Coalesce,
3307                vec![
3308                    HirScalarExpr::column(left_col),
3309                    HirScalarExpr::column(right_col),
3310                ],
3311            )]);
3312
3313        // Project off the previous iteration's coalesced column, but keep both of this
3314        // iteration's ordinality columns.
3315        left_expr = left_expr.project(
3316            (0..left_col) // non-coalesced ordinality columns from left function
3317                .chain(left_col + 1..right_col + 2) // non-ordinality columns from right function
3318                .collect(),
3319        );
3320        // Move the coalesced ordinality column.
3321        right_scope.items.push(left_scope.items.pop().unwrap());
3322
3323        left_scope.items.extend(right_scope.items);
3324    }
3325
3326    Ok((left_expr, left_scope, num_cols))
3327}
3328
3329/// Plans a table function that appears alone, i.e., that is not part of a `ROWS
3330/// FROM` clause that contains other table functions. Special aliasing rules
3331/// apply.
3332fn plan_solitary_table_function(
3333    qcx: &QueryContext,
3334    function: &Function<Aug>,
3335    alias: Option<&TableAlias>,
3336    with_ordinality: bool,
3337) -> Result<(HirRelationExpr, Scope), PlanError> {
3338    let (expr, mut scope) = plan_table_function_internal(qcx, function, with_ordinality, None)?;
3339
3340    let single_column_function = scope.len() == 1 + if with_ordinality { 1 } else { 0 };
3341    if single_column_function {
3342        let item = &mut scope.items[0];
3343
3344        // Mark that the function only produced a single column. This impacts
3345        // whole-row references.
3346        item.from_single_column_function = true;
3347
3348        // Strange special case for solitary table functions that output one
3349        // column whose name matches the name of the table function. If a table
3350        // alias is provided, the column name is changed to the table alias's
3351        // name. Concretely, the following query returns a column named `x`
3352        // rather than a column named `generate_series`:
3353        //
3354        //     SELECT * FROM generate_series(1, 5) AS x
3355        //
3356        // Note that this case does not apply to e.g. `jsonb_array_elements`,
3357        // since its output column is explicitly named `value`, not
3358        // `jsonb_array_elements`.
3359        //
3360        // Note also that we may (correctly) change the column name again when
3361        // we plan the table alias below if the `alias.columns` is non-empty.
3362        if let Some(alias) = alias {
3363            if let ScopeItem {
3364                table_name: Some(table_name),
3365                column_name,
3366                ..
3367            } = item
3368            {
3369                if table_name.item.as_str() == column_name.as_str() {
3370                    *column_name = normalize::column_name(alias.name.clone());
3371                }
3372            }
3373        }
3374    }
3375
3376    let scope = plan_table_alias(scope, alias)?;
3377    Ok((expr, scope))
3378}
3379
3380/// Plans a table function.
3381///
3382/// You generally should call `plan_rows_from` or `plan_solitary_table_function`
3383/// instead to get the appropriate aliasing behavior.
3384fn plan_table_function_internal(
3385    qcx: &QueryContext,
3386    Function {
3387        name,
3388        args,
3389        filter,
3390        over,
3391        distinct,
3392    }: &Function<Aug>,
3393    with_ordinality: bool,
3394    table_name: Option<FullItemName>,
3395) -> Result<(HirRelationExpr, Scope), PlanError> {
3396    // The parser rejects FILTER, OVER, and DISTINCT in every table function
3397    // position (`FROM f(...)`, `ROWS FROM (...)`), and table functions in
3398    // scalar position are only lifted into a `FROM` clause when all three are
3399    // absent, so these are defensive.
3400    if filter.is_some() {
3401        sql_bail!("FILTER is not allowed for table functions in FROM");
3402    }
3403    if over.is_some() {
3404        sql_bail!("OVER is not allowed for table functions in FROM");
3405    }
3406    if *distinct {
3407        sql_bail!("DISTINCT is not allowed for table functions in FROM");
3408    }
3409
3410    let ecx = &ExprContext {
3411        qcx,
3412        name: "table function arguments",
3413        scope: &Scope::empty(),
3414        relation_type: &SqlRelationType::empty(),
3415        allow_aggregates: false,
3416        allow_subqueries: true,
3417        allow_parameters: true,
3418        allow_windows: false,
3419    };
3420
3421    let scalar_args = match args {
3422        FunctionArgs::Star => sql_bail!("{} does not accept * as an argument", name),
3423        FunctionArgs::Args { args, order_by } => {
3424            if !order_by.is_empty() {
3425                sql_bail!(
3426                    "ORDER BY specified, but {} is not an aggregate function",
3427                    name
3428                );
3429            }
3430            plan_exprs(ecx, args)?
3431        }
3432    };
3433
3434    let table_name = match table_name {
3435        Some(table_name) => table_name.item,
3436        None => name.full_item_name().item.clone(),
3437    };
3438
3439    let scope_name = Some(PartialItemName {
3440        database: None,
3441        schema: None,
3442        item: table_name,
3443    });
3444
3445    let (expr, mut scope) = match resolve_func(ecx, name, args)? {
3446        Func::Table(impls) => {
3447            let tf = func::select_impl(ecx, FuncSpec::Func(name), impls, scalar_args, vec![])?;
3448            let scope = Scope::from_source(scope_name.clone(), tf.column_names);
3449            let expr = match tf.imp {
3450                TableFuncImpl::CallTable { mut func, exprs } => {
3451                    if with_ordinality {
3452                        func = TableFunc::with_ordinality(func.clone()).ok_or(
3453                            PlanError::Unsupported {
3454                                feature: format!("WITH ORDINALITY on {}", func),
3455                                discussion_no: None,
3456                            },
3457                        )?;
3458                    }
3459                    HirRelationExpr::CallTable { func, exprs }
3460                }
3461                TableFuncImpl::Expr(expr) => {
3462                    if !with_ordinality {
3463                        expr
3464                    } else {
3465                        // The table function is defined by a SQL query (i.e., TableFuncImpl::Expr),
3466                        // so we can't use the new `WITH ORDINALITY` implementation. We can fall
3467                        // back to the legacy implementation or error out the query.
3468                        if qcx
3469                            .scx
3470                            .is_feature_flag_enabled(&ENABLE_WITH_ORDINALITY_LEGACY_FALLBACK)
3471                        {
3472                            // Note that this can give an incorrect ordering, and also has an extreme
3473                            // performance problem in some cases. See the doc comment of
3474                            // `TableFuncImpl`.
3475                            tracing::error!(
3476                                %name,
3477                                "Using the legacy WITH ORDINALITY / ROWS FROM implementation for a table function",
3478                            );
3479                            expr.map(vec![HirScalarExpr::windowing(WindowExpr {
3480                                func: WindowExprType::Scalar(ScalarWindowExpr {
3481                                    func: ScalarWindowFunc::RowNumber,
3482                                    order_by: vec![],
3483                                }),
3484                                partition_by: vec![],
3485                                order_by: vec![],
3486                            })])
3487                        } else {
3488                            bail_unsupported!(format!(
3489                                "WITH ORDINALITY or ROWS FROM with {}",
3490                                name
3491                            ));
3492                        }
3493                    }
3494                }
3495            };
3496            (expr, scope)
3497        }
3498        Func::Scalar(impls) => {
3499            let expr = func::select_impl(ecx, FuncSpec::Func(name), impls, scalar_args, vec![])?;
3500            let output = expr.typ(
3501                &qcx.outer_relation_types,
3502                &SqlRelationType::new(vec![]),
3503                &qcx.scx.param_types.borrow(),
3504            );
3505
3506            let relation = SqlRelationType::new(vec![output]);
3507
3508            let function_ident = Ident::new(name.full_item_name().item.clone())?;
3509            let column_name = normalize::column_name(function_ident);
3510            let name = column_name.to_string();
3511
3512            let scope = Scope::from_source(scope_name.clone(), vec![column_name]);
3513
3514            let mut func = TableFunc::TabletizedScalar { relation, name };
3515            if with_ordinality {
3516                func = TableFunc::with_ordinality(func.clone()).ok_or(PlanError::Unsupported {
3517                    feature: format!("WITH ORDINALITY on {}", func),
3518                    discussion_no: None,
3519                })?;
3520            }
3521            (
3522                HirRelationExpr::CallTable {
3523                    func,
3524                    exprs: vec![expr],
3525                },
3526                scope,
3527            )
3528        }
3529        o => sql_bail!(
3530            "{} functions are not supported in functions in FROM",
3531            o.class()
3532        ),
3533    };
3534
3535    if with_ordinality {
3536        scope
3537            .items
3538            .push(ScopeItem::from_name(scope_name, "ordinality"));
3539    }
3540
3541    Ok((expr, scope))
3542}
3543
3544fn plan_table_alias(mut scope: Scope, alias: Option<&TableAlias>) -> Result<Scope, PlanError> {
3545    if let Some(TableAlias {
3546        name,
3547        columns,
3548        strict,
3549    }) = alias
3550    {
3551        if (columns.len() > scope.items.len()) || (*strict && columns.len() != scope.items.len()) {
3552            sql_bail!(
3553                "{} has {} columns available but {} columns specified",
3554                name,
3555                scope.items.len(),
3556                columns.len()
3557            );
3558        }
3559
3560        let table_name = normalize::ident(name.to_owned());
3561        for (i, item) in scope.items.iter_mut().enumerate() {
3562            item.table_name = if item.allow_unqualified_references {
3563                Some(PartialItemName {
3564                    database: None,
3565                    schema: None,
3566                    item: table_name.clone(),
3567                })
3568            } else {
3569                // Columns that prohibit unqualified references are special
3570                // columns from the output of a NATURAL or USING join that can
3571                // only be referenced by their full, pre-join name. Applying an
3572                // alias to the output of that join renders those columns
3573                // inaccessible, which we accomplish here by setting the
3574                // table name to `None`.
3575                //
3576                // Concretely, consider:
3577                //
3578                //      CREATE TABLE t1 (a int);
3579                //      CREATE TABLE t2 (a int);
3580                //  (1) SELECT ... FROM (t1 NATURAL JOIN t2);
3581                //  (2) SELECT ... FROM (t1 NATURAL JOIN t2) AS t;
3582                //
3583                // In (1), the join has no alias. The underlying columns from
3584                // either side of the join can be referenced as `t1.a` and
3585                // `t2.a`, respectively, and the unqualified name `a` refers to
3586                // a column whose value is `coalesce(t1.a, t2.a)`.
3587                //
3588                // In (2), the join is aliased as `t`. The columns from either
3589                // side of the join (`t1.a` and `t2.a`) are inaccessible, and
3590                // the coalesced column can be named as either `a` or `t.a`.
3591                //
3592                // We previously had a bug [0] that mishandled this subtle
3593                // logic.
3594                //
3595                // NOTE(benesch): We could in theory choose to project away
3596                // those inaccessible columns and drop them from the scope
3597                // entirely, but that would require that this function also
3598                // take and return the `HirRelationExpr` that is being aliased,
3599                // which is a rather large refactor.
3600                //
3601                // [0]: https://github.com/MaterializeInc/database-issues/issues/4887
3602                None
3603            };
3604            item.column_name = columns
3605                .get(i)
3606                .map(|a| normalize::column_name(a.clone()))
3607                .unwrap_or_else(|| item.column_name.clone());
3608        }
3609    }
3610    Ok(scope)
3611}
3612
3613// `table_func_names` is a mapping from a UUID to the original function
3614// name. The UUIDs are identifiers that have been rewritten from some table
3615// function expression, and this mapping restores the original names.
3616fn invent_column_name(
3617    ecx: &ExprContext,
3618    expr: &Expr<Aug>,
3619    table_func_names: &BTreeMap<String, Ident>,
3620) -> Result<Option<ColumnName>, PlanError> {
3621    // We follow PostgreSQL exactly here, which has some complicated rules
3622    // around "high" and "low" quality names. Low quality names override other
3623    // low quality names but not high quality names.
3624    //
3625    // See: https://github.com/postgres/postgres/blob/1f655fdc3/src/backend/parser/parse_target.c#L1716-L1728
3626
3627    #[derive(Debug)]
3628    enum NameQuality {
3629        Low,
3630        High,
3631    }
3632
3633    fn invent(
3634        ecx: &ExprContext,
3635        expr: &Expr<Aug>,
3636        table_func_names: &BTreeMap<String, Ident>,
3637    ) -> Result<Option<(ColumnName, NameQuality)>, PlanError> {
3638        Ok(match expr {
3639            Expr::Identifier(names) => {
3640                if let [name] = names.as_slice() {
3641                    if let Some(table_func_name) = table_func_names.get(name.as_str()) {
3642                        return Ok(Some((
3643                            normalize::column_name(table_func_name.clone()),
3644                            NameQuality::High,
3645                        )));
3646                    }
3647                }
3648                names
3649                    .last()
3650                    .map(|n| (normalize::column_name(n.clone()), NameQuality::High))
3651            }
3652            Expr::Value(v) => match v {
3653                // Per PostgreSQL, `bool` and `interval` literals take on the name
3654                // of their type, but not other literal types.
3655                Value::Boolean(_) => Some(("bool".into(), NameQuality::High)),
3656                Value::Interval(_) => Some(("interval".into(), NameQuality::High)),
3657                _ => None,
3658            },
3659            Expr::Function(func) => {
3660                let (schema, item) = match &func.name {
3661                    ResolvedItemName::Item {
3662                        qualifiers,
3663                        full_name,
3664                        ..
3665                    } => (&qualifiers.schema_spec, full_name.item.clone()),
3666                    // Name resolution should have rejected anything other than
3667                    // `Item` for a function call.
3668                    _ => {
3669                        bail_internal!("function name did not resolve to an item: {:?}", func.name)
3670                    }
3671                };
3672
3673                if schema == &SchemaSpecifier::from(ecx.qcx.scx.catalog.get_mz_internal_schema_id())
3674                    || schema
3675                        == &SchemaSpecifier::from(ecx.qcx.scx.catalog.get_mz_unsafe_schema_id())
3676                {
3677                    None
3678                } else {
3679                    Some((item.into(), NameQuality::High))
3680                }
3681            }
3682            Expr::HomogenizingFunction { function, .. } => Some((
3683                function.to_string().to_lowercase().into(),
3684                NameQuality::High,
3685            )),
3686            Expr::NullIf { .. } => Some(("nullif".into(), NameQuality::High)),
3687            Expr::Array { .. } => Some(("array".into(), NameQuality::High)),
3688            Expr::List { .. } => Some(("list".into(), NameQuality::High)),
3689            Expr::Map { .. } | Expr::MapSubquery(_) => Some(("map".into(), NameQuality::High)),
3690            Expr::Cast { expr, data_type } => match invent(ecx, expr, table_func_names)? {
3691                Some((name, NameQuality::High)) => Some((name, NameQuality::High)),
3692                _ => Some((data_type.unqualified_item_name().into(), NameQuality::Low)),
3693            },
3694            Expr::Case { else_result, .. } => {
3695                let inner = match else_result.as_ref() {
3696                    Some(else_result) => invent(ecx, else_result, table_func_names)?,
3697                    None => None,
3698                };
3699                match inner {
3700                    Some((name, NameQuality::High)) => Some((name, NameQuality::High)),
3701                    _ => Some(("case".into(), NameQuality::Low)),
3702                }
3703            }
3704            Expr::FieldAccess { field, .. } => {
3705                Some((normalize::column_name(field.clone()), NameQuality::High))
3706            }
3707            Expr::Exists { .. } => Some(("exists".into(), NameQuality::High)),
3708            Expr::Subscript { expr, .. } => invent(ecx, expr, table_func_names)?,
3709            Expr::Subquery(query) | Expr::ListSubquery(query) | Expr::ArraySubquery(query) => {
3710                // A bit silly to have to plan the query here just to get its column
3711                // name, since we throw away the planned expression, but fixing this
3712                // requires a separate semantic analysis phase.
3713                //
3714                // We deliberately swallow planning errors here: if the subquery
3715                // doesn't plan, we just don't invent a name for it; the real
3716                // planning attempt elsewhere will surface the error.
3717                let Ok((_expr, scope)) = plan_nested_query(&mut ecx.derived_query_context(), query)
3718                else {
3719                    return Ok(None);
3720                };
3721                scope
3722                    .items
3723                    .first()
3724                    .map(|name| (name.column_name.clone(), NameQuality::High))
3725            }
3726            Expr::Row { .. } => Some(("row".into(), NameQuality::High)),
3727            _ => None,
3728        })
3729    }
3730
3731    Ok(invent(ecx, expr, table_func_names)?.map(|(name, _quality)| name))
3732}
3733
3734#[derive(Debug)]
3735enum ExpandedSelectItem<'a> {
3736    InputOrdinal(usize),
3737    Expr(Cow<'a, Expr<Aug>>),
3738}
3739
3740impl ExpandedSelectItem<'_> {
3741    fn as_expr(&self) -> Option<&Expr<Aug>> {
3742        match self {
3743            ExpandedSelectItem::InputOrdinal(_) => None,
3744            ExpandedSelectItem::Expr(expr) => Some(expr),
3745        }
3746    }
3747}
3748
3749fn expand_select_item<'a>(
3750    ecx: &ExprContext,
3751    s: &'a SelectItem<Aug>,
3752    table_func_names: &BTreeMap<String, Ident>,
3753) -> Result<Vec<(ExpandedSelectItem<'a>, ColumnName)>, PlanError> {
3754    match s {
3755        SelectItem::Expr {
3756            expr: Expr::QualifiedWildcard(table_name),
3757            alias: _,
3758        } => {
3759            *ecx.qcx.scx.ambiguous_columns.borrow_mut() = true;
3760            let table_name =
3761                normalize::unresolved_item_name(UnresolvedItemName(table_name.clone()))?;
3762            let out: Vec<_> = ecx
3763                .scope
3764                .items
3765                .iter()
3766                .enumerate()
3767                .filter(|(_i, item)| item.is_from_table(&table_name))
3768                .map(|(i, item)| {
3769                    let name = item.column_name.clone();
3770                    (ExpandedSelectItem::InputOrdinal(i), name)
3771                })
3772                .collect();
3773            if out.is_empty() {
3774                sql_bail!("no table named '{}' in scope", table_name);
3775            }
3776            Ok(out)
3777        }
3778        SelectItem::Expr {
3779            expr: Expr::WildcardAccess(sql_expr),
3780            alias: _,
3781        } => {
3782            *ecx.qcx.scx.ambiguous_columns.borrow_mut() = true;
3783            // A bit silly to have to plan the expression here just to get its
3784            // type, since we throw away the planned expression, but fixing this
3785            // requires a separate semantic analysis phase. Luckily this is an
3786            // uncommon operation and the PostgreSQL docs have a warning that
3787            // this operation is slow in Postgres too.
3788            let expr = plan_expr(ecx, sql_expr)?.type_as_any(ecx)?;
3789            let fields = match ecx.scalar_type(&expr) {
3790                SqlScalarType::Record { fields, .. } => fields,
3791                ty => sql_bail!(
3792                    "type {} is not composite",
3793                    ecx.humanize_sql_scalar_type(&ty, false)
3794                ),
3795            };
3796            let mut skip_cols: BTreeSet<ColumnName> = BTreeSet::new();
3797            if let Expr::Identifier(ident) = sql_expr.as_ref() {
3798                if let [name] = ident.as_slice() {
3799                    if let Ok(items) = ecx.scope.items_from_table(
3800                        &[],
3801                        &PartialItemName {
3802                            database: None,
3803                            schema: None,
3804                            item: name.as_str().to_string(),
3805                        },
3806                    ) {
3807                        for (_, item) in items {
3808                            if item
3809                                .is_exists_column_for_a_table_function_that_was_in_the_target_list
3810                            {
3811                                skip_cols.insert(item.column_name.clone());
3812                            }
3813                        }
3814                    }
3815                }
3816            }
3817            let items = fields
3818                .iter()
3819                .filter_map(|(name, _ty)| {
3820                    if skip_cols.contains(name) {
3821                        None
3822                    } else {
3823                        let item = ExpandedSelectItem::Expr(Cow::Owned(Expr::FieldAccess {
3824                            expr: sql_expr.clone(),
3825                            field: name.clone().into(),
3826                        }));
3827                        Some((item, name.clone()))
3828                    }
3829                })
3830                .collect();
3831            Ok(items)
3832        }
3833        SelectItem::Wildcard => {
3834            *ecx.qcx.scx.ambiguous_columns.borrow_mut() = true;
3835            let items: Vec<_> = ecx
3836                .scope
3837                .items
3838                .iter()
3839                .enumerate()
3840                .filter(|(_i, item)| item.allow_unqualified_references)
3841                .map(|(i, item)| {
3842                    let name = item.column_name.clone();
3843                    (ExpandedSelectItem::InputOrdinal(i), name)
3844                })
3845                .collect();
3846
3847            Ok(items)
3848        }
3849        SelectItem::Expr { expr, alias } => {
3850            let name = match alias.clone().map(normalize::column_name) {
3851                Some(name) => name,
3852                None => invent_column_name(ecx, expr, table_func_names)?
3853                    .unwrap_or_else(|| UNKNOWN_COLUMN_NAME.into()),
3854            };
3855            Ok(vec![(ExpandedSelectItem::Expr(Cow::Borrowed(expr)), name)])
3856        }
3857    }
3858}
3859
3860fn plan_join(
3861    left_qcx: &QueryContext,
3862    left: HirRelationExpr,
3863    left_scope: Scope,
3864    join: &Join<Aug>,
3865) -> Result<(HirRelationExpr, Scope), PlanError> {
3866    const ON_TRUE: JoinConstraint<Aug> = JoinConstraint::On(Expr::Value(Value::Boolean(true)));
3867    let (kind, constraint) = match &join.join_operator {
3868        JoinOperator::CrossJoin => (JoinKind::Inner, &ON_TRUE),
3869        JoinOperator::Inner(constraint) => (JoinKind::Inner, constraint),
3870        JoinOperator::LeftOuter(constraint) => (JoinKind::LeftOuter, constraint),
3871        JoinOperator::RightOuter(constraint) => (JoinKind::RightOuter, constraint),
3872        JoinOperator::FullOuter(constraint) => (JoinKind::FullOuter, constraint),
3873    };
3874
3875    let mut right_qcx = left_qcx.derived_context(left_scope.clone(), left_qcx.relation_type(&left));
3876    if !kind.can_be_correlated() {
3877        for item in &mut right_qcx.outer_scopes[0].items {
3878            // Per PostgreSQL (and apparently SQL:2008), we can't simply remove
3879            // these items from scope. These items need to *exist* because they
3880            // might shadow variables in outer scopes that would otherwise be
3881            // valid to reference, but accessing them needs to produce an error.
3882            item.error_if_referenced =
3883                Some(|table, column| PlanError::WrongJoinTypeForLateralColumn {
3884                    table: table.cloned(),
3885                    column: column.clone(),
3886                });
3887        }
3888    }
3889    let (right, right_scope) = plan_table_factor(&right_qcx, &join.relation)?;
3890
3891    let (expr, scope) = match constraint {
3892        JoinConstraint::On(expr) => {
3893            let product_scope = left_scope.product(right_scope)?;
3894            let ecx = &ExprContext {
3895                qcx: left_qcx,
3896                name: "ON clause",
3897                scope: &product_scope,
3898                relation_type: &SqlRelationType::new(
3899                    left_qcx
3900                        .relation_type(&left)
3901                        .column_types
3902                        .into_iter()
3903                        .chain(right_qcx.relation_type(&right).column_types)
3904                        .collect(),
3905                ),
3906                allow_aggregates: false,
3907                allow_subqueries: true,
3908                allow_parameters: true,
3909                allow_windows: false,
3910            };
3911            let on = plan_expr(ecx, expr)?.type_as(ecx, &SqlScalarType::Bool)?;
3912            let joined = left.join(right, on, kind);
3913            (joined, product_scope)
3914        }
3915        JoinConstraint::Using { columns, alias } => {
3916            let column_names = columns
3917                .iter()
3918                .map(|ident| normalize::column_name(ident.clone()))
3919                .collect::<Vec<_>>();
3920
3921            plan_using_constraint(
3922                &column_names,
3923                left_qcx,
3924                left,
3925                left_scope,
3926                &right_qcx,
3927                right,
3928                right_scope,
3929                kind,
3930                alias.as_ref(),
3931            )?
3932        }
3933        JoinConstraint::Natural => {
3934            // We shouldn't need to set ambiguous_columns on both the right and left qcx since they
3935            // have the same scx. However, it doesn't hurt to be safe.
3936            *left_qcx.scx.ambiguous_columns.borrow_mut() = true;
3937            *right_qcx.scx.ambiguous_columns.borrow_mut() = true;
3938            let left_column_names = left_scope.column_names();
3939            let right_column_names: BTreeSet<_> = right_scope.column_names().collect();
3940            let column_names: Vec<_> = left_column_names
3941                .filter(|col| right_column_names.contains(col))
3942                .cloned()
3943                .collect();
3944            plan_using_constraint(
3945                &column_names,
3946                left_qcx,
3947                left,
3948                left_scope,
3949                &right_qcx,
3950                right,
3951                right_scope,
3952                kind,
3953                None,
3954            )?
3955        }
3956    };
3957    Ok((expr, scope))
3958}
3959
3960// See page 440 of ANSI SQL 2016 spec for details on scoping of using/natural joins
3961#[allow(clippy::too_many_arguments)]
3962fn plan_using_constraint(
3963    column_names: &[ColumnName],
3964    left_qcx: &QueryContext,
3965    left: HirRelationExpr,
3966    left_scope: Scope,
3967    right_qcx: &QueryContext,
3968    right: HirRelationExpr,
3969    right_scope: Scope,
3970    kind: JoinKind,
3971    alias: Option<&Ident>,
3972) -> Result<(HirRelationExpr, Scope), PlanError> {
3973    let mut both_scope = left_scope.clone().product(right_scope.clone())?;
3974
3975    // Cargo culting PG here; no discernable reason this must fail, but PG does
3976    // so we do, as well.
3977    let mut unique_column_names = BTreeSet::new();
3978    for c in column_names {
3979        if !unique_column_names.insert(c) {
3980            return Err(PlanError::Unsupported {
3981                feature: format!(
3982                    "column name {} appears more than once in USING clause",
3983                    c.quoted()
3984                ),
3985                discussion_no: None,
3986            });
3987        }
3988    }
3989
3990    let alias_item_name = alias.map(|alias| PartialItemName {
3991        database: None,
3992        schema: None,
3993        item: alias.clone().to_string(),
3994    });
3995
3996    if let Some(alias_item_name) = &alias_item_name {
3997        for partial_item_name in both_scope.table_names() {
3998            if partial_item_name.matches(alias_item_name) {
3999                sql_bail!(
4000                    "table name \"{}\" specified more than once",
4001                    alias_item_name
4002                )
4003            }
4004        }
4005    }
4006
4007    let ecx = &ExprContext {
4008        qcx: right_qcx,
4009        name: "USING clause",
4010        scope: &both_scope,
4011        relation_type: &SqlRelationType::new(
4012            left_qcx
4013                .relation_type(&left)
4014                .column_types
4015                .into_iter()
4016                .chain(right_qcx.relation_type(&right).column_types)
4017                .collect(),
4018        ),
4019        allow_aggregates: false,
4020        allow_subqueries: false,
4021        allow_parameters: false,
4022        allow_windows: false,
4023    };
4024
4025    let mut join_exprs = vec![];
4026    let mut map_exprs = vec![];
4027    let mut new_items = vec![];
4028    let mut join_cols = vec![];
4029    let mut hidden_cols = vec![];
4030
4031    for column_name in column_names {
4032        // the two sides will have different names (e.g., `t1.a` and `t2.a`)
4033        let (lhs, lhs_name) = left_scope.resolve_using_column(
4034            column_name,
4035            JoinSide::Left,
4036            &mut left_qcx.name_manager.borrow_mut(),
4037        )?;
4038        let (mut rhs, rhs_name) = right_scope.resolve_using_column(
4039            column_name,
4040            JoinSide::Right,
4041            &mut right_qcx.name_manager.borrow_mut(),
4042        )?;
4043
4044        // Adjust the RHS reference to its post-join location.
4045        rhs.column += left_scope.len();
4046
4047        // Join keys must be resolved to same type.
4048        let mut exprs = coerce_homogeneous_exprs(
4049            &ecx.with_name(&format!(
4050                "NATURAL/USING join column {}",
4051                column_name.quoted()
4052            )),
4053            vec![
4054                CoercibleScalarExpr::Coerced(HirScalarExpr::named_column(
4055                    lhs,
4056                    Arc::clone(&lhs_name),
4057                )),
4058                CoercibleScalarExpr::Coerced(HirScalarExpr::named_column(
4059                    rhs,
4060                    Arc::clone(&rhs_name),
4061                )),
4062            ],
4063            None,
4064        )?;
4065        let (expr1, expr2) = (exprs.remove(0), exprs.remove(0));
4066
4067        match kind {
4068            JoinKind::LeftOuter { .. } | JoinKind::Inner { .. } => {
4069                join_cols.push(lhs.column);
4070                hidden_cols.push(rhs.column);
4071            }
4072            JoinKind::RightOuter => {
4073                join_cols.push(rhs.column);
4074                hidden_cols.push(lhs.column);
4075            }
4076            JoinKind::FullOuter => {
4077                // Create a new column that will be the coalesced value of left
4078                // and right.
4079                join_cols.push(both_scope.items.len() + map_exprs.len());
4080                hidden_cols.push(lhs.column);
4081                hidden_cols.push(rhs.column);
4082                map_exprs.push(HirScalarExpr::call_variadic(
4083                    Coalesce,
4084                    vec![expr1.clone(), expr2.clone()],
4085                ));
4086                new_items.push(ScopeItem::from_column_name(column_name));
4087            }
4088        }
4089
4090        // If a `join_using_alias` is present, add a new scope item that accepts
4091        // only table-qualified references for each specified join column.
4092        // Unlike regular table aliases, a `join_using_alias` should not hide the
4093        // names of the joined relations.
4094        if alias_item_name.is_some() {
4095            let new_item_col = both_scope.items.len() + new_items.len();
4096            join_cols.push(new_item_col);
4097            hidden_cols.push(new_item_col);
4098
4099            new_items.push(ScopeItem::from_name(
4100                alias_item_name.clone(),
4101                column_name.clone().to_string(),
4102            ));
4103
4104            // The aliased column `alias.col` must take the same value as the
4105            // unqualified join output column `col`. For INNER and LEFT joins
4106            // that's the LHS value, for RIGHT joins it's the RHS value, and
4107            // for FULL OUTER joins it's COALESCE(lhs, rhs). Using `lhs`
4108            // unconditionally produces wrong results for RIGHT/FULL joins on
4109            // rows where the LHS side is NULL.
4110            let alias_expr = match kind {
4111                JoinKind::LeftOuter { .. } | JoinKind::Inner { .. } => {
4112                    HirScalarExpr::named_column(lhs, Arc::clone(&lhs_name))
4113                }
4114                JoinKind::RightOuter => HirScalarExpr::named_column(rhs, Arc::clone(&rhs_name)),
4115                JoinKind::FullOuter => {
4116                    HirScalarExpr::call_variadic(Coalesce, vec![expr1.clone(), expr2.clone()])
4117                }
4118            };
4119            map_exprs.push(alias_expr);
4120        }
4121
4122        join_exprs.push(expr1.call_binary(expr2, expr_func::Eq));
4123    }
4124    both_scope.items.extend(new_items);
4125
4126    // The columns from the secondary side of the join remain accessible by
4127    // their table-qualified name, but not by their column name alone. They are
4128    // also excluded from `SELECT *`.
4129    for c in hidden_cols {
4130        both_scope.items[c].allow_unqualified_references = false;
4131    }
4132
4133    // Reproject all returned elements to the front of the list.
4134    let project_key = join_cols
4135        .into_iter()
4136        .chain(0..both_scope.items.len())
4137        .unique()
4138        .collect::<Vec<_>>();
4139
4140    both_scope = both_scope.project(&project_key);
4141
4142    let on = HirScalarExpr::variadic_and(join_exprs);
4143
4144    let both = left
4145        .join(right, on, kind)
4146        .map(map_exprs)
4147        .project(project_key);
4148    Ok((both, both_scope))
4149}
4150
4151pub fn plan_expr<'a>(
4152    ecx: &'a ExprContext,
4153    e: &Expr<Aug>,
4154) -> Result<CoercibleScalarExpr, PlanError> {
4155    ecx.checked_recur(|ecx| plan_expr_inner(ecx, e))
4156}
4157
4158fn plan_expr_inner<'a>(
4159    ecx: &'a ExprContext,
4160    e: &Expr<Aug>,
4161) -> Result<CoercibleScalarExpr, PlanError> {
4162    if let Some((i, item)) = ecx.scope.resolve_expr(e) {
4163        // We've already calculated this expression.
4164        return Ok(HirScalarExpr::named_column(
4165            i,
4166            ecx.qcx.name_manager.borrow_mut().intern_scope_item(item),
4167        )
4168        .into());
4169    }
4170
4171    match e {
4172        // Names.
4173        Expr::Identifier(names) | Expr::QualifiedWildcard(names) => {
4174            Ok(plan_identifier(ecx, names)?.into())
4175        }
4176
4177        // Literals.
4178        Expr::Value(val) => plan_literal(val),
4179        Expr::Parameter(n) => plan_parameter(ecx, *n),
4180        Expr::Array(exprs) => plan_array(ecx, exprs, None),
4181        Expr::List(exprs) => plan_list(ecx, exprs, None),
4182        Expr::Map(exprs) => plan_map(ecx, exprs, None),
4183        Expr::Row { exprs } => plan_row(ecx, exprs),
4184
4185        // Generalized functions, operators, and casts.
4186        Expr::Op { op, expr1, expr2 } => {
4187            Ok(plan_op(ecx, normalize::op(op)?, expr1, expr2.as_deref())?.into())
4188        }
4189        Expr::Cast { expr, data_type } => plan_cast(ecx, expr, data_type),
4190        Expr::Function(func) => Ok(plan_function(ecx, func)?.into()),
4191
4192        // Special functions and operators.
4193        Expr::Not { expr } => plan_not(ecx, expr),
4194        Expr::And { left, right } => plan_and(ecx, left, right),
4195        Expr::Or { left, right } => plan_or(ecx, left, right),
4196        Expr::IsExpr {
4197            expr,
4198            construct,
4199            negated,
4200        } => Ok(plan_is_expr(ecx, expr, construct, *negated)?.into()),
4201        Expr::Case {
4202            operand,
4203            conditions,
4204            results,
4205            else_result,
4206        } => Ok(plan_case(ecx, operand, conditions, results, else_result)?.into()),
4207        Expr::HomogenizingFunction { function, exprs } => {
4208            plan_homogenizing_function(ecx, function, exprs)
4209        }
4210        Expr::NullIf { l_expr, r_expr } => Ok(plan_case(
4211            ecx,
4212            &None,
4213            &[l_expr.clone().equals(*r_expr.clone())],
4214            &[Expr::null()],
4215            &Some(Box::new(*l_expr.clone())),
4216        )?
4217        .into()),
4218        Expr::FieldAccess { expr, field } => plan_field_access(ecx, expr, field),
4219        Expr::WildcardAccess(expr) => plan_expr(ecx, expr),
4220        Expr::Subscript { expr, positions } => plan_subscript(ecx, expr, positions),
4221        Expr::Like {
4222            expr,
4223            pattern,
4224            escape,
4225            case_insensitive,
4226            negated,
4227        } => Ok(plan_like(
4228            ecx,
4229            expr,
4230            pattern,
4231            escape.as_deref(),
4232            *case_insensitive,
4233            *negated,
4234        )?
4235        .into()),
4236
4237        Expr::InList {
4238            expr,
4239            list,
4240            negated,
4241        } => plan_in_list(ecx, expr, list, negated),
4242
4243        // Subqueries.
4244        Expr::Exists(query) => plan_exists(ecx, query),
4245        Expr::Subquery(query) => plan_subquery(ecx, query),
4246        Expr::ListSubquery(query) => plan_list_subquery(ecx, query),
4247        Expr::MapSubquery(query) => plan_map_subquery(ecx, query),
4248        Expr::ArraySubquery(query) => plan_array_subquery(ecx, query),
4249        Expr::Collate { expr, collation } => plan_collate(ecx, expr, collation),
4250        Expr::Nested(_) => bail_internal!("Expr::Nested should have been desugared"),
4251        Expr::InSubquery { .. } => {
4252            bail_internal!("Expr::InSubquery should have been desugared")
4253        }
4254        Expr::AnyExpr { .. } => {
4255            bail_internal!("Expr::AnyExpr should have been desugared")
4256        }
4257        Expr::AllExpr { .. } => {
4258            bail_internal!("Expr::AllExpr should have been desugared")
4259        }
4260        Expr::AnySubquery { .. } => {
4261            bail_internal!("Expr::AnySubquery should have been desugared")
4262        }
4263        Expr::AllSubquery { .. } => {
4264            bail_internal!("Expr::AllSubquery should have been desugared")
4265        }
4266        Expr::Between { .. } => {
4267            bail_internal!("Expr::Between should have been desugared")
4268        }
4269    }
4270}
4271
4272fn plan_parameter(ecx: &ExprContext, n: usize) -> Result<CoercibleScalarExpr, PlanError> {
4273    if !ecx.allow_parameters {
4274        // It might be clearer to return an error like "cannot use parameter
4275        // here", but this is how PostgreSQL does it, and so for now we follow
4276        // PostgreSQL.
4277        return Err(PlanError::UnknownParameter(n));
4278    }
4279    if n == 0 || n > 65536 {
4280        return Err(PlanError::UnknownParameter(n));
4281    }
4282    if ecx.param_types().borrow().contains_key(&n) {
4283        Ok(HirScalarExpr::parameter(n).into())
4284    } else {
4285        Ok(CoercibleScalarExpr::Parameter(n))
4286    }
4287}
4288
4289fn plan_row(ecx: &ExprContext, exprs: &[Expr<Aug>]) -> Result<CoercibleScalarExpr, PlanError> {
4290    let mut out = vec![];
4291    for e in exprs {
4292        out.push(plan_expr(ecx, e)?);
4293    }
4294    Ok(CoercibleScalarExpr::LiteralRecord(out))
4295}
4296
4297fn plan_cast(
4298    ecx: &ExprContext,
4299    expr: &Expr<Aug>,
4300    data_type: &ResolvedDataType,
4301) -> Result<CoercibleScalarExpr, PlanError> {
4302    let to_scalar_type = scalar_type_from_sql(ecx.qcx.scx, data_type)?;
4303    let expr = match expr {
4304        // Special case a direct cast of an ARRAY, LIST, or MAP expression so
4305        // we can pass in the target type as a type hint. This is
4306        // a limited form of the coercion that we do for string literals
4307        // via CoercibleScalarExpr. We used to let CoercibleScalarExpr
4308        // handle ARRAY/LIST/MAP coercion too, but doing so causes
4309        // PostgreSQL compatibility trouble.
4310        //
4311        // See: https://github.com/postgres/postgres/blob/31f403e95/src/backend/parser/parse_expr.c#L2762-L2768
4312        Expr::Array(exprs) => plan_array(ecx, exprs, Some(&to_scalar_type))?,
4313        Expr::List(exprs) => plan_list(ecx, exprs, Some(&to_scalar_type))?,
4314        Expr::Map(exprs) => plan_map(ecx, exprs, Some(&to_scalar_type))?,
4315        _ => plan_expr(ecx, expr)?,
4316    };
4317    let ecx = &ecx.with_name("CAST");
4318    let expr = typeconv::plan_coerce(ecx, expr, &to_scalar_type)?;
4319    let expr = typeconv::plan_cast(ecx, CastContext::Explicit, expr, &to_scalar_type)?;
4320    Ok(expr.into())
4321}
4322
4323fn plan_not(ecx: &ExprContext, expr: &Expr<Aug>) -> Result<CoercibleScalarExpr, PlanError> {
4324    let ecx = ecx.with_name("NOT argument");
4325    Ok(plan_expr(&ecx, expr)?
4326        .type_as(&ecx, &SqlScalarType::Bool)?
4327        .call_unary(UnaryFunc::Not(expr_func::Not))
4328        .into())
4329}
4330
4331fn plan_and(
4332    ecx: &ExprContext,
4333    left: &Expr<Aug>,
4334    right: &Expr<Aug>,
4335) -> Result<CoercibleScalarExpr, PlanError> {
4336    let ecx = ecx.with_name("AND argument");
4337    Ok(HirScalarExpr::variadic_and(vec![
4338        plan_expr(&ecx, left)?.type_as(&ecx, &SqlScalarType::Bool)?,
4339        plan_expr(&ecx, right)?.type_as(&ecx, &SqlScalarType::Bool)?,
4340    ])
4341    .into())
4342}
4343
4344fn plan_or(
4345    ecx: &ExprContext,
4346    left: &Expr<Aug>,
4347    right: &Expr<Aug>,
4348) -> Result<CoercibleScalarExpr, PlanError> {
4349    let ecx = ecx.with_name("OR argument");
4350    Ok(HirScalarExpr::variadic_or(vec![
4351        plan_expr(&ecx, left)?.type_as(&ecx, &SqlScalarType::Bool)?,
4352        plan_expr(&ecx, right)?.type_as(&ecx, &SqlScalarType::Bool)?,
4353    ])
4354    .into())
4355}
4356
4357fn plan_in_list(
4358    ecx: &ExprContext,
4359    lhs: &Expr<Aug>,
4360    list: &Vec<Expr<Aug>>,
4361    negated: &bool,
4362) -> Result<CoercibleScalarExpr, PlanError> {
4363    let ecx = ecx.with_name("IN list");
4364    let or = HirScalarExpr::variadic_or(
4365        list.into_iter()
4366            .map(|e| {
4367                let eq = lhs.clone().equals(e.clone());
4368                plan_expr(&ecx, &eq)?.type_as(&ecx, &SqlScalarType::Bool)
4369            })
4370            .collect::<Result<Vec<HirScalarExpr>, PlanError>>()?,
4371    );
4372    Ok(if *negated {
4373        or.call_unary(UnaryFunc::Not(expr_func::Not))
4374    } else {
4375        or
4376    }
4377    .into())
4378}
4379
4380fn plan_homogenizing_function(
4381    ecx: &ExprContext,
4382    function: &HomogenizingFunction,
4383    exprs: &[Expr<Aug>],
4384) -> Result<CoercibleScalarExpr, PlanError> {
4385    assert!(!exprs.is_empty()); // `COALESCE()` is a syntax error
4386    let expr = HirScalarExpr::call_variadic(
4387        match function {
4388            HomogenizingFunction::Coalesce => VariadicFunc::from(Coalesce),
4389            HomogenizingFunction::Greatest => VariadicFunc::from(Greatest),
4390            HomogenizingFunction::Least => VariadicFunc::from(Least),
4391        },
4392        coerce_homogeneous_exprs(
4393            &ecx.with_name(&function.to_string().to_lowercase()),
4394            plan_exprs(ecx, exprs)?,
4395            None,
4396        )?,
4397    );
4398    Ok(expr.into())
4399}
4400
4401fn plan_field_access(
4402    ecx: &ExprContext,
4403    expr: &Expr<Aug>,
4404    field: &Ident,
4405) -> Result<CoercibleScalarExpr, PlanError> {
4406    let field = normalize::column_name(field.clone());
4407    let expr = plan_expr(ecx, expr)?.type_as_any(ecx)?;
4408    let ty = ecx.scalar_type(&expr);
4409    let i = match &ty {
4410        SqlScalarType::Record { fields, .. } => {
4411            fields.iter().position(|(name, _ty)| *name == field)
4412        }
4413        ty => sql_bail!(
4414            "column notation applied to type {}, which is not a composite type",
4415            ecx.humanize_sql_scalar_type(ty, false)
4416        ),
4417    };
4418    match i {
4419        None => sql_bail!(
4420            "field {} not found in data type {}",
4421            field,
4422            ecx.humanize_sql_scalar_type(&ty, false)
4423        ),
4424        Some(i) => Ok(expr
4425            .call_unary(UnaryFunc::RecordGet(expr_func::RecordGet(i)))
4426            .into()),
4427    }
4428}
4429
4430fn plan_subscript(
4431    ecx: &ExprContext,
4432    expr: &Expr<Aug>,
4433    positions: &[SubscriptPosition<Aug>],
4434) -> Result<CoercibleScalarExpr, PlanError> {
4435    assert!(
4436        !positions.is_empty(),
4437        "subscript expression must contain at least one position"
4438    );
4439
4440    let ecx = &ecx.with_name("subscripting");
4441    let expr = plan_expr(ecx, expr)?.type_as_any(ecx)?;
4442    let ty = ecx.scalar_type(&expr);
4443    match &ty {
4444        SqlScalarType::Array(..) | SqlScalarType::Int2Vector => plan_subscript_array(
4445            ecx,
4446            expr,
4447            positions,
4448            // Int2Vector uses 0-based indexing, while arrays use 1-based indexing, so we need to
4449            // adjust all Int2Vector subscript operations by 1 (both w/r/t input and the values we
4450            // track in its backing data).
4451            if ty == SqlScalarType::Int2Vector {
4452                1
4453            } else {
4454                0
4455            },
4456        ),
4457        SqlScalarType::Jsonb => plan_subscript_jsonb(ecx, expr, positions),
4458        SqlScalarType::List { element_type, .. } => {
4459            // `elem_type_name` is used only in error msgs, so we set `postgres_compat` to false.
4460            let elem_type_name = ecx.humanize_sql_scalar_type(element_type, false);
4461            let n_layers = ty.unwrap_list_n_layers();
4462            plan_subscript_list(ecx, expr, positions, n_layers, &elem_type_name)
4463        }
4464        ty => sql_bail!(
4465            "cannot subscript type {}",
4466            ecx.humanize_sql_scalar_type(ty, false)
4467        ),
4468    }
4469}
4470
4471// All subscript positions are of the form [<expr>(:<expr>?)?]; extract all
4472// expressions from those that look like indexes (i.e. `[<expr>]`) or error if
4473// any were slices (i.e. included colon).
4474fn extract_scalar_subscript_from_positions<'a>(
4475    positions: &'a [SubscriptPosition<Aug>],
4476    expr_type_name: &str,
4477) -> Result<Vec<&'a Expr<Aug>>, PlanError> {
4478    let mut scalar_subscripts = Vec::with_capacity(positions.len());
4479    for p in positions {
4480        if p.explicit_slice {
4481            sql_bail!("{} subscript does not support slices", expr_type_name);
4482        }
4483        assert!(
4484            p.end.is_none(),
4485            "index-appearing subscripts cannot have end value"
4486        );
4487        scalar_subscripts.push(p.start.as_ref().expect("has start if not slice"));
4488    }
4489    Ok(scalar_subscripts)
4490}
4491
4492fn plan_subscript_array(
4493    ecx: &ExprContext,
4494    expr: HirScalarExpr,
4495    positions: &[SubscriptPosition<Aug>],
4496    offset: i64,
4497) -> Result<CoercibleScalarExpr, PlanError> {
4498    let mut exprs = Vec::with_capacity(positions.len() + 1);
4499    exprs.push(expr);
4500
4501    // Subscripting arrays doesn't yet support slicing, so we always want to
4502    // extract scalars or error.
4503    let indexes = extract_scalar_subscript_from_positions(positions, "array")?;
4504
4505    for i in indexes {
4506        exprs.push(plan_expr(ecx, i)?.cast_to(
4507            ecx,
4508            CastContext::Explicit,
4509            &SqlScalarType::Int64,
4510        )?);
4511    }
4512
4513    Ok(HirScalarExpr::call_variadic(ArrayIndex { offset }, exprs).into())
4514}
4515
4516fn plan_subscript_list(
4517    ecx: &ExprContext,
4518    mut expr: HirScalarExpr,
4519    positions: &[SubscriptPosition<Aug>],
4520    mut remaining_layers: usize,
4521    elem_type_name: &str,
4522) -> Result<CoercibleScalarExpr, PlanError> {
4523    let mut i = 0;
4524
4525    while i < positions.len() {
4526        // Take all contiguous index operations, i.e. find next slice operation.
4527        let j = positions[i..]
4528            .iter()
4529            .position(|p| p.explicit_slice)
4530            .unwrap_or(positions.len() - i);
4531        if j != 0 {
4532            let indexes = extract_scalar_subscript_from_positions(&positions[i..i + j], "")?;
4533            let (n, e) = plan_index_list(
4534                ecx,
4535                expr,
4536                indexes.as_slice(),
4537                remaining_layers,
4538                elem_type_name,
4539            )?;
4540            remaining_layers = n;
4541            expr = e;
4542            i += j;
4543        }
4544
4545        // Take all contiguous slice operations, i.e. find next index operation.
4546        let j = positions[i..]
4547            .iter()
4548            .position(|p| !p.explicit_slice)
4549            .unwrap_or(positions.len() - i);
4550        if j != 0 {
4551            expr = plan_slice_list(
4552                ecx,
4553                expr,
4554                &positions[i..i + j],
4555                remaining_layers,
4556                elem_type_name,
4557            )?;
4558            i += j;
4559        }
4560    }
4561
4562    Ok(expr.into())
4563}
4564
4565fn plan_index_list(
4566    ecx: &ExprContext,
4567    expr: HirScalarExpr,
4568    indexes: &[&Expr<Aug>],
4569    n_layers: usize,
4570    elem_type_name: &str,
4571) -> Result<(usize, HirScalarExpr), PlanError> {
4572    let depth = indexes.len();
4573
4574    if depth > n_layers {
4575        if n_layers == 0 {
4576            sql_bail!("cannot subscript type {}", elem_type_name)
4577        } else {
4578            sql_bail!(
4579                "cannot index into {} layers; list only has {} layer{}",
4580                depth,
4581                n_layers,
4582                if n_layers == 1 { "" } else { "s" }
4583            )
4584        }
4585    }
4586
4587    let mut exprs = Vec::with_capacity(depth + 1);
4588    exprs.push(expr);
4589
4590    for i in indexes {
4591        exprs.push(plan_expr(ecx, i)?.cast_to(
4592            ecx,
4593            CastContext::Explicit,
4594            &SqlScalarType::Int64,
4595        )?);
4596    }
4597
4598    Ok((
4599        n_layers - depth,
4600        HirScalarExpr::call_variadic(ListIndex, exprs),
4601    ))
4602}
4603
4604fn plan_slice_list(
4605    ecx: &ExprContext,
4606    expr: HirScalarExpr,
4607    slices: &[SubscriptPosition<Aug>],
4608    n_layers: usize,
4609    elem_type_name: &str,
4610) -> Result<HirScalarExpr, PlanError> {
4611    if n_layers == 0 {
4612        sql_bail!("cannot subscript type {}", elem_type_name)
4613    }
4614
4615    // first arg will be list
4616    let mut exprs = Vec::with_capacity(slices.len() + 1);
4617    exprs.push(expr);
4618    // extract (start, end) parts from collected slices
4619    let extract_position_or_default = |position, default| -> Result<HirScalarExpr, PlanError> {
4620        Ok(match position {
4621            Some(p) => {
4622                plan_expr(ecx, p)?.cast_to(ecx, CastContext::Explicit, &SqlScalarType::Int64)?
4623            }
4624            None => HirScalarExpr::literal(Datum::Int64(default), SqlScalarType::Int64),
4625        })
4626    };
4627    for p in slices {
4628        let start = extract_position_or_default(p.start.as_ref(), 1)?;
4629        let end = extract_position_or_default(p.end.as_ref(), i64::MAX - 1)?;
4630        exprs.push(start);
4631        exprs.push(end);
4632    }
4633
4634    Ok(HirScalarExpr::call_variadic(ListSliceLinear, exprs))
4635}
4636
4637fn plan_like(
4638    ecx: &ExprContext,
4639    expr: &Expr<Aug>,
4640    pattern: &Expr<Aug>,
4641    escape: Option<&Expr<Aug>>,
4642    case_insensitive: bool,
4643    not: bool,
4644) -> Result<HirScalarExpr, PlanError> {
4645    use CastContext::Implicit;
4646    let ecx = ecx.with_name("LIKE argument");
4647    let expr = plan_expr(&ecx, expr)?;
4648    let haystack = match ecx.scalar_type(&expr) {
4649        CoercibleScalarType::Coerced(ref ty @ SqlScalarType::Char { length }) => expr
4650            .type_as(&ecx, ty)?
4651            .call_unary(UnaryFunc::PadChar(expr_func::PadChar { length })),
4652        _ => expr.cast_to(&ecx, Implicit, &SqlScalarType::String)?,
4653    };
4654    let mut pattern = plan_expr(&ecx, pattern)?.cast_to(&ecx, Implicit, &SqlScalarType::String)?;
4655    if let Some(escape) = escape {
4656        pattern = pattern.call_binary(
4657            plan_expr(&ecx, escape)?.cast_to(&ecx, Implicit, &SqlScalarType::String)?,
4658            expr_func::LikeEscape,
4659        );
4660    }
4661    let func: BinaryFunc = if case_insensitive {
4662        expr_func::IsLikeMatchCaseInsensitive.into()
4663    } else {
4664        expr_func::IsLikeMatchCaseSensitive.into()
4665    };
4666    let like = haystack.call_binary(pattern, func);
4667    if not {
4668        Ok(like.call_unary(UnaryFunc::Not(expr_func::Not)))
4669    } else {
4670        Ok(like)
4671    }
4672}
4673
4674fn plan_subscript_jsonb(
4675    ecx: &ExprContext,
4676    expr: HirScalarExpr,
4677    positions: &[SubscriptPosition<Aug>],
4678) -> Result<CoercibleScalarExpr, PlanError> {
4679    use CastContext::Implicit;
4680    use SqlScalarType::{Int64, String};
4681
4682    // JSONB doesn't support the slicing syntax, so simply error if you
4683    // encounter any explicit slices.
4684    let subscripts = extract_scalar_subscript_from_positions(positions, "jsonb")?;
4685
4686    let mut exprs = Vec::with_capacity(subscripts.len());
4687    for s in subscripts {
4688        let subscript = plan_expr(ecx, s)?;
4689        let subscript = if let Ok(subscript) = subscript.clone().cast_to(ecx, Implicit, &String) {
4690            subscript
4691        } else if let Ok(subscript) = subscript.cast_to(ecx, Implicit, &Int64) {
4692            // Integers are converted to a string here and then re-parsed as an
4693            // integer by `JsonbGetPath`. Weird, but this is how PostgreSQL says to
4694            // do it.
4695            typeconv::to_string(ecx, subscript)?
4696        } else {
4697            sql_bail!("jsonb subscript type must be coercible to integer or text");
4698        };
4699        exprs.push(subscript);
4700    }
4701
4702    // Subscripting works like `expr #> ARRAY[subscript]` rather than
4703    // `expr->subscript` as you might expect.
4704    let expr = expr.call_binary(
4705        HirScalarExpr::call_variadic(
4706            ArrayCreate {
4707                elem_type: SqlScalarType::String,
4708            },
4709            exprs,
4710        ),
4711        expr_func::JsonbGetPath,
4712    );
4713    Ok(expr.into())
4714}
4715
4716fn plan_exists(ecx: &ExprContext, query: &Query<Aug>) -> Result<CoercibleScalarExpr, PlanError> {
4717    if !ecx.allow_subqueries {
4718        sql_bail!("{} does not allow subqueries", ecx.name)
4719    }
4720    let mut qcx = ecx.derived_query_context();
4721    let (expr, _scope) = plan_nested_query(&mut qcx, query)?;
4722    Ok(expr.exists().into())
4723}
4724
4725fn plan_subquery(ecx: &ExprContext, query: &Query<Aug>) -> Result<CoercibleScalarExpr, PlanError> {
4726    if !ecx.allow_subqueries {
4727        sql_bail!("{} does not allow subqueries", ecx.name)
4728    }
4729    let mut qcx = ecx.derived_query_context();
4730    let (expr, _scope) = plan_nested_query(&mut qcx, query)?;
4731    let column_types = qcx.relation_type(&expr).column_types;
4732    if column_types.len() != 1 {
4733        sql_bail!(
4734            "Expected subselect to return 1 column, got {} columns",
4735            column_types.len()
4736        );
4737    }
4738    Ok(expr.select().into())
4739}
4740
4741fn plan_list_subquery(
4742    ecx: &ExprContext,
4743    query: &Query<Aug>,
4744) -> Result<CoercibleScalarExpr, PlanError> {
4745    plan_vector_like_subquery(
4746        ecx,
4747        query,
4748        |_| false,
4749        |elem_type| ListCreate { elem_type }.into(),
4750        |order_by| AggregateFunc::ListConcat { order_by },
4751        expr_func::ListListConcat.into(),
4752        |elem_type| {
4753            HirScalarExpr::literal(
4754                Datum::empty_list(),
4755                SqlScalarType::List {
4756                    element_type: Box::new(elem_type),
4757                    custom_id: None,
4758                },
4759            )
4760        },
4761        "list",
4762    )
4763}
4764
4765fn plan_array_subquery(
4766    ecx: &ExprContext,
4767    query: &Query<Aug>,
4768) -> Result<CoercibleScalarExpr, PlanError> {
4769    plan_vector_like_subquery(
4770        ecx,
4771        query,
4772        |elem_type| {
4773            matches!(
4774                elem_type,
4775                SqlScalarType::Char { .. }
4776                    | SqlScalarType::Array { .. }
4777                    | SqlScalarType::List { .. }
4778                    | SqlScalarType::Map { .. }
4779            )
4780        },
4781        |elem_type| ArrayCreate { elem_type }.into(),
4782        |order_by| AggregateFunc::ArrayConcat { order_by },
4783        expr_func::ArrayArrayConcat.into(),
4784        |elem_type| {
4785            HirScalarExpr::literal(
4786                Datum::empty_array(),
4787                SqlScalarType::Array(Box::new(elem_type)),
4788            )
4789        },
4790        "[]",
4791    )
4792}
4793
4794/// Generic function used to plan both array subqueries and list subqueries
4795fn plan_vector_like_subquery<F1, F2, F3, F4>(
4796    ecx: &ExprContext,
4797    query: &Query<Aug>,
4798    is_unsupported_type: F1,
4799    vector_create: F2,
4800    aggregate_concat: F3,
4801    binary_concat: BinaryFunc,
4802    empty_literal: F4,
4803    vector_type_string: &str,
4804) -> Result<CoercibleScalarExpr, PlanError>
4805where
4806    F1: Fn(&SqlScalarType) -> bool,
4807    F2: Fn(SqlScalarType) -> VariadicFunc,
4808    F3: Fn(Vec<ColumnOrder>) -> AggregateFunc,
4809    F4: Fn(SqlScalarType) -> HirScalarExpr,
4810{
4811    if !ecx.allow_subqueries {
4812        sql_bail!("{} does not allow subqueries", ecx.name)
4813    }
4814
4815    let mut qcx = ecx.derived_query_context();
4816    let mut planned_query = plan_query(&mut qcx, query)?;
4817    if planned_query.limit.is_some()
4818        || !planned_query
4819            .offset
4820            .clone()
4821            .try_into_literal_int64()
4822            .is_ok_and(|offset| offset == 0)
4823    {
4824        planned_query.expr = HirRelationExpr::top_k(
4825            planned_query.expr,
4826            vec![],
4827            planned_query.order_by.clone(),
4828            planned_query.limit,
4829            planned_query.offset,
4830            planned_query.group_size_hints.limit_input_group_size,
4831        );
4832    }
4833
4834    if planned_query.project.len() != 1 {
4835        sql_bail!(
4836            "Expected subselect to return 1 column, got {} columns",
4837            planned_query.project.len()
4838        );
4839    }
4840
4841    let project_column = *planned_query.project.get(0).unwrap();
4842    let elem_type = qcx
4843        .relation_type(&planned_query.expr)
4844        .column_types
4845        .get(project_column)
4846        .cloned()
4847        .unwrap()
4848        .scalar_type();
4849
4850    if is_unsupported_type(&elem_type) {
4851        bail_unsupported!(format!(
4852            "cannot build array from subquery because return type {}{}",
4853            ecx.humanize_sql_scalar_type(&elem_type, false),
4854            vector_type_string
4855        ));
4856    }
4857
4858    // `ColumnRef`s in `aggregation_exprs` refers to the columns produced by planning the
4859    // subquery above.
4860    let aggregation_exprs: Vec<_> = iter::once(HirScalarExpr::call_variadic(
4861        vector_create(elem_type.clone()),
4862        vec![HirScalarExpr::column(project_column)],
4863    ))
4864    .chain(
4865        planned_query
4866            .order_by
4867            .iter()
4868            .map(|co| HirScalarExpr::column(co.column)),
4869    )
4870    .collect();
4871
4872    // However, column references for `aggregation_projection` and `aggregation_order_by`
4873    // are with reference to the `exprs` of the aggregation expression.  Here that is
4874    // `aggregation_exprs`.
4875    let aggregation_projection = vec![0];
4876    let aggregation_order_by = planned_query
4877        .order_by
4878        .into_iter()
4879        .enumerate()
4880        .map(|(i, order)| ColumnOrder { column: i, ..order })
4881        .collect();
4882
4883    let reduced_expr = planned_query
4884        .expr
4885        .reduce(
4886            vec![],
4887            vec![AggregateExpr {
4888                func: aggregate_concat(aggregation_order_by),
4889                expr: Box::new(HirScalarExpr::call_variadic(
4890                    RecordCreate {
4891                        field_names: iter::repeat(ColumnName::from(""))
4892                            .take(aggregation_exprs.len())
4893                            .collect(),
4894                    },
4895                    aggregation_exprs,
4896                )),
4897                distinct: false,
4898            }],
4899            None,
4900        )
4901        .project(aggregation_projection);
4902
4903    // If `expr` has no rows, return an empty array/list rather than NULL.
4904    Ok(reduced_expr
4905        .select()
4906        .call_binary(empty_literal(elem_type), binary_concat)
4907        .into())
4908}
4909
4910fn plan_map_subquery(
4911    ecx: &ExprContext,
4912    query: &Query<Aug>,
4913) -> Result<CoercibleScalarExpr, PlanError> {
4914    if !ecx.allow_subqueries {
4915        sql_bail!("{} does not allow subqueries", ecx.name)
4916    }
4917
4918    let mut qcx = ecx.derived_query_context();
4919    let mut query = plan_query(&mut qcx, query)?;
4920    if query.limit.is_some()
4921        || !query
4922            .offset
4923            .clone()
4924            .try_into_literal_int64()
4925            .is_ok_and(|offset| offset == 0)
4926    {
4927        query.expr = HirRelationExpr::top_k(
4928            query.expr,
4929            vec![],
4930            query.order_by.clone(),
4931            query.limit,
4932            query.offset,
4933            query.group_size_hints.limit_input_group_size,
4934        );
4935    }
4936    if query.project.len() != 2 {
4937        sql_bail!(
4938            "expected map subquery to return 2 columns, got {} columns",
4939            query.project.len()
4940        );
4941    }
4942
4943    let query_types = qcx.relation_type(&query.expr).column_types;
4944    let key_column = query.project[0];
4945    let key_type = query_types[key_column].clone().scalar_type();
4946    let value_column = query.project[1];
4947    let value_type = query_types[value_column].clone().scalar_type();
4948
4949    if key_type != SqlScalarType::String {
4950        sql_bail!("cannot build map from subquery because first column is not of type text");
4951    }
4952
4953    let aggregation_exprs: Vec<_> = iter::once(HirScalarExpr::call_variadic(
4954        RecordCreate {
4955            field_names: vec![ColumnName::from("key"), ColumnName::from("value")],
4956        },
4957        vec![
4958            HirScalarExpr::column(key_column),
4959            HirScalarExpr::column(value_column),
4960        ],
4961    ))
4962    .chain(
4963        query
4964            .order_by
4965            .iter()
4966            .map(|co| HirScalarExpr::column(co.column)),
4967    )
4968    .collect();
4969
4970    let expr = query
4971        .expr
4972        .reduce(
4973            vec![],
4974            vec![AggregateExpr {
4975                func: AggregateFunc::MapAgg {
4976                    order_by: query
4977                        .order_by
4978                        .into_iter()
4979                        .enumerate()
4980                        .map(|(i, order)| ColumnOrder { column: i, ..order })
4981                        .collect(),
4982                    value_type: value_type.clone(),
4983                },
4984                expr: Box::new(HirScalarExpr::call_variadic(
4985                    RecordCreate {
4986                        field_names: iter::repeat(ColumnName::from(""))
4987                            .take(aggregation_exprs.len())
4988                            .collect(),
4989                    },
4990                    aggregation_exprs,
4991                )),
4992                distinct: false,
4993            }],
4994            None,
4995        )
4996        .project(vec![0]);
4997
4998    // If `expr` has no rows, return an empty map rather than NULL.
4999    let expr = HirScalarExpr::call_variadic(
5000        Coalesce,
5001        vec![
5002            expr.select(),
5003            HirScalarExpr::literal(
5004                Datum::empty_map(),
5005                SqlScalarType::Map {
5006                    value_type: Box::new(value_type),
5007                    custom_id: None,
5008                },
5009            ),
5010        ],
5011    );
5012
5013    Ok(expr.into())
5014}
5015
5016fn plan_collate(
5017    ecx: &ExprContext,
5018    expr: &Expr<Aug>,
5019    collation: &UnresolvedItemName,
5020) -> Result<CoercibleScalarExpr, PlanError> {
5021    if collation.0.len() == 2
5022        && collation.0[0] == ident!(mz_repr::namespaces::PG_CATALOG_SCHEMA)
5023        && collation.0[1] == ident!("default")
5024    {
5025        plan_expr(ecx, expr)
5026    } else {
5027        bail_unsupported!("COLLATE");
5028    }
5029}
5030
5031/// Plans a slice of expressions.
5032///
5033/// This function is a simple convenience function for mapping [`plan_expr`]
5034/// over a slice of expressions. The planned expressions are returned in the
5035/// same order as the input. If any of the expressions fail to plan, returns an
5036/// error instead.
5037fn plan_exprs<E>(ecx: &ExprContext, exprs: &[E]) -> Result<Vec<CoercibleScalarExpr>, PlanError>
5038where
5039    E: std::borrow::Borrow<Expr<Aug>>,
5040{
5041    let mut out = vec![];
5042    for expr in exprs {
5043        out.push(plan_expr(ecx, expr.borrow())?);
5044    }
5045    Ok(out)
5046}
5047
5048/// Plans an `ARRAY` expression.
5049fn plan_array(
5050    ecx: &ExprContext,
5051    exprs: &[Expr<Aug>],
5052    type_hint: Option<&SqlScalarType>,
5053) -> Result<CoercibleScalarExpr, PlanError> {
5054    // Plan each element expression.
5055    let mut out = vec![];
5056    for expr in exprs {
5057        out.push(match expr {
5058            // Special case nested ARRAY expressions so we can plumb
5059            // the type hint through.
5060            Expr::Array(exprs) => plan_array(ecx, exprs, type_hint.clone())?,
5061            _ => plan_expr(ecx, expr)?,
5062        });
5063    }
5064
5065    // Attempt to make use of the type hint.
5066    let type_hint = match type_hint {
5067        // The user has provided an explicit cast to an array type. We know the
5068        // element type to coerce to. Need to be careful, though: if there's
5069        // evidence that any of the array elements are themselves arrays, we
5070        // want to coerce to the array type, not the element type.
5071        Some(SqlScalarType::Array(elem_type)) => {
5072            let multidimensional = out.iter().any(|e| {
5073                matches!(
5074                    ecx.scalar_type(e),
5075                    CoercibleScalarType::Coerced(SqlScalarType::Array(_))
5076                )
5077            });
5078            if multidimensional {
5079                type_hint
5080            } else {
5081                Some(&**elem_type)
5082            }
5083        }
5084        // The user provided an explicit cast to a non-array type. We'll have to
5085        // guess what the correct type for the array. Our caller will then
5086        // handle converting that array type to the desired non-array type.
5087        Some(_) => None,
5088        // No type hint. We'll have to guess the correct type for the array.
5089        None => None,
5090    };
5091
5092    // Coerce all elements to the same type.
5093    let (elem_type, exprs) = if exprs.is_empty() {
5094        if let Some(elem_type) = type_hint {
5095            (elem_type.clone(), vec![])
5096        } else {
5097            sql_bail!("cannot determine type of empty array");
5098        }
5099    } else {
5100        let out = coerce_homogeneous_exprs(&ecx.with_name("ARRAY"), out, type_hint)?;
5101        (ecx.scalar_type(&out[0]), out)
5102    };
5103
5104    // Arrays of `char` type are disallowed due to a known limitation:
5105    // https://github.com/MaterializeInc/database-issues/issues/2360.
5106    //
5107    // Arrays of `list` and `map` types are disallowed due to mind-bending
5108    // semantics.
5109    if matches!(
5110        elem_type,
5111        SqlScalarType::Char { .. } | SqlScalarType::List { .. } | SqlScalarType::Map { .. }
5112    ) {
5113        bail_unsupported!(format!(
5114            "{}[]",
5115            ecx.humanize_sql_scalar_type(&elem_type, false)
5116        ));
5117    }
5118
5119    Ok(HirScalarExpr::call_variadic(ArrayCreate { elem_type }, exprs).into())
5120}
5121
5122fn plan_list(
5123    ecx: &ExprContext,
5124    exprs: &[Expr<Aug>],
5125    type_hint: Option<&SqlScalarType>,
5126) -> Result<CoercibleScalarExpr, PlanError> {
5127    let (elem_type, exprs) = if exprs.is_empty() {
5128        if let Some(SqlScalarType::List { element_type, .. }) = type_hint {
5129            (element_type.without_modifiers(), vec![])
5130        } else {
5131            sql_bail!("cannot determine type of empty list");
5132        }
5133    } else {
5134        let type_hint = match type_hint {
5135            Some(SqlScalarType::List { element_type, .. }) => Some(&**element_type),
5136            _ => None,
5137        };
5138
5139        let mut out = vec![];
5140        for expr in exprs {
5141            out.push(match expr {
5142                // Special case nested LIST expressions so we can plumb
5143                // the type hint through.
5144                Expr::List(exprs) => plan_list(ecx, exprs, type_hint)?,
5145                _ => plan_expr(ecx, expr)?,
5146            });
5147        }
5148        let out = coerce_homogeneous_exprs(&ecx.with_name("LIST"), out, type_hint)?;
5149        (ecx.scalar_type(&out[0]).without_modifiers(), out)
5150    };
5151
5152    if matches!(elem_type, SqlScalarType::Char { .. }) {
5153        bail_unsupported!("char list");
5154    }
5155
5156    Ok(HirScalarExpr::call_variadic(ListCreate { elem_type }, exprs).into())
5157}
5158
5159fn plan_map(
5160    ecx: &ExprContext,
5161    entries: &[MapEntry<Aug>],
5162    type_hint: Option<&SqlScalarType>,
5163) -> Result<CoercibleScalarExpr, PlanError> {
5164    let (value_type, exprs) = if entries.is_empty() {
5165        if let Some(SqlScalarType::Map { value_type, .. }) = type_hint {
5166            (value_type.without_modifiers(), vec![])
5167        } else {
5168            sql_bail!("cannot determine type of empty map");
5169        }
5170    } else {
5171        let type_hint = match type_hint {
5172            Some(SqlScalarType::Map { value_type, .. }) => Some(&**value_type),
5173            _ => None,
5174        };
5175
5176        let mut keys = vec![];
5177        let mut values = vec![];
5178        for MapEntry { key, value } in entries {
5179            let key = plan_expr(ecx, key)?.type_as(ecx, &SqlScalarType::String)?;
5180            let value = match value {
5181                // Special case nested MAP expressions so we can plumb
5182                // the type hint through.
5183                Expr::Map(entries) => plan_map(ecx, entries, type_hint)?,
5184                _ => plan_expr(ecx, value)?,
5185            };
5186            keys.push(key);
5187            values.push(value);
5188        }
5189        let values = coerce_homogeneous_exprs(&ecx.with_name("MAP"), values, type_hint)?;
5190        let value_type = ecx.scalar_type(&values[0]).without_modifiers();
5191        let out = itertools::interleave(keys, values).collect();
5192        (value_type, out)
5193    };
5194
5195    if matches!(value_type, SqlScalarType::Char { .. }) {
5196        bail_unsupported!("char map");
5197    }
5198
5199    let expr = HirScalarExpr::call_variadic(MapBuild { value_type }, exprs);
5200    Ok(expr.into())
5201}
5202
5203/// Coerces a list of expressions such that all input expressions will be cast
5204/// to the same type. If successful, returns a new list of expressions in the
5205/// same order as the input, where each expression has the appropriate casts to
5206/// make them all of a uniform type.
5207///
5208/// If `force_type` is `Some`, the expressions are forced to the specified type
5209/// via an explicit cast. Otherwise the best common type is guessed via
5210/// [`typeconv::guess_best_common_type`] and conversions are attempted via
5211/// implicit casts
5212///
5213/// Note that this is our implementation of Postgres' type conversion for
5214/// ["`UNION`, `CASE`, and Related Constructs"][union-type-conv], though it
5215/// isn't yet used in all of those cases.
5216///
5217/// [union-type-conv]:
5218/// https://www.postgresql.org/docs/12/typeconv-union-case.html
5219pub fn coerce_homogeneous_exprs(
5220    ecx: &ExprContext,
5221    exprs: Vec<CoercibleScalarExpr>,
5222    force_type: Option<&SqlScalarType>,
5223) -> Result<Vec<HirScalarExpr>, PlanError> {
5224    assert!(!exprs.is_empty());
5225
5226    let target_holder;
5227    let target = match force_type {
5228        Some(t) => t,
5229        None => {
5230            let types: Vec<_> = exprs.iter().map(|e| ecx.scalar_type(e)).collect();
5231            target_holder = typeconv::guess_best_common_type(ecx, &types)?;
5232            &target_holder
5233        }
5234    };
5235
5236    // Try to cast all expressions to `target`.
5237    let mut out = Vec::new();
5238    for expr in exprs {
5239        let arg = typeconv::plan_coerce(ecx, expr, target)?;
5240        let ccx = match force_type {
5241            None => CastContext::Implicit,
5242            Some(_) => CastContext::Explicit,
5243        };
5244        match typeconv::plan_cast(ecx, ccx, arg.clone(), target) {
5245            Ok(expr) => out.push(expr),
5246            Err(_) => sql_bail!(
5247                "{} could not convert type {} to {}",
5248                ecx.name,
5249                ecx.humanize_sql_scalar_type(&ecx.scalar_type(&arg), false),
5250                ecx.humanize_sql_scalar_type(target, false),
5251            ),
5252        }
5253    }
5254    Ok(out)
5255}
5256
5257/// Creates a `ColumnOrder` from an `OrderByExpr` and column index.
5258/// Column index is specified by the caller, but `desc` and `nulls_last` is figured out here.
5259pub(crate) fn resolve_desc_and_nulls_last<T: AstInfo>(
5260    obe: &OrderByExpr<T>,
5261    column: usize,
5262) -> ColumnOrder {
5263    let desc = !obe.asc.unwrap_or(true);
5264    ColumnOrder {
5265        column,
5266        desc,
5267        // https://www.postgresql.org/docs/14/queries-order.html
5268        //   "NULLS FIRST is the default for DESC order, and NULLS LAST otherwise"
5269        nulls_last: obe.nulls_last.unwrap_or(!desc),
5270    }
5271}
5272
5273/// Plans the ORDER BY clause of a window function.
5274///
5275/// Unfortunately, we have to create two HIR structs from an AST OrderByExpr:
5276/// A ColumnOrder has asc/desc and nulls first/last, but can't represent an HirScalarExpr, just
5277/// a column reference by index. Therefore, we return both HirScalarExprs and ColumnOrders.
5278/// Note that the column references in the ColumnOrders point NOT to input columns, but into the
5279/// `Vec<HirScalarExpr>` that we return.
5280fn plan_function_order_by(
5281    ecx: &ExprContext,
5282    order_by: &[OrderByExpr<Aug>],
5283) -> Result<(Vec<HirScalarExpr>, Vec<ColumnOrder>), PlanError> {
5284    let mut order_by_exprs = vec![];
5285    let mut col_orders = vec![];
5286    {
5287        for (i, obe) in order_by.iter().enumerate() {
5288            // Unlike `SELECT ... ORDER BY` clauses, function `ORDER BY` clauses
5289            // do not support ordinal references in PostgreSQL. So we use
5290            // `plan_expr` directly rather than `plan_order_by_or_distinct_expr`.
5291            let expr = plan_expr(ecx, &obe.expr)?.type_as_any(ecx)?;
5292            order_by_exprs.push(expr);
5293            col_orders.push(resolve_desc_and_nulls_last(obe, i));
5294        }
5295    }
5296    Ok((order_by_exprs, col_orders))
5297}
5298
5299/// Returns a human-readable rendering of `name`, falling back to a debug
5300/// dump of the `ResolvedItemName` if humanization fails. Used to construct
5301/// user-facing error messages on already-failing paths, where we'd rather
5302/// surface the raw resolved name than emit a useless `<unknown>` placeholder.
5303fn humanize_or_debug(scx: &StatementContext, name: &ResolvedItemName) -> String {
5304    scx.humanize_resolved_name(name)
5305        .map(|n| n.to_string())
5306        .unwrap_or_else(|_| format!("<error when trying to humanize `{name:?}`>"))
5307}
5308
5309/// Common part of the planning of windowed and non-windowed aggregation functions.
5310fn plan_aggregate_common(
5311    ecx: &ExprContext,
5312    Function::<Aug> {
5313        name,
5314        args,
5315        filter,
5316        over: _,
5317        distinct,
5318    }: &Function<Aug>,
5319) -> Result<AggregateExpr, PlanError> {
5320    // Normal aggregate functions, like `sum`, expect as input a single expression
5321    // which yields the datum to aggregate. Order sensitive aggregate functions,
5322    // like `jsonb_agg`, are special, and instead expect a Record whose first
5323    // element yields the datum to aggregate and whose successive elements yield
5324    // keys to order by. This expectation is hard coded within the implementation
5325    // of each of the order-sensitive aggregates. The specification of how many
5326    // order by keys to consider, and in what order, is passed via the `order_by`
5327    // field on the `AggregateFunc` variant.
5328
5329    // While all aggregate functions support the ORDER BY syntax, it's a no-op for
5330    // most, so explicitly drop it if the function doesn't care about order. This
5331    // prevents the projection into Record below from triggering on unsupported
5332    // functions.
5333
5334    let impls = match resolve_func(ecx, name, args)? {
5335        Func::Aggregate(impls) => impls,
5336        _ => bail_internal!("plan_aggregate_common called on non-aggregate function"),
5337    };
5338
5339    // We follow PostgreSQL's rule here for mapping `count(*)` into the
5340    // generalized function selection framework. The rule is simple: the user
5341    // must type `count(*)`, but the function selection framework sees an empty
5342    // parameter list, as if the user had typed `count()`. But if the user types
5343    // `count()` directly, that is an error. Like PostgreSQL, we apply these
5344    // rules to all aggregates, not just `count`, since we may one day support
5345    // user-defined aggregates, including user-defined aggregates that take no
5346    // parameters.
5347    let (args, order_by) = match &args {
5348        FunctionArgs::Star => (vec![], vec![]),
5349        FunctionArgs::Args { args, order_by } => {
5350            if args.is_empty() {
5351                sql_bail!(
5352                    "{}(*) must be used to call a parameterless aggregate function",
5353                    humanize_or_debug(ecx.qcx.scx, name)
5354                );
5355            }
5356            let args = plan_exprs(ecx, args)?;
5357            (args, order_by.clone())
5358        }
5359    };
5360
5361    let (order_by_exprs, col_orders) = plan_function_order_by(ecx, &order_by)?;
5362
5363    let (mut expr, func) = func::select_impl(ecx, FuncSpec::Func(name), impls, args, col_orders)?;
5364    if let Some(filter) = &filter {
5365        // If a filter is present, as in
5366        //
5367        //     <agg>(<expr>) FILTER (WHERE <cond>)
5368        //
5369        // we plan it by essentially rewriting the expression to
5370        //
5371        //     <agg>(CASE WHEN <cond> THEN <expr> ELSE <identity>)
5372        //
5373        // where <identity> is the identity input for <agg>.
5374        let cond =
5375            plan_expr(&ecx.with_name("FILTER"), filter)?.type_as(ecx, &SqlScalarType::Bool)?;
5376        let expr_typ = ecx.scalar_type(&expr);
5377        expr = HirScalarExpr::if_then_else(
5378            cond,
5379            expr,
5380            HirScalarExpr::literal(func.identity_datum(), expr_typ),
5381        );
5382    }
5383
5384    let mut seen_outer = false;
5385    let mut seen_inner = false;
5386    #[allow(deprecated)]
5387    expr.visit_columns(0, &mut |depth, col| {
5388        if depth == 0 && col.level == 0 {
5389            seen_inner = true;
5390        } else if col.level > depth {
5391            seen_outer = true;
5392        }
5393    });
5394    if seen_outer && !seen_inner {
5395        bail_unsupported!(
5396            3720,
5397            "aggregate functions that refer exclusively to outer columns"
5398        );
5399    }
5400
5401    // If a function supports ORDER BY (even if there was no ORDER BY specified),
5402    // map the needed expressions into the aggregate datum.
5403    if func.is_order_sensitive() {
5404        let field_names = iter::repeat(ColumnName::from(""))
5405            .take(1 + order_by_exprs.len())
5406            .collect();
5407        let mut exprs = vec![expr];
5408        exprs.extend(order_by_exprs);
5409        expr = HirScalarExpr::call_variadic(RecordCreate { field_names }, exprs);
5410    }
5411
5412    Ok(AggregateExpr {
5413        func,
5414        expr: Box::new(expr),
5415        distinct: *distinct,
5416    })
5417}
5418
5419fn plan_identifier(ecx: &ExprContext, names: &[Ident]) -> Result<HirScalarExpr, PlanError> {
5420    let mut names = names.to_vec();
5421    // The parser guarantees that an `Expr::Identifier` is constructed with a
5422    // non-empty list of name parts, so an empty list here is an internal bug.
5423    let Some(last) = names.pop() else {
5424        bail_internal!("empty identifier");
5425    };
5426    let col_name = normalize::column_name(last);
5427
5428    // If the name is qualified, it must refer to a column in a table.
5429    if !names.is_empty() {
5430        let table_name = normalize::unresolved_item_name(UnresolvedItemName(names))?;
5431        let (i, i_name) = ecx.scope.resolve_table_column(
5432            &ecx.qcx.outer_scopes,
5433            &table_name,
5434            &col_name,
5435            &mut ecx.qcx.name_manager.borrow_mut(),
5436        )?;
5437        return Ok(HirScalarExpr::named_column(i, i_name));
5438    }
5439
5440    // If the name is unqualified, first check if it refers to a column. Track any similar names
5441    // that might exist for a better error message.
5442    let similar_names = match ecx.scope.resolve_column(
5443        &ecx.qcx.outer_scopes,
5444        &col_name,
5445        &mut ecx.qcx.name_manager.borrow_mut(),
5446    ) {
5447        Ok((i, i_name)) => {
5448            return Ok(HirScalarExpr::named_column(i, i_name));
5449        }
5450        Err(PlanError::UnknownColumn { similar, .. }) => similar,
5451        Err(e) => return Err(e),
5452    };
5453
5454    // The name doesn't refer to a column. Check if it is a whole-row reference
5455    // to a table.
5456    let items = ecx.scope.items_from_table(
5457        &ecx.qcx.outer_scopes,
5458        &PartialItemName {
5459            database: None,
5460            schema: None,
5461            item: col_name.as_str().to_owned(),
5462        },
5463    )?;
5464    match items.as_slice() {
5465        // The name doesn't refer to a table either. Return an error.
5466        [] => Err(PlanError::UnknownColumn {
5467            table: None,
5468            column: col_name,
5469            similar: similar_names,
5470        }),
5471        // The name refers to a table that is the result of a function that
5472        // returned a single column. Per PostgreSQL, this is a special case
5473        // that returns the value directly.
5474        // See: https://github.com/postgres/postgres/blob/22592e10b/src/backend/parser/parse_expr.c#L2519-L2524
5475        [(column, item)] if item.from_single_column_function => Ok(HirScalarExpr::named_column(
5476            *column,
5477            ecx.qcx.name_manager.borrow_mut().intern_scope_item(item),
5478        )),
5479        // The name refers to a normal table. Return a record containing all the
5480        // columns of the table.
5481        _ => {
5482            let mut has_exists_column = None;
5483            let (exprs, field_names): (Vec<_>, Vec<_>) = items
5484                .into_iter()
5485                .filter_map(|(column, item)| {
5486                    if item.is_exists_column_for_a_table_function_that_was_in_the_target_list {
5487                        has_exists_column = Some(column);
5488                        None
5489                    } else {
5490                        let expr = HirScalarExpr::named_column(
5491                            column,
5492                            ecx.qcx.name_manager.borrow_mut().intern_scope_item(item),
5493                        );
5494                        let name = item.column_name.clone();
5495                        Some((expr, name))
5496                    }
5497                })
5498                .unzip();
5499            // For the special case of a table function with a single column, the single column is instead not wrapped.
5500            let expr = if exprs.len() == 1 && has_exists_column.is_some() {
5501                exprs.into_element()
5502            } else {
5503                HirScalarExpr::call_variadic(RecordCreate { field_names }, exprs)
5504            };
5505            if let Some(has_exists_column) = has_exists_column {
5506                Ok(HirScalarExpr::if_then_else(
5507                    HirScalarExpr::unnamed_column(has_exists_column)
5508                        .call_unary(UnaryFunc::IsNull(mz_expr::func::IsNull)),
5509                    HirScalarExpr::literal_null(ecx.scalar_type(&expr)),
5510                    expr,
5511                ))
5512            } else {
5513                Ok(expr)
5514            }
5515        }
5516    }
5517}
5518
5519fn plan_op(
5520    ecx: &ExprContext,
5521    op: &str,
5522    expr1: &Expr<Aug>,
5523    expr2: Option<&Expr<Aug>>,
5524) -> Result<HirScalarExpr, PlanError> {
5525    let impls = func::resolve_op(op)?;
5526    let args = match expr2 {
5527        None => plan_exprs(ecx, &[expr1])?,
5528        Some(expr2) => plan_exprs(ecx, &[expr1, expr2])?,
5529    };
5530    func::select_impl(ecx, FuncSpec::Op(op), impls, args, vec![])
5531}
5532
5533fn plan_function<'a>(
5534    ecx: &ExprContext,
5535    f @ Function {
5536        name,
5537        args,
5538        filter,
5539        over,
5540        distinct,
5541    }: &'a Function<Aug>,
5542) -> Result<HirScalarExpr, PlanError> {
5543    let impls = match resolve_func(ecx, name, args)? {
5544        Func::Table(_) => {
5545            sql_bail!(
5546                "table functions are not allowed in {} (function {})",
5547                ecx.name,
5548                name
5549            );
5550        }
5551        Func::Scalar(impls) => {
5552            if over.is_some() {
5553                sql_bail!(
5554                    "OVER clause not allowed on {name}. The OVER clause can only be used with window functions (including aggregations)."
5555                );
5556            }
5557            impls
5558        }
5559        Func::ScalarWindow(impls) => {
5560            let (
5561                ignore_nulls,
5562                order_by_exprs,
5563                col_orders,
5564                _window_frame,
5565                partition_by,
5566                scalar_args,
5567            ) = plan_window_function_non_aggr(ecx, f)?;
5568
5569            // All scalar window functions have 0 parameters. Let's print a nice error msg if the
5570            // user gave some args. (The below `func::select_impl` would fail anyway, but the error
5571            // msg there is less informative.)
5572            if !scalar_args.is_empty() {
5573                if let ResolvedItemName::Item {
5574                    full_name: FullItemName { item, .. },
5575                    ..
5576                } = name
5577                {
5578                    sql_bail!(
5579                        "function {} has 0 parameters, but was called with {}",
5580                        item,
5581                        scalar_args.len()
5582                    );
5583                }
5584            }
5585
5586            // Note: the window frame doesn't affect scalar window funcs, but, strangely, we should
5587            // accept a window frame here without an error msg. (Postgres also does this.)
5588            // TODO: maybe we should give a notice
5589
5590            let func = func::select_impl(ecx, FuncSpec::Func(name), impls, scalar_args, vec![])?;
5591
5592            if ignore_nulls {
5593                // If we ever add a scalar window function that supports ignore, then don't forget
5594                // to also update HIR EXPLAIN.
5595                bail_unsupported!(IGNORE_NULLS_ERROR_MSG);
5596            }
5597
5598            return Ok(HirScalarExpr::windowing(WindowExpr {
5599                func: WindowExprType::Scalar(ScalarWindowExpr {
5600                    func,
5601                    order_by: col_orders,
5602                }),
5603                partition_by,
5604                order_by: order_by_exprs,
5605            }));
5606        }
5607        Func::ValueWindow(impls) => {
5608            let window_plan = plan_window_function_non_aggr(ecx, f)?;
5609            let (ignore_nulls, order_by_exprs, col_orders, window_frame, partition_by, win_args) =
5610                window_plan;
5611
5612            let (args_encoded, func) =
5613                func::select_impl(ecx, FuncSpec::Func(name), impls, win_args, vec![])?;
5614
5615            if ignore_nulls {
5616                match func {
5617                    ValueWindowFunc::Lag | ValueWindowFunc::Lead => {}
5618                    _ => bail_unsupported!(IGNORE_NULLS_ERROR_MSG),
5619                }
5620            }
5621
5622            return Ok(HirScalarExpr::windowing(WindowExpr {
5623                func: WindowExprType::Value(ValueWindowExpr {
5624                    func,
5625                    args: Box::new(args_encoded),
5626                    order_by: col_orders,
5627                    window_frame,
5628                    ignore_nulls, // (RESPECT NULLS is the default)
5629                }),
5630                partition_by,
5631                order_by: order_by_exprs,
5632            }));
5633        }
5634        Func::Aggregate(_) => {
5635            if f.over.is_none() {
5636                // Not a window aggregate. Something is wrong.
5637                if ecx.allow_aggregates {
5638                    // Should already have been caught by `scope.resolve_expr` in `plan_expr_inner`
5639                    // (after having been planned earlier in `Step 5` of `plan_select_from_where`).
5640                    sql_bail!(
5641                        "Internal error: encountered unplanned non-windowed aggregate function: {:?}",
5642                        name,
5643                    );
5644                } else {
5645                    // scope.resolve_expr didn't catch it because we have not yet planned it,
5646                    // because it was in an unsupported context.
5647                    sql_bail!(
5648                        "aggregate functions are not allowed in {} (function {})",
5649                        ecx.name,
5650                        name
5651                    );
5652                }
5653            } else {
5654                let (ignore_nulls, order_by_exprs, col_orders, window_frame, partition_by) =
5655                    plan_window_function_common(ecx, &f.name, &f.over)?;
5656
5657                // https://github.com/MaterializeInc/database-issues/issues/6720
5658                match (&window_frame.start_bound, &window_frame.end_bound) {
5659                    (
5660                        mz_expr::WindowFrameBound::UnboundedPreceding,
5661                        mz_expr::WindowFrameBound::OffsetPreceding(..),
5662                    )
5663                    | (
5664                        mz_expr::WindowFrameBound::UnboundedPreceding,
5665                        mz_expr::WindowFrameBound::OffsetFollowing(..),
5666                    )
5667                    | (
5668                        mz_expr::WindowFrameBound::OffsetPreceding(..),
5669                        mz_expr::WindowFrameBound::UnboundedFollowing,
5670                    )
5671                    | (
5672                        mz_expr::WindowFrameBound::OffsetFollowing(..),
5673                        mz_expr::WindowFrameBound::UnboundedFollowing,
5674                    ) => bail_unsupported!("mixed unbounded - offset frames"),
5675                    (_, _) => {} // other cases are ok
5676                }
5677
5678                if ignore_nulls {
5679                    // https://github.com/MaterializeInc/database-issues/issues/6722
5680                    // If we ever add support for ignore_nulls for a window aggregate, then don't
5681                    // forget to also update HIR EXPLAIN.
5682                    bail_unsupported!(IGNORE_NULLS_ERROR_MSG);
5683                }
5684
5685                let aggregate_expr = plan_aggregate_common(ecx, f)?;
5686
5687                if aggregate_expr.distinct {
5688                    // https://github.com/MaterializeInc/database-issues/issues/6626
5689                    bail_unsupported!("DISTINCT in window aggregates");
5690                }
5691
5692                return Ok(HirScalarExpr::windowing(WindowExpr {
5693                    func: WindowExprType::Aggregate(AggregateWindowExpr {
5694                        aggregate_expr,
5695                        order_by: col_orders,
5696                        window_frame,
5697                    }),
5698                    partition_by,
5699                    order_by: order_by_exprs,
5700                }));
5701            }
5702        }
5703    };
5704
5705    if over.is_some() {
5706        bail_internal!("OVER clause should have been handled by the window function path above");
5707    }
5708
5709    if *distinct {
5710        sql_bail!(
5711            "DISTINCT specified, but {} is not an aggregate function",
5712            humanize_or_debug(ecx.qcx.scx, name)
5713        );
5714    }
5715    if filter.is_some() {
5716        sql_bail!(
5717            "FILTER specified, but {} is not an aggregate function",
5718            humanize_or_debug(ecx.qcx.scx, name)
5719        );
5720    }
5721
5722    let scalar_args = match &args {
5723        FunctionArgs::Star => {
5724            sql_bail!(
5725                "* argument is invalid with non-aggregate function {}",
5726                humanize_or_debug(ecx.qcx.scx, name)
5727            )
5728        }
5729        FunctionArgs::Args { args, order_by } => {
5730            if !order_by.is_empty() {
5731                sql_bail!(
5732                    "ORDER BY specified, but {} is not an aggregate function",
5733                    humanize_or_debug(ecx.qcx.scx, name)
5734                );
5735            }
5736            plan_exprs(ecx, args)?
5737        }
5738    };
5739
5740    func::select_impl(ecx, FuncSpec::Func(name), impls, scalar_args, vec![])
5741}
5742
5743pub const IGNORE_NULLS_ERROR_MSG: &str =
5744    "IGNORE NULLS and RESPECT NULLS options for functions other than LAG and LEAD";
5745
5746/// Resolves the name to a set of function implementations.
5747///
5748/// If the name does not specify a known built-in function, returns an error.
5749pub fn resolve_func(
5750    ecx: &ExprContext,
5751    name: &ResolvedItemName,
5752    args: &mz_sql_parser::ast::FunctionArgs<Aug>,
5753) -> Result<&'static Func, PlanError> {
5754    if let Ok(i) = ecx.qcx.scx.get_item_by_resolved_name(name) {
5755        if let Ok(f) = i.func() {
5756            return Ok(f);
5757        }
5758    }
5759
5760    // Couldn't resolve function with this name, so generate verbose error
5761    // message.
5762    let cexprs = match args {
5763        mz_sql_parser::ast::FunctionArgs::Star => vec![],
5764        mz_sql_parser::ast::FunctionArgs::Args { args, order_by } => {
5765            if !order_by.is_empty() {
5766                sql_bail!(
5767                    "ORDER BY specified, but {} is not an aggregate function",
5768                    name
5769                );
5770            }
5771            plan_exprs(ecx, args)?
5772        }
5773    };
5774
5775    let arg_types: Vec<_> = cexprs
5776        .into_iter()
5777        .map(|ty| match ecx.scalar_type(&ty) {
5778            CoercibleScalarType::Coerced(ty) => ecx.humanize_sql_scalar_type(&ty, false),
5779            CoercibleScalarType::Record(_) => "record".to_string(),
5780            CoercibleScalarType::Uncoerced => "unknown".to_string(),
5781        })
5782        .collect();
5783
5784    Err(PlanError::UnknownFunction {
5785        name: name.to_string(),
5786        arg_types,
5787    })
5788}
5789
5790fn plan_is_expr<'a>(
5791    ecx: &ExprContext,
5792    expr: &'a Expr<Aug>,
5793    construct: &IsExprConstruct<Aug>,
5794    not: bool,
5795) -> Result<HirScalarExpr, PlanError> {
5796    let expr_hir = plan_expr(ecx, expr)?;
5797
5798    let mut result = match construct {
5799        IsExprConstruct::Null => {
5800            // PostgreSQL can plan `NULL IS NULL` but not `$1 IS NULL`. This is
5801            // at odds with our type coercion rules, which treat `NULL` literals
5802            // and unconstrained parameters identically. Providing a type hint
5803            // of string means we wind up supporting both.
5804            expr_hir.type_as_any(ecx)?.call_is_null()
5805        }
5806        IsExprConstruct::Unknown => expr_hir.type_as(ecx, &SqlScalarType::Bool)?.call_is_null(),
5807        IsExprConstruct::True => expr_hir
5808            .type_as(ecx, &SqlScalarType::Bool)?
5809            .call_unary(UnaryFunc::IsTrue(expr_func::IsTrue)),
5810        IsExprConstruct::False => expr_hir
5811            .type_as(ecx, &SqlScalarType::Bool)?
5812            .call_unary(UnaryFunc::IsFalse(expr_func::IsFalse)),
5813        IsExprConstruct::DistinctFrom(expr2) => {
5814            // There are three cases:
5815            // 1. Both terms are non-null, in which case the result should be `a != b`.
5816            // 2. Exactly one term is null, in which case the result should be true.
5817            // 3. Both terms are null, in which case the result should be false.
5818            //
5819            // (a != b OR a IS NULL OR b IS NULL) AND (a IS NOT NULL OR b IS NOT NULL)
5820
5821            // We'll need `expr != expr2`, but don't just construct this HIR directly. Instead,
5822            // construct an AST expression for `expr != expr2` and plan it to get proper type
5823            // checking, implicit casts, etc. (This seems to be also what Postgres does.)
5824            let ne_ast = expr.clone().not_equals(expr2.as_ref().clone());
5825            let ne_hir = plan_expr(ecx, &ne_ast)?.type_as_any(ecx)?;
5826
5827            let expr1_hir = expr_hir.type_as_any(ecx)?;
5828            let expr2_hir = plan_expr(ecx, expr2)?.type_as_any(ecx)?;
5829
5830            let term1 = HirScalarExpr::variadic_or(vec![
5831                ne_hir,
5832                expr1_hir.clone().call_is_null(),
5833                expr2_hir.clone().call_is_null(),
5834            ]);
5835            let term2 = HirScalarExpr::variadic_or(vec![
5836                expr1_hir.call_is_null().not(),
5837                expr2_hir.call_is_null().not(),
5838            ]);
5839            term1.and(term2)
5840        }
5841    };
5842    if not {
5843        result = result.not();
5844    }
5845    Ok(result)
5846}
5847
5848fn plan_case<'a>(
5849    ecx: &ExprContext,
5850    operand: &'a Option<Box<Expr<Aug>>>,
5851    conditions: &'a [Expr<Aug>],
5852    results: &'a [Expr<Aug>],
5853    else_result: &'a Option<Box<Expr<Aug>>>,
5854) -> Result<HirScalarExpr, PlanError> {
5855    let mut cond_exprs = Vec::new();
5856    let mut result_exprs = Vec::new();
5857    for (c, r) in conditions.iter().zip_eq(results) {
5858        let c = match operand {
5859            Some(operand) => operand.clone().equals(c.clone()),
5860            None => c.clone(),
5861        };
5862        let cexpr = plan_expr(ecx, &c)?.type_as(ecx, &SqlScalarType::Bool)?;
5863        cond_exprs.push(cexpr);
5864        result_exprs.push(r);
5865    }
5866    result_exprs.push(match else_result {
5867        Some(else_result) => else_result,
5868        None => &Expr::Value(Value::Null),
5869    });
5870    let mut result_exprs = coerce_homogeneous_exprs(
5871        &ecx.with_name("CASE"),
5872        plan_exprs(ecx, &result_exprs)?,
5873        None,
5874    )?;
5875    let mut expr = result_exprs.pop().unwrap();
5876    assert_eq!(cond_exprs.len(), result_exprs.len());
5877    for (cexpr, rexpr) in cond_exprs
5878        .into_iter()
5879        .rev()
5880        .zip_eq(result_exprs.into_iter().rev())
5881    {
5882        expr = HirScalarExpr::if_then_else(cexpr, rexpr, expr);
5883    }
5884    Ok(expr)
5885}
5886
5887fn plan_literal<'a>(l: &'a Value) -> Result<CoercibleScalarExpr, PlanError> {
5888    let (datum, scalar_type) = match l {
5889        Value::Number(s) => {
5890            let d = strconv::parse_numeric(s.as_str())?;
5891            if !s.contains(&['E', '.'][..]) {
5892                // Maybe representable as an int?
5893                if let Ok(n) = d.0.try_into() {
5894                    (Datum::Int32(n), SqlScalarType::Int32)
5895                } else if let Ok(n) = d.0.try_into() {
5896                    (Datum::Int64(n), SqlScalarType::Int64)
5897                } else {
5898                    (
5899                        Datum::Numeric(d),
5900                        SqlScalarType::Numeric { max_scale: None },
5901                    )
5902                }
5903            } else {
5904                (
5905                    Datum::Numeric(d),
5906                    SqlScalarType::Numeric { max_scale: None },
5907                )
5908            }
5909        }
5910        Value::HexString(_) => bail_unsupported!("hex string literals"),
5911        Value::Boolean(b) => match b {
5912            false => (Datum::False, SqlScalarType::Bool),
5913            true => (Datum::True, SqlScalarType::Bool),
5914        },
5915        Value::Interval(i) => {
5916            let i = literal::plan_interval(i)?;
5917            (Datum::Interval(i), SqlScalarType::Interval)
5918        }
5919        Value::String(s) => return Ok(CoercibleScalarExpr::LiteralString(s.clone())),
5920        Value::Null => return Ok(CoercibleScalarExpr::LiteralNull),
5921    };
5922    let expr = HirScalarExpr::literal(datum, scalar_type);
5923    Ok(expr.into())
5924}
5925
5926/// The common part of the planning of non-aggregate window functions, i.e.,
5927/// scalar window functions and value window functions.
5928fn plan_window_function_non_aggr<'a>(
5929    ecx: &ExprContext,
5930    Function {
5931        name,
5932        args,
5933        filter,
5934        over,
5935        distinct,
5936    }: &'a Function<Aug>,
5937) -> Result<
5938    (
5939        bool,
5940        Vec<HirScalarExpr>,
5941        Vec<ColumnOrder>,
5942        mz_expr::WindowFrame,
5943        Vec<HirScalarExpr>,
5944        Vec<CoercibleScalarExpr>,
5945    ),
5946    PlanError,
5947> {
5948    let (ignore_nulls, order_by_exprs, col_orders, window_frame, partition) =
5949        plan_window_function_common(ecx, name, over)?;
5950
5951    if *distinct {
5952        sql_bail!(
5953            "DISTINCT specified, but {} is not an aggregate function",
5954            name
5955        );
5956    }
5957
5958    if filter.is_some() {
5959        bail_unsupported!("FILTER in non-aggregate window functions");
5960    }
5961
5962    let scalar_args = match &args {
5963        FunctionArgs::Star => {
5964            sql_bail!("* argument is invalid with non-aggregate function {}", name)
5965        }
5966        FunctionArgs::Args { args, order_by } => {
5967            if !order_by.is_empty() {
5968                sql_bail!(
5969                    "ORDER BY specified, but {} is not an aggregate function",
5970                    name
5971                );
5972            }
5973            plan_exprs(ecx, args)?
5974        }
5975    };
5976
5977    Ok((
5978        ignore_nulls,
5979        order_by_exprs,
5980        col_orders,
5981        window_frame,
5982        partition,
5983        scalar_args,
5984    ))
5985}
5986
5987/// The common part of the planning of all window functions.
5988fn plan_window_function_common(
5989    ecx: &ExprContext,
5990    name: &<Aug as AstInfo>::ItemName,
5991    over: &Option<WindowSpec<Aug>>,
5992) -> Result<
5993    (
5994        bool,
5995        Vec<HirScalarExpr>,
5996        Vec<ColumnOrder>,
5997        mz_expr::WindowFrame,
5998        Vec<HirScalarExpr>,
5999    ),
6000    PlanError,
6001> {
6002    if !ecx.allow_windows {
6003        sql_bail!(
6004            "window functions are not allowed in {} (function {})",
6005            ecx.name,
6006            name
6007        );
6008    }
6009
6010    let window_spec = match over.as_ref() {
6011        Some(over) => over,
6012        None => sql_bail!("window function {} requires an OVER clause", name),
6013    };
6014    if window_spec.ignore_nulls && window_spec.respect_nulls {
6015        sql_bail!("Both IGNORE NULLS and RESPECT NULLS were given.");
6016    }
6017    let window_frame = match window_spec.window_frame.as_ref() {
6018        Some(frame) => plan_window_frame(frame)?,
6019        None => mz_expr::WindowFrame::default(),
6020    };
6021    let mut partition = Vec::new();
6022    for expr in &window_spec.partition_by {
6023        partition.push(plan_expr(ecx, expr)?.type_as_any(ecx)?);
6024    }
6025
6026    let (order_by_exprs, col_orders) = plan_function_order_by(ecx, &window_spec.order_by)?;
6027
6028    Ok((
6029        window_spec.ignore_nulls,
6030        order_by_exprs,
6031        col_orders,
6032        window_frame,
6033        partition,
6034    ))
6035}
6036
6037fn plan_window_frame(
6038    WindowFrame {
6039        units,
6040        start_bound,
6041        end_bound,
6042    }: &WindowFrame,
6043) -> Result<mz_expr::WindowFrame, PlanError> {
6044    use mz_expr::WindowFrameBound::*;
6045    let units = window_frame_unit_ast_to_expr(units)?;
6046    let start_bound = window_frame_bound_ast_to_expr(start_bound);
6047    let end_bound = end_bound
6048        .as_ref()
6049        .map(window_frame_bound_ast_to_expr)
6050        .unwrap_or(CurrentRow);
6051
6052    // Validate bounds according to Postgres rules
6053    match (&start_bound, &end_bound) {
6054        // Start bound can't be UNBOUNDED FOLLOWING
6055        (UnboundedFollowing, _) => {
6056            sql_bail!("frame start cannot be UNBOUNDED FOLLOWING")
6057        }
6058        // End bound can't be UNBOUNDED PRECEDING
6059        (_, UnboundedPreceding) => {
6060            sql_bail!("frame end cannot be UNBOUNDED PRECEDING")
6061        }
6062        // Start bound should come before end bound in the list of bound definitions
6063        (CurrentRow, OffsetPreceding(_)) => {
6064            sql_bail!("frame starting from current row cannot have preceding rows")
6065        }
6066        (OffsetFollowing(_), OffsetPreceding(_) | CurrentRow) => {
6067            sql_bail!("frame starting from following row cannot have preceding rows")
6068        }
6069        // The above rules are adopted from Postgres.
6070        // The following rules are Materialize-specific.
6071        (OffsetPreceding(o1), OffsetFollowing(o2)) => {
6072            // Note that the only hard limit is that partition size + offset should fit in i64, so
6073            // in theory, we could support much larger offsets than this. But for our current
6074            // performance, even 1000000 is quite big.
6075            if *o1 > 1000000 || *o2 > 1000000 {
6076                sql_bail!("Window frame offsets greater than 1000000 are currently not supported")
6077            }
6078        }
6079        (OffsetPreceding(o1), OffsetPreceding(o2)) => {
6080            if *o1 > 1000000 || *o2 > 1000000 {
6081                sql_bail!("Window frame offsets greater than 1000000 are currently not supported")
6082            }
6083        }
6084        (OffsetFollowing(o1), OffsetFollowing(o2)) => {
6085            if *o1 > 1000000 || *o2 > 1000000 {
6086                sql_bail!("Window frame offsets greater than 1000000 are currently not supported")
6087            }
6088        }
6089        (OffsetPreceding(o), CurrentRow) => {
6090            if *o > 1000000 {
6091                sql_bail!("Window frame offsets greater than 1000000 are currently not supported")
6092            }
6093        }
6094        (CurrentRow, OffsetFollowing(o)) => {
6095            if *o > 1000000 {
6096                sql_bail!("Window frame offsets greater than 1000000 are currently not supported")
6097            }
6098        }
6099        // Other bounds are valid
6100        (_, _) => (),
6101    }
6102
6103    // RANGE is only supported in the default frame
6104    // https://github.com/MaterializeInc/database-issues/issues/6585
6105    if units == mz_expr::WindowFrameUnits::Range
6106        && (start_bound != UnboundedPreceding || end_bound != CurrentRow)
6107    {
6108        bail_unsupported!("RANGE in non-default window frames")
6109    }
6110
6111    let frame = mz_expr::WindowFrame {
6112        units,
6113        start_bound,
6114        end_bound,
6115    };
6116    Ok(frame)
6117}
6118
6119fn window_frame_unit_ast_to_expr(
6120    unit: &WindowFrameUnits,
6121) -> Result<mz_expr::WindowFrameUnits, PlanError> {
6122    match unit {
6123        WindowFrameUnits::Rows => Ok(mz_expr::WindowFrameUnits::Rows),
6124        WindowFrameUnits::Range => Ok(mz_expr::WindowFrameUnits::Range),
6125        WindowFrameUnits::Groups => bail_unsupported!("GROUPS in window frames"),
6126    }
6127}
6128
6129fn window_frame_bound_ast_to_expr(bound: &WindowFrameBound) -> mz_expr::WindowFrameBound {
6130    match bound {
6131        WindowFrameBound::CurrentRow => mz_expr::WindowFrameBound::CurrentRow,
6132        WindowFrameBound::Preceding(None) => mz_expr::WindowFrameBound::UnboundedPreceding,
6133        WindowFrameBound::Preceding(Some(offset)) => {
6134            mz_expr::WindowFrameBound::OffsetPreceding(*offset)
6135        }
6136        WindowFrameBound::Following(None) => mz_expr::WindowFrameBound::UnboundedFollowing,
6137        WindowFrameBound::Following(Some(offset)) => {
6138            mz_expr::WindowFrameBound::OffsetFollowing(*offset)
6139        }
6140    }
6141}
6142
6143pub fn scalar_type_from_sql(
6144    scx: &StatementContext,
6145    data_type: &ResolvedDataType,
6146) -> Result<SqlScalarType, PlanError> {
6147    match data_type {
6148        ResolvedDataType::AnonymousList(elem_type) => {
6149            let elem_type = scalar_type_from_sql(scx, elem_type)?;
6150            if matches!(elem_type, SqlScalarType::Char { .. }) {
6151                bail_unsupported!("char list");
6152            }
6153            Ok(SqlScalarType::List {
6154                element_type: Box::new(elem_type),
6155                custom_id: None,
6156            })
6157        }
6158        ResolvedDataType::AnonymousMap {
6159            key_type,
6160            value_type,
6161        } => {
6162            match scalar_type_from_sql(scx, key_type)? {
6163                SqlScalarType::String => {}
6164                other => sql_bail!(
6165                    "map key type must be {}, got {}",
6166                    scx.humanize_sql_scalar_type(&SqlScalarType::String, false),
6167                    scx.humanize_sql_scalar_type(&other, false)
6168                ),
6169            }
6170            Ok(SqlScalarType::Map {
6171                value_type: Box::new(scalar_type_from_sql(scx, value_type)?),
6172                custom_id: None,
6173            })
6174        }
6175        ResolvedDataType::Named { id, modifiers, .. } => {
6176            scalar_type_from_catalog(scx.catalog, *id, modifiers)
6177        }
6178        ResolvedDataType::Error => bail_internal!("should have been caught in name resolution"),
6179    }
6180}
6181
6182/// Maximum nesting depth of a custom type. A deeper type is rejected rather than
6183/// recursed into, so a long `CREATE TYPE` chain (`l0 <- l1 <- ... <- lN`) cannot
6184/// overflow the stack while resolving.
6185const MAX_TYPE_NESTING_DEPTH: usize = 128;
6186
6187/// Maximum number of sub-type resolutions performed while resolving a single
6188/// custom type. A record whose fields reference the same sub-type produces a
6189/// type tree that is exponential in its depth (fields hold owned copies, not
6190/// shared references), so bound the total work to reject such a type before it
6191/// exhausts memory / CPU rather than after.
6192const MAX_TYPE_RESOLUTION_NODES: usize = 100_000;
6193
6194pub fn scalar_type_from_catalog(
6195    catalog: &dyn SessionCatalog,
6196    id: CatalogItemId,
6197    modifiers: &[i64],
6198) -> Result<SqlScalarType, PlanError> {
6199    let (depth_limit, mut budget) = type_resolution_limits(catalog);
6200    scalar_type_from_catalog_inner(catalog, id, modifiers, 0, depth_limit, &mut budget)
6201}
6202
6203/// The `(nesting-depth, resolution-node)` limits to apply while resolving one
6204/// root custom type. See [`MAX_TYPE_NESTING_DEPTH`] and
6205/// [`MAX_TYPE_RESOLUTION_NODES`] for what each guards against.
6206///
6207/// The limits are lifted while re-planning a persisted catalog item. The
6208/// `unsafe_enable_unbounded_custom_type_resolution` flag signals this, and
6209/// `SystemVars::enable_for_item_parsing` force-enables it during bootstrap. A
6210/// type that an earlier version already accepted resolves to a finite tree, so
6211/// its persisted `create_sql` must keep re-planning after these limits were
6212/// introduced. Rejecting such a grandfathered type during rehydration would
6213/// turn a graceful planning error into a fatal bootstrap panic. A later
6214/// resolution in a normal user session still applies the limits and returns the
6215/// graceful error.
6216fn type_resolution_limits(catalog: &dyn SessionCatalog) -> (usize, usize) {
6217    if catalog
6218        .system_vars()
6219        .unsafe_enable_unbounded_custom_type_resolution()
6220    {
6221        (usize::MAX, usize::MAX)
6222    } else {
6223        (MAX_TYPE_NESTING_DEPTH, MAX_TYPE_RESOLUTION_NODES)
6224    }
6225}
6226
6227/// Bounds the total resolution work while resolving one root custom type into a
6228/// `SqlScalarType`. A single budget must span the entire root type: a record's
6229/// fields, and any containers nested within them, all draw from one shared pool.
6230/// A type that is small field-by-field but enormous in aggregate is therefore
6231/// still rejected. Resetting the budget per field would let a wide record of
6232/// individually-cheap fields resolve into an unbounded type tree and exhaust
6233/// memory, which is the denial of service this bound exists to prevent.
6234///
6235/// Use this when resolving a type that is being assembled from its parts (for
6236/// example at `CREATE TYPE` time, before the root exists in the catalog) so that
6237/// creation-time validation rejects exactly the types a later direct
6238/// [`scalar_type_from_catalog`] call would reject.
6239pub struct TypeResolutionBudget {
6240    /// Sub-type resolutions remaining before the root type is rejected as too
6241    /// complex.
6242    remaining: usize,
6243    /// Nesting depth past which the root type is rejected. Shared by every
6244    /// child so the whole root type is bounded consistently.
6245    depth_limit: usize,
6246}
6247
6248impl TypeResolutionBudget {
6249    /// Creates a budget for resolving one root type, charging the root node
6250    /// itself against the budget. Children resolved through
6251    /// [`TypeResolutionBudget::resolve_child`] begin at nesting depth one,
6252    /// mirroring a direct [`scalar_type_from_catalog`] call. The limits are
6253    /// relaxed for grandfathered persisted items, see [`type_resolution_limits`].
6254    pub fn for_root(catalog: &dyn SessionCatalog) -> TypeResolutionBudget {
6255        let (depth_limit, budget) = type_resolution_limits(catalog);
6256        TypeResolutionBudget {
6257            // The root type counts as one node.
6258            remaining: budget.saturating_sub(1),
6259            depth_limit,
6260        }
6261    }
6262
6263    /// Resolves a type referenced directly by the root (a record field, list
6264    /// element, or map value) into a `SqlScalarType`, drawing from this shared
6265    /// budget so that all such children of one root are bounded together.
6266    pub fn resolve_child(
6267        &mut self,
6268        catalog: &dyn SessionCatalog,
6269        id: CatalogItemId,
6270        modifiers: &[i64],
6271    ) -> Result<SqlScalarType, PlanError> {
6272        scalar_type_from_catalog_inner(
6273            catalog,
6274            id,
6275            modifiers,
6276            1,
6277            self.depth_limit,
6278            &mut self.remaining,
6279        )
6280    }
6281}
6282
6283fn scalar_type_from_catalog_inner(
6284    catalog: &dyn SessionCatalog,
6285    id: CatalogItemId,
6286    modifiers: &[i64],
6287    depth: usize,
6288    depth_limit: usize,
6289    budget: &mut usize,
6290) -> Result<SqlScalarType, PlanError> {
6291    if depth > depth_limit {
6292        sql_bail!("custom type nesting depth exceeds limit of {}", depth_limit);
6293    }
6294    *budget = match budget.checked_sub(1) {
6295        Some(remaining) => remaining,
6296        None => sql_bail!("custom type is too complex to resolve"),
6297    };
6298    let entry = catalog.get_item(&id);
6299    let type_details = match entry.type_details() {
6300        Some(type_details) => type_details,
6301        None => {
6302            // Resolution should never produce a `ResolvedDataType::Named` with
6303            // an ID of a non-type, but we error gracefully just in case.
6304            sql_bail!(
6305                "internal error: {} does not refer to a type",
6306                catalog.resolve_full_name(entry.name()).to_string().quoted()
6307            );
6308        }
6309    };
6310    match &type_details.typ {
6311        CatalogType::Numeric => {
6312            let mut modifiers = modifiers.iter().fuse();
6313            let precision = match modifiers.next() {
6314                Some(p) if *p < 1 || *p > i64::from(NUMERIC_DATUM_MAX_PRECISION) => {
6315                    sql_bail!(
6316                        "precision for type numeric must be between 1 and {}",
6317                        NUMERIC_DATUM_MAX_PRECISION,
6318                    );
6319                }
6320                Some(p) => Some(*p),
6321                None => None,
6322            };
6323            let scale = match modifiers.next() {
6324                Some(scale) => {
6325                    if let Some(precision) = precision {
6326                        if *scale > precision {
6327                            sql_bail!(
6328                                "scale for type numeric must be between 0 and precision {}",
6329                                precision
6330                            );
6331                        }
6332                    }
6333                    Some(NumericMaxScale::try_from(*scale)?)
6334                }
6335                None => None,
6336            };
6337            if modifiers.next().is_some() {
6338                sql_bail!("type numeric supports at most two type modifiers");
6339            }
6340            Ok(SqlScalarType::Numeric { max_scale: scale })
6341        }
6342        CatalogType::Char => {
6343            let mut modifiers = modifiers.iter().fuse();
6344            let length = match modifiers.next() {
6345                Some(l) => Some(CharLength::try_from(*l)?),
6346                None => Some(CharLength::ONE),
6347            };
6348            if modifiers.next().is_some() {
6349                sql_bail!("type character supports at most one type modifier");
6350            }
6351            Ok(SqlScalarType::Char { length })
6352        }
6353        CatalogType::VarChar => {
6354            let mut modifiers = modifiers.iter().fuse();
6355            let length = match modifiers.next() {
6356                Some(l) => Some(VarCharMaxLength::try_from(*l)?),
6357                None => None,
6358            };
6359            if modifiers.next().is_some() {
6360                sql_bail!("type character varying supports at most one type modifier");
6361            }
6362            Ok(SqlScalarType::VarChar { max_length: length })
6363        }
6364        CatalogType::Timestamp => {
6365            let mut modifiers = modifiers.iter().fuse();
6366            let precision = match modifiers.next() {
6367                Some(p) => Some(TimestampPrecision::try_from(*p)?),
6368                None => None,
6369            };
6370            if modifiers.next().is_some() {
6371                sql_bail!("type timestamp supports at most one type modifier");
6372            }
6373            Ok(SqlScalarType::Timestamp { precision })
6374        }
6375        CatalogType::TimestampTz => {
6376            let mut modifiers = modifiers.iter().fuse();
6377            let precision = match modifiers.next() {
6378                Some(p) => Some(TimestampPrecision::try_from(*p)?),
6379                None => None,
6380            };
6381            if modifiers.next().is_some() {
6382                sql_bail!("type timestamp with time zone supports at most one type modifier");
6383            }
6384            Ok(SqlScalarType::TimestampTz { precision })
6385        }
6386        t => {
6387            if !modifiers.is_empty() {
6388                sql_bail!(
6389                    "{} does not support type modifiers",
6390                    catalog.resolve_full_name(entry.name()).to_string()
6391                );
6392            }
6393            match t {
6394                CatalogType::Array {
6395                    element_reference: element_id,
6396                } => Ok(SqlScalarType::Array(Box::new(
6397                    scalar_type_from_catalog_inner(
6398                        catalog,
6399                        *element_id,
6400                        modifiers,
6401                        depth + 1,
6402                        depth_limit,
6403                        budget,
6404                    )?,
6405                ))),
6406                CatalogType::List {
6407                    element_reference: element_id,
6408                    element_modifiers,
6409                } => Ok(SqlScalarType::List {
6410                    element_type: Box::new(scalar_type_from_catalog_inner(
6411                        catalog,
6412                        *element_id,
6413                        element_modifiers,
6414                        depth + 1,
6415                        depth_limit,
6416                        budget,
6417                    )?),
6418                    custom_id: Some(id),
6419                }),
6420                CatalogType::Map {
6421                    key_reference: _,
6422                    key_modifiers: _,
6423                    value_reference: value_id,
6424                    value_modifiers,
6425                } => Ok(SqlScalarType::Map {
6426                    value_type: Box::new(scalar_type_from_catalog_inner(
6427                        catalog,
6428                        *value_id,
6429                        value_modifiers,
6430                        depth + 1,
6431                        depth_limit,
6432                        budget,
6433                    )?),
6434                    custom_id: Some(id),
6435                }),
6436                CatalogType::Range {
6437                    element_reference: element_id,
6438                } => Ok(SqlScalarType::Range {
6439                    element_type: Box::new(scalar_type_from_catalog_inner(
6440                        catalog,
6441                        *element_id,
6442                        &[],
6443                        depth + 1,
6444                        depth_limit,
6445                        budget,
6446                    )?),
6447                }),
6448                CatalogType::Record { fields } => {
6449                    let scalars: Box<[(ColumnName, SqlColumnType)]> = fields
6450                        .iter()
6451                        .map(|f| {
6452                            let scalar_type = scalar_type_from_catalog_inner(
6453                                catalog,
6454                                f.type_reference,
6455                                &f.type_modifiers,
6456                                depth + 1,
6457                                depth_limit,
6458                                budget,
6459                            )?;
6460                            Ok((
6461                                f.name.clone(),
6462                                SqlColumnType {
6463                                    scalar_type,
6464                                    nullable: true,
6465                                },
6466                            ))
6467                        })
6468                        .collect::<Result<Box<_>, PlanError>>()?;
6469                    Ok(SqlScalarType::Record {
6470                        fields: scalars,
6471                        custom_id: Some(id),
6472                    })
6473                }
6474                CatalogType::AclItem => Ok(SqlScalarType::AclItem),
6475                CatalogType::Bool => Ok(SqlScalarType::Bool),
6476                CatalogType::Bytes => Ok(SqlScalarType::Bytes),
6477                CatalogType::Date => Ok(SqlScalarType::Date),
6478                CatalogType::Float32 => Ok(SqlScalarType::Float32),
6479                CatalogType::Float64 => Ok(SqlScalarType::Float64),
6480                CatalogType::Int16 => Ok(SqlScalarType::Int16),
6481                CatalogType::Int32 => Ok(SqlScalarType::Int32),
6482                CatalogType::Int64 => Ok(SqlScalarType::Int64),
6483                CatalogType::UInt16 => Ok(SqlScalarType::UInt16),
6484                CatalogType::UInt32 => Ok(SqlScalarType::UInt32),
6485                CatalogType::UInt64 => Ok(SqlScalarType::UInt64),
6486                CatalogType::MzTimestamp => Ok(SqlScalarType::MzTimestamp),
6487                CatalogType::Interval => Ok(SqlScalarType::Interval),
6488                CatalogType::Jsonb => Ok(SqlScalarType::Jsonb),
6489                CatalogType::Oid => Ok(SqlScalarType::Oid),
6490                CatalogType::PgLegacyChar => Ok(SqlScalarType::PgLegacyChar),
6491                CatalogType::PgLegacyName => Ok(SqlScalarType::PgLegacyName),
6492                CatalogType::Pseudo => {
6493                    sql_bail!(
6494                        "cannot reference pseudo type {}",
6495                        catalog.resolve_full_name(entry.name()).to_string()
6496                    )
6497                }
6498                CatalogType::RegClass => Ok(SqlScalarType::RegClass),
6499                CatalogType::RegProc => Ok(SqlScalarType::RegProc),
6500                CatalogType::RegType => Ok(SqlScalarType::RegType),
6501                CatalogType::String => Ok(SqlScalarType::String),
6502                CatalogType::Time => Ok(SqlScalarType::Time),
6503                CatalogType::Uuid => Ok(SqlScalarType::Uuid),
6504                CatalogType::Int2Vector => Ok(SqlScalarType::Int2Vector),
6505                CatalogType::MzAclItem => Ok(SqlScalarType::MzAclItem),
6506                CatalogType::Numeric => unreachable!("handled above"),
6507                CatalogType::Char => unreachable!("handled above"),
6508                CatalogType::VarChar => unreachable!("handled above"),
6509                CatalogType::Timestamp => unreachable!("handled above"),
6510                CatalogType::TimestampTz => unreachable!("handled above"),
6511            }
6512        }
6513    }
6514}
6515
6516/// This is used to collect aggregates and table functions from within an `Expr`.
6517/// See the explanation of aggregate handling at the top of the file for more details.
6518struct AggregateTableFuncVisitor<'a> {
6519    scx: &'a StatementContext<'a>,
6520    aggs: Vec<Function<Aug>>,
6521    within_aggregate: bool,
6522    tables: BTreeMap<Function<Aug>, String>,
6523    table_disallowed_context: Vec<&'static str>,
6524    in_select_item: bool,
6525    id_gen: IdGen,
6526    err: Option<PlanError>,
6527}
6528
6529impl<'a> AggregateTableFuncVisitor<'a> {
6530    fn new(scx: &'a StatementContext<'a>) -> AggregateTableFuncVisitor<'a> {
6531        AggregateTableFuncVisitor {
6532            scx,
6533            aggs: Vec::new(),
6534            within_aggregate: false,
6535            tables: BTreeMap::new(),
6536            table_disallowed_context: Vec::new(),
6537            in_select_item: false,
6538            id_gen: Default::default(),
6539            err: None,
6540        }
6541    }
6542
6543    fn into_result(
6544        self,
6545    ) -> Result<(Vec<Function<Aug>>, BTreeMap<Function<Aug>, String>), PlanError> {
6546        match self.err {
6547            Some(err) => Err(err),
6548            None => {
6549                // Dedup while preserving the order. We don't care what the order is, but it
6550                // has to be reproducible so that EXPLAIN PLAN tests work.
6551                let mut seen = BTreeSet::new();
6552                let aggs = self
6553                    .aggs
6554                    .into_iter()
6555                    .filter(move |agg| seen.insert(agg.clone()))
6556                    .collect();
6557                Ok((aggs, self.tables))
6558            }
6559        }
6560    }
6561}
6562
6563impl<'a> VisitMut<'_, Aug> for AggregateTableFuncVisitor<'a> {
6564    fn visit_function_mut(&mut self, func: &mut Function<Aug>) {
6565        let item = match self.scx.get_item_by_resolved_name(&func.name) {
6566            Ok(i) => i,
6567            // Catching missing functions later in planning improves error messages.
6568            Err(_) => return,
6569        };
6570
6571        match item.func() {
6572            // We don't want to collect window aggregations, because these will be handled not by
6573            // plan_aggregate, but by plan_function.
6574            Ok(Func::Aggregate { .. }) if func.over.is_none() => {
6575                if self.within_aggregate {
6576                    self.err = Some(sql_err!("nested aggregate functions are not allowed",));
6577                    return;
6578                }
6579                self.aggs.push(func.clone());
6580                let Function {
6581                    name: _,
6582                    args,
6583                    filter,
6584                    over: _,
6585                    distinct: _,
6586                } = func;
6587                if let Some(filter) = filter {
6588                    self.visit_expr_mut(filter);
6589                }
6590                let old_within_aggregate = self.within_aggregate;
6591                self.within_aggregate = true;
6592                self.table_disallowed_context
6593                    .push("aggregate function calls");
6594
6595                self.visit_function_args_mut(args);
6596
6597                self.within_aggregate = old_within_aggregate;
6598                self.table_disallowed_context.pop();
6599            }
6600            Ok(Func::Table { .. }) => {
6601                self.table_disallowed_context.push("other table functions");
6602                visit_mut::visit_function_mut(self, func);
6603                self.table_disallowed_context.pop();
6604            }
6605            _ => visit_mut::visit_function_mut(self, func),
6606        }
6607    }
6608
6609    fn visit_query_mut(&mut self, _query: &mut Query<Aug>) {
6610        // Don't go into subqueries.
6611    }
6612
6613    fn visit_expr_mut(&mut self, expr: &mut Expr<Aug>) {
6614        let (disallowed_context, func) = match expr {
6615            Expr::Case { .. } => (Some("CASE"), None),
6616            Expr::HomogenizingFunction {
6617                function: HomogenizingFunction::Coalesce,
6618                ..
6619            } => (Some("COALESCE"), None),
6620            Expr::Function(func) if self.in_select_item => {
6621                // If we're in a SELECT list, replace table functions with a uuid identifier
6622                // and save the table func so it can be planned elsewhere.
6623                let mut table_func = None;
6624                if let Ok(item) = self.scx.get_item_by_resolved_name(&func.name) {
6625                    if let Ok(Func::Table { .. }) = item.func() {
6626                        if let Some(context) = self.table_disallowed_context.last() {
6627                            self.err = Some(sql_err!(
6628                                "table functions are not allowed in {} (function {})",
6629                                context,
6630                                func.name
6631                            ));
6632                            return;
6633                        }
6634                        table_func = Some(func.clone());
6635                    }
6636                }
6637                // Since we will descend into the table func below, don't add its own disallow
6638                // context here, instead use visit_function to set that.
6639                (None, table_func)
6640            }
6641            _ => (None, None),
6642        };
6643        if let Some(func) = func {
6644            // Since we are trading out expr, we need to visit the table func here.
6645            visit_mut::visit_expr_mut(self, expr);
6646            // Don't attempt to replace table functions with unsupported syntax.
6647            if let Function {
6648                name: _,
6649                args: _,
6650                filter: None,
6651                over: None,
6652                distinct: false,
6653            } = &func
6654            {
6655                // Identical table functions can be de-duplicated.
6656                let unique_id = self.id_gen.allocate_id();
6657                let id = self
6658                    .tables
6659                    .entry(func)
6660                    .or_insert_with(|| format!("table_func_{unique_id}"));
6661                // We know this is okay because id is is 11 characters + <=20 characters, which is
6662                // less than our max length.
6663                *expr = Expr::Identifier(vec![Ident::new_unchecked(id.clone())]);
6664            }
6665        }
6666        if let Some(context) = disallowed_context {
6667            self.table_disallowed_context.push(context);
6668        }
6669
6670        visit_mut::visit_expr_mut(self, expr);
6671
6672        if disallowed_context.is_some() {
6673            self.table_disallowed_context.pop();
6674        }
6675    }
6676
6677    fn visit_select_item_mut(&mut self, si: &mut SelectItem<Aug>) {
6678        let old = self.in_select_item;
6679        self.in_select_item = true;
6680        visit_mut::visit_select_item_mut(self, si);
6681        self.in_select_item = old;
6682    }
6683}
6684
6685#[derive(Default)]
6686struct WindowFuncCollector {
6687    window_funcs: Vec<Expr<Aug>>,
6688}
6689
6690impl WindowFuncCollector {
6691    fn into_result(self) -> Vec<Expr<Aug>> {
6692        // Dedup while preserving the order.
6693        let mut seen = BTreeSet::new();
6694        let window_funcs_dedupped = self
6695            .window_funcs
6696            .into_iter()
6697            .filter(move |expr| seen.insert(expr.clone()))
6698            // Reverse the order, so that in case of a nested window function call, the
6699            // inner one is evaluated first.
6700            .rev()
6701            .collect();
6702        window_funcs_dedupped
6703    }
6704}
6705
6706impl Visit<'_, Aug> for WindowFuncCollector {
6707    fn visit_expr(&mut self, expr: &Expr<Aug>) {
6708        match expr {
6709            Expr::Function(func) => {
6710                if func.over.is_some() {
6711                    self.window_funcs.push(expr.clone());
6712                }
6713            }
6714            _ => (),
6715        }
6716        visit::visit_expr(self, expr);
6717    }
6718
6719    fn visit_query(&mut self, _query: &Query<Aug>) {
6720        // Don't go into subqueries. Those will be handled by their own `plan_query`.
6721    }
6722}
6723
6724/// Specifies how long a query will live.
6725#[derive(Debug, Eq, PartialEq, Copy, Clone)]
6726pub enum QueryLifetime {
6727    /// The query's (or the expression's) result will be computed at one point in time.
6728    OneShot,
6729    /// The query (or expression) is used in a dataflow that maintains an index.
6730    Index,
6731    /// The query (or expression) is used in a dataflow that maintains a materialized view.
6732    MaterializedView,
6733    /// The query (or expression) is used in a dataflow that maintains a SUBSCRIBE.
6734    Subscribe,
6735    /// The query (or expression) is part of a (non-materialized) view.
6736    View,
6737    /// The expression is part of a source definition.
6738    Source,
6739}
6740
6741impl QueryLifetime {
6742    /// (This used to impact whether the query is allowed to reason about the time at which it is
6743    /// running, e.g., by calling the `now()` function. Nowadays, this is decided by a different
6744    /// mechanism, see `ExprPrepStyle`.)
6745    pub fn is_one_shot(&self) -> bool {
6746        let result = match self {
6747            QueryLifetime::OneShot => true,
6748            QueryLifetime::Index => false,
6749            QueryLifetime::MaterializedView => false,
6750            QueryLifetime::Subscribe => false,
6751            QueryLifetime::View => false,
6752            QueryLifetime::Source => false,
6753        };
6754        assert_eq!(!result, self.is_maintained());
6755        result
6756    }
6757
6758    /// Maintained dataflows can't have a finishing applied directly. Therefore, the finishing is
6759    /// turned into a `TopK`.
6760    pub fn is_maintained(&self) -> bool {
6761        match self {
6762            QueryLifetime::OneShot => false,
6763            QueryLifetime::Index => true,
6764            QueryLifetime::MaterializedView => true,
6765            QueryLifetime::Subscribe => true,
6766            QueryLifetime::View => true,
6767            QueryLifetime::Source => true,
6768        }
6769    }
6770
6771    /// Most maintained dataflows don't allow SHOW commands currently. However, SUBSCRIBE does.
6772    pub fn allow_show(&self) -> bool {
6773        match self {
6774            QueryLifetime::OneShot => true,
6775            QueryLifetime::Index => false,
6776            QueryLifetime::MaterializedView => false,
6777            QueryLifetime::Subscribe => true, // SUBSCRIBE allows SHOW commands!
6778            QueryLifetime::View => false,
6779            QueryLifetime::Source => false,
6780        }
6781    }
6782}
6783
6784/// Description of a CTE sufficient for query planning.
6785#[derive(Debug, Clone)]
6786pub struct CteDesc {
6787    pub name: String,
6788    pub desc: RelationDesc,
6789}
6790
6791/// The state required when planning a `Query`.
6792#[derive(Debug, Clone)]
6793pub struct QueryContext<'a> {
6794    /// The context for the containing `Statement`.
6795    pub scx: &'a StatementContext<'a>,
6796    /// The lifetime that the planned query will have.
6797    pub lifetime: QueryLifetime,
6798    /// The scopes of the outer relation expression.
6799    pub outer_scopes: Vec<Scope>,
6800    /// The type of the outer relation expressions.
6801    pub outer_relation_types: Vec<SqlRelationType>,
6802    /// CTEs for this query, mapping their assigned LocalIds to their definition.
6803    pub ctes: BTreeMap<LocalId, CteDesc>,
6804    /// A name manager, for interning column names that will be stored in HIR and MIR.
6805    pub name_manager: Rc<RefCell<NameManager>>,
6806    pub recursion_guard: RecursionGuard,
6807}
6808
6809impl CheckedRecursion for QueryContext<'_> {
6810    fn recursion_guard(&self) -> &RecursionGuard {
6811        &self.recursion_guard
6812    }
6813}
6814
6815impl<'a> QueryContext<'a> {
6816    pub fn root(scx: &'a StatementContext, lifetime: QueryLifetime) -> QueryContext<'a> {
6817        QueryContext {
6818            scx,
6819            lifetime,
6820            outer_scopes: vec![],
6821            outer_relation_types: vec![],
6822            ctes: BTreeMap::new(),
6823            name_manager: Rc::new(RefCell::new(NameManager::new())),
6824            recursion_guard: RecursionGuard::with_limit(1024), // chosen arbitrarily
6825        }
6826    }
6827
6828    fn relation_type(&self, expr: &HirRelationExpr) -> SqlRelationType {
6829        expr.typ(&self.outer_relation_types, &self.scx.param_types.borrow())
6830    }
6831
6832    /// Generate a new `QueryContext` appropriate to be used in subqueries of
6833    /// `self`.
6834    fn derived_context(&self, scope: Scope, relation_type: SqlRelationType) -> QueryContext<'a> {
6835        let ctes = self.ctes.clone();
6836        let outer_scopes = iter::once(scope).chain(self.outer_scopes.clone()).collect();
6837        let outer_relation_types = iter::once(relation_type)
6838            .chain(self.outer_relation_types.clone())
6839            .collect();
6840        // These shenanigans are simpler than adding `&mut NameManager` arguments everywhere.
6841        let name_manager = Rc::clone(&self.name_manager);
6842
6843        QueryContext {
6844            scx: self.scx,
6845            lifetime: self.lifetime,
6846            outer_scopes,
6847            outer_relation_types,
6848            ctes,
6849            name_manager,
6850            recursion_guard: self.recursion_guard.clone(),
6851        }
6852    }
6853
6854    /// Derives a `QueryContext` for a scope that contains no columns.
6855    fn empty_derived_context(&self) -> QueryContext<'a> {
6856        let scope = Scope::empty();
6857        let ty = SqlRelationType::empty();
6858        self.derived_context(scope, ty)
6859    }
6860
6861    /// Resolves `object` to a table expr, i.e. creating a `Get` or inlining a
6862    /// CTE.
6863    pub fn resolve_table_name(
6864        &self,
6865        object: ResolvedItemName,
6866    ) -> Result<(HirRelationExpr, Scope), PlanError> {
6867        match object {
6868            ResolvedItemName::Item {
6869                id,
6870                full_name,
6871                version,
6872                ..
6873            } => {
6874                let item = self.scx.get_item(&id).at_version(version);
6875                let desc = match item.relation_desc() {
6876                    Some(desc) => desc.clone(),
6877                    None => {
6878                        return Err(PlanError::InvalidDependency {
6879                            name: full_name.to_string(),
6880                            item_type: item.item_type().to_string(),
6881                        });
6882                    }
6883                };
6884                let expr = HirRelationExpr::Get {
6885                    id: Id::Global(item.global_id()),
6886                    typ: desc.typ().clone(),
6887                };
6888
6889                let name = full_name.into();
6890                let scope = Scope::from_source(Some(name), desc.iter_names().cloned());
6891
6892                Ok((expr, scope))
6893            }
6894            ResolvedItemName::Cte { id, name } => {
6895                let name = name.into();
6896                let cte = self.ctes.get(&id).unwrap();
6897                let expr = HirRelationExpr::Get {
6898                    id: Id::Local(id),
6899                    typ: cte.desc.typ().clone(),
6900                };
6901
6902                let scope = Scope::from_source(Some(name), cte.desc.iter_names());
6903
6904                Ok((expr, scope))
6905            }
6906            ResolvedItemName::Error => bail_internal!("should have been caught in name resolution"),
6907        }
6908    }
6909
6910    /// The returned String is more detailed when the `postgres_compat` flag is not set. However,
6911    /// the flag should be set in, e.g., the implementation of the `pg_typeof` function.
6912    pub fn humanize_sql_scalar_type(&self, typ: &SqlScalarType, postgres_compat: bool) -> String {
6913        self.scx.humanize_sql_scalar_type(typ, postgres_compat)
6914    }
6915}
6916
6917/// A bundle of unrelated things that we need for planning `Expr`s.
6918#[derive(Debug, Clone)]
6919pub struct ExprContext<'a> {
6920    pub qcx: &'a QueryContext<'a>,
6921    /// The name of this kind of expression eg "WHERE clause". Used only for error messages.
6922    pub name: &'a str,
6923    /// The context for the `Query` that contains this `Expr`.
6924    /// The current scope.
6925    pub scope: &'a Scope,
6926    /// The type of the current relation expression upon which this scalar
6927    /// expression will be evaluated.
6928    pub relation_type: &'a SqlRelationType,
6929    /// Are aggregate functions allowed in this context
6930    pub allow_aggregates: bool,
6931    /// Are subqueries allowed in this context
6932    pub allow_subqueries: bool,
6933    /// Are parameters allowed in this context.
6934    pub allow_parameters: bool,
6935    /// Are window functions allowed in this context
6936    pub allow_windows: bool,
6937}
6938
6939impl CheckedRecursion for ExprContext<'_> {
6940    fn recursion_guard(&self) -> &RecursionGuard {
6941        &self.qcx.recursion_guard
6942    }
6943}
6944
6945impl<'a> ExprContext<'a> {
6946    pub fn catalog(&self) -> &dyn SessionCatalog {
6947        self.qcx.scx.catalog
6948    }
6949
6950    pub fn with_name(&self, name: &'a str) -> ExprContext<'a> {
6951        let mut ecx = self.clone();
6952        ecx.name = name;
6953        ecx
6954    }
6955
6956    pub fn column_type<E>(&self, expr: &E) -> E::Type
6957    where
6958        E: AbstractExpr,
6959    {
6960        expr.typ(
6961            &self.qcx.outer_relation_types,
6962            self.relation_type,
6963            &self.qcx.scx.param_types.borrow(),
6964        )
6965    }
6966
6967    pub fn scalar_type<E>(&self, expr: &E) -> <E::Type as AbstractColumnType>::AbstractScalarType
6968    where
6969        E: AbstractExpr,
6970    {
6971        self.column_type(expr).scalar_type()
6972    }
6973
6974    fn derived_query_context(&self) -> QueryContext<'_> {
6975        let mut scope = self.scope.clone();
6976        scope.lateral_barrier = true;
6977        self.qcx.derived_context(scope, self.relation_type.clone())
6978    }
6979
6980    pub fn require_feature_flag(&self, flag: &'static FeatureFlag) -> Result<(), PlanError> {
6981        self.qcx.scx.require_feature_flag(flag)
6982    }
6983
6984    pub fn param_types(&self) -> &RefCell<BTreeMap<usize, SqlScalarType>> {
6985        &self.qcx.scx.param_types
6986    }
6987
6988    /// The returned String is more detailed when the `postgres_compat` flag is not set. However,
6989    /// the flag should be set in, e.g., the implementation of the `pg_typeof` function.
6990    pub fn humanize_sql_scalar_type(&self, typ: &SqlScalarType, postgres_compat: bool) -> String {
6991        self.qcx.scx.humanize_sql_scalar_type(typ, postgres_compat)
6992    }
6993
6994    pub fn intern(&self, item: &ScopeItem) -> Arc<str> {
6995        self.qcx.name_manager.borrow_mut().intern_scope_item(item)
6996    }
6997}
6998
6999/// Manages column names, doing lightweight string internment.
7000///
7001/// Names are stored in `HirScalarExpr` and `MirScalarExpr` using
7002/// `Option<Arc<str>>`; we use the `NameManager` when lowering from SQL to HIR
7003/// to ensure maximal sharing.
7004#[derive(Debug, Clone)]
7005pub struct NameManager(BTreeSet<Arc<str>>);
7006
7007impl NameManager {
7008    /// Creates a new `NameManager`, with no interned names
7009    pub fn new() -> Self {
7010        Self(BTreeSet::new())
7011    }
7012
7013    /// Interns a string, returning a reference-counted pointer to the interned
7014    /// string.
7015    fn intern<S: AsRef<str>>(&mut self, s: S) -> Arc<str> {
7016        let s = s.as_ref();
7017        if let Some(interned) = self.0.get(s) {
7018            Arc::clone(interned)
7019        } else {
7020            let interned: Arc<str> = Arc::from(s);
7021            self.0.insert(Arc::clone(&interned));
7022            interned
7023        }
7024    }
7025
7026    /// Interns a string representing a reference to a `ScopeItem`, returning a
7027    /// reference-counted pointer to the interned string.
7028    pub fn intern_scope_item(&mut self, item: &ScopeItem) -> Arc<str> {
7029        // TODO(mgree): extracting the table name from `item` leads to an issue with the catalog
7030        //
7031        // After an `ALTER ... RENAME` on a table, the catalog will have out-of-date
7032        // name information. Note that as of 2025-04-09, we don't support column
7033        // renames.
7034        //
7035        // A few bad alternatives:
7036        //
7037        // (1) Store it but don't write it down. This fails because the expression
7038        //     cache will erase our names on restart.
7039        // (2) When `ALTER ... RENAME` is run, re-optimize all downstream objects to
7040        //     get the right names. But the world now and the world when we made
7041        //     those objects may be different.
7042        // (3) Just don't write down the table name. Nothing fails... for now.
7043
7044        self.intern(item.column_name.as_str())
7045    }
7046}
7047
7048#[cfg(test)]
7049mod test {
7050    use super::*;
7051
7052    /// Ensure that `NameManager`'s string interning works as expected.
7053    ///
7054    /// In particular, structurally but not referentially identical strings should
7055    /// be interned to the same `Arc`ed pointer.
7056    #[mz_ore::test]
7057    pub fn test_name_manager_string_interning() {
7058        let mut nm = NameManager::new();
7059
7060        let orig_hi = "hi";
7061        let hi = nm.intern(orig_hi);
7062        let hello = nm.intern("hello");
7063
7064        assert_ne!(hi.as_ptr(), hello.as_ptr());
7065
7066        // this static string is _likely_ the same as `orig_hi``
7067        let hi2 = nm.intern("hi");
7068        assert_eq!(hi.as_ptr(), hi2.as_ptr());
7069
7070        // generate a "hi" string that doesn't get optimized to the same static string
7071        let s = format!(
7072            "{}{}",
7073            hi.chars().nth(0).unwrap(),
7074            hi2.chars().nth(1).unwrap()
7075        );
7076        // make sure that we're testing with a fresh string!
7077        assert_ne!(orig_hi.as_ptr(), s.as_ptr());
7078
7079        let hi3 = nm.intern(s);
7080        assert_eq!(hi.as_ptr(), hi3.as_ptr());
7081    }
7082}