1use 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#[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 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
184fn 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 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 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 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 let expr = match source {
304 InsertSource::Query(mut query) => {
305 transform_ast::transform(scx, &mut query)?;
306
307 match query {
308 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 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 if expr_arity < columns.len() {
344 sql_bail!("INSERT has more target columns than expressions");
345 }
346
347 source_types.truncate(expr_arity);
349 ordering.truncate(expr_arity);
350
351 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 let mut map_exprs = vec![];
364 let mut project_key = Vec::with_capacity(desc.arity());
365
366 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
437pub 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 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 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 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 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 let source_desc = if columns.is_empty() {
526 let indexes = (0..table_desc.arity()).map(ColumnIndex::from_raw);
527 ordering.extend(indexes);
528
529 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 RelationDesc::new(SqlRelationType::new(source_types), names)
560 };
561
562 Ok((item.id(), source_desc, ordering, mfp))
563}
564
565pub 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 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
610pub 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 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 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 let default: Vec<_> = (0..desc.arity()).map(ColumnIndex::from_raw).collect();
662 if columns == default {
663 return Ok(expr);
664 }
665
666 let mut map_exprs = vec![];
668 let mut project_key = Vec::with_capacity(desc.arity());
669
670 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
687pub struct ReadThenWritePlan {
689 pub id: CatalogItemId,
690 pub selection: HirRelationExpr,
695 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 let (id, version) = match table_name {
745 ResolvedItemName::Item { id, version, .. } => (id, version),
746 _ => sql_bail!("cannot mutate non-user table"),
747 };
748
749 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 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 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
841fn 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 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 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 let mut expr = plan_expr(ecx, &expr)?.type_as(ecx, &SqlScalarType::Bool)?;
905
906 let using_rel_arity = qcx.relation_type(&using_rel_expr).arity();
910 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 using_rel_expr = using_rel_expr.filter(vec![expr]);
925 } else {
926 let _joined_scope = using_scope.product(outer_scope)?;
929 }
930 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
950pub(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 match typeconv::plan_cast(ecx, ccx, expr.clone(), target_typ) {
980 Ok(cast_expr) => {
981 if expr == cast_expr {
982 project_key.push(i);
984 } else {
985 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
1002pub 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
1017pub 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 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 let timestamp = hir
1061 .into_literal_mz_timestamp()
1062 .ok_or_else(|| PlanError::InvalidAsOfUpTo)?;
1063 Ok(timestamp)
1064}
1065
1066pub 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
1093pub 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 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 let column_idx = column_typs.len() - 1;
1130 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 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 let column_idx = column_typs.len() - 1;
1161 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 let mut validation_secrets = vec![];
1172
1173 for CreateWebhookSourceSecret {
1174 secret,
1175 alias,
1176 use_bytes,
1177 } in secrets
1178 {
1179 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 let name = if let Some(alias) = alias {
1199 alias.into_string()
1200 } else {
1201 item
1202 };
1203 column_names.push(name);
1204
1205 let column_idx = column_typs.len() - 1;
1208 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
1318pub(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
1332pub(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: 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 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 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 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 let offset_value = offset_into_value(offset)?;
1493 HirScalarExpr::literal(Datum::Int64(offset_value), SqlScalarType::Int64)
1494 } else {
1495 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 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 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
1630pub(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
1652pub fn plan_ctes(
1657 qcx: &mut QueryContext,
1658 q: &Query<Aug>,
1659) -> Result<Vec<(LocalId, HirRelationExpr, Option<CteDesc>)>, PlanError> {
1660 let mut result = Vec::new();
1662 let mut shadowed_descs = BTreeMap::new();
1665
1666 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 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 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 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 if let Some(shadowed) = shadowed {
1723 shadowed_descs.insert(cte.id, shadowed);
1724 }
1725 }
1726
1727 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 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 sql_bail!("[internal error]: WMR CTEs do not support keys");
1745 }
1746
1747 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 let val = match cast_relation(
1775 qcx,
1776 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 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 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 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 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 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 let (lhs, rhs) = if lhs.relation_node_count() > rhs.relation_node_count() {
1979 (rhs, lhs)
1980 } else {
1981 (lhs, rhs)
1982 };
1983 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 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 if !qcx.lifetime.allow_show() {
2031 return Err(PlanError::ShowCommandInView);
2032 }
2033
2034 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
2099fn 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 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 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))?; }
2145 col_types.push(col_type);
2146 col_iters.push(col.into_iter());
2147 }
2148
2149 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 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
2174fn 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))?; }
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#[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
2272fn 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 let select_option_extracted = SelectOptionExtracted::try_from(s.options.clone())?;
2301 let group_size_hints = GroupSizeHints::try_from(select_option_extracted)?;
2302
2303 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 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 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 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 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 let (mut group_scope, select_all_mapping) = {
2400 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 if let Some(existing_scope_item) = group_exprs.get_mut(&expr) {
2432 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 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 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 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 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 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 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 (
2564 from_scope.clone(),
2565 (0..from_scope.len()).map(|i| (i, i)).collect(),
2566 )
2567 }
2568 };
2569
2570 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 let window_funcs = {
2599 let mut visitor = WindowFuncCollector::default();
2600 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 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 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 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 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 output_columns.push((column, column_name));
2692 } else {
2693 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 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 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 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 let arity = relation_type.arity();
2795 for ord in order_by.iter().take(distinct_exprs.len()) {
2796 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 for expr in distinct_exprs {
2815 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 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 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 Ident::new_unchecked(table_func.name.full_item_name().item.clone()),
2877 );
2878 }
2879 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 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 bail_unsupported!(format!(
2903 "{} in a SELECT clause with multiple table functions",
2904 REPEAT_ROW_NAME
2905 ));
2906 }
2907 let (expr, mut scope, num_cols) =
2909 plan_rows_from_internal(&rows_from_qcx, table_funcs.keys(), None)?;
2910
2911 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 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 scope.items[i].allow_unqualified_references = false;
2938 Ok((expr, scope))
2939}
2940
2941fn 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 if let Some(column) = check_col_index(ecx.name, group_expr, projection.len())? {
2962 return plan_projection(column);
2963 }
2964
2965 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 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 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
3003pub(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 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
3033fn 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 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 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
3145fn plan_rows_from(
3187 qcx: &QueryContext,
3188 functions: &[Function<Aug>],
3189 alias: Option<&TableAlias>,
3190 with_ordinality: bool,
3191) -> Result<(HirRelationExpr, Scope), PlanError> {
3192 if functions.iter().any(is_repeat_row) {
3194 bail_unsupported!(format!("{} in ROWS FROM", REPEAT_ROW_NAME));
3198 }
3199
3200 if let [function] = functions {
3203 return plan_solitary_table_function(qcx, function, alias, with_ordinality);
3204 }
3205
3206 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 let mut columns = Vec::new();
3217 let mut offset = 0;
3218 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 scope.items.remove(offset - idx - 1);
3228 }
3229
3230 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
3248fn 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 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 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 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 left_expr = left_expr.project(
3316 (0..left_col) .chain(left_col + 1..right_col + 2) .collect(),
3319 );
3320 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
3329fn 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 item.from_single_column_function = true;
3347
3348 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
3380fn 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 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 if qcx
3469 .scx
3470 .is_feature_flag_enabled(&ENABLE_WITH_ORDINALITY_LEGACY_FALLBACK)
3471 {
3472 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 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
3613fn invent_column_name(
3617 ecx: &ExprContext,
3618 expr: &Expr<Aug>,
3619 table_func_names: &BTreeMap<String, Ident>,
3620) -> Result<Option<ColumnName>, PlanError> {
3621 #[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 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 _ => {
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 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 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 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 *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#[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 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 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 rhs.column += left_scope.len();
4046
4047 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 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 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 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 for c in hidden_cols {
4130 both_scope.items[c].allow_unqualified_references = false;
4131 }
4132
4133 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 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 Expr::Identifier(names) | Expr::QualifiedWildcard(names) => {
4174 Ok(plan_identifier(ecx, names)?.into())
4175 }
4176
4177 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 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 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 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 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 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()); 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 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 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
4471fn 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 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 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 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 let mut exprs = Vec::with_capacity(slices.len() + 1);
4617 exprs.push(expr);
4618 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 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 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 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
4794fn 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 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 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 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 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
5031fn 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
5048fn plan_array(
5050 ecx: &ExprContext,
5051 exprs: &[Expr<Aug>],
5052 type_hint: Option<&SqlScalarType>,
5053) -> Result<CoercibleScalarExpr, PlanError> {
5054 let mut out = vec![];
5056 for expr in exprs {
5057 out.push(match expr {
5058 Expr::Array(exprs) => plan_array(ecx, exprs, type_hint.clone())?,
5061 _ => plan_expr(ecx, expr)?,
5062 });
5063 }
5064
5065 let type_hint = match type_hint {
5067 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 Some(_) => None,
5088 None => None,
5090 };
5091
5092 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 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 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 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
5203pub 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 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
5257pub(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 nulls_last: obe.nulls_last.unwrap_or(!desc),
5270 }
5271}
5272
5273fn 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 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
5299fn 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
5309fn 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 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 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 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 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 let Some(last) = names.pop() else {
5424 bail_internal!("empty identifier");
5425 };
5426 let col_name = normalize::column_name(last);
5427
5428 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 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 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 [] => Err(PlanError::UnknownColumn {
5467 table: None,
5468 column: col_name,
5469 similar: similar_names,
5470 }),
5471 [(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 _ => {
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 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 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 let func = func::select_impl(ecx, FuncSpec::Func(name), impls, scalar_args, vec![])?;
5591
5592 if ignore_nulls {
5593 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, }),
5630 partition_by,
5631 order_by: order_by_exprs,
5632 }));
5633 }
5634 Func::Aggregate(_) => {
5635 if f.over.is_none() {
5636 if ecx.allow_aggregates {
5638 sql_bail!(
5641 "Internal error: encountered unplanned non-windowed aggregate function: {:?}",
5642 name,
5643 );
5644 } else {
5645 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 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 (_, _) => {} }
5677
5678 if ignore_nulls {
5679 bail_unsupported!(IGNORE_NULLS_ERROR_MSG);
5683 }
5684
5685 let aggregate_expr = plan_aggregate_common(ecx, f)?;
5686
5687 if aggregate_expr.distinct {
5688 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
5746pub 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 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 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 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 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
5926fn 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
5987fn 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 match (&start_bound, &end_bound) {
6054 (UnboundedFollowing, _) => {
6056 sql_bail!("frame start cannot be UNBOUNDED FOLLOWING")
6057 }
6058 (_, UnboundedPreceding) => {
6060 sql_bail!("frame end cannot be UNBOUNDED PRECEDING")
6061 }
6062 (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 (OffsetPreceding(o1), OffsetFollowing(o2)) => {
6072 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 (_, _) => (),
6101 }
6102
6103 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
6182const MAX_TYPE_NESTING_DEPTH: usize = 128;
6186
6187const 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
6203fn 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
6227pub struct TypeResolutionBudget {
6240 remaining: usize,
6243 depth_limit: usize,
6246}
6247
6248impl TypeResolutionBudget {
6249 pub fn for_root(catalog: &dyn SessionCatalog) -> TypeResolutionBudget {
6255 let (depth_limit, budget) = type_resolution_limits(catalog);
6256 TypeResolutionBudget {
6257 remaining: budget.saturating_sub(1),
6259 depth_limit,
6260 }
6261 }
6262
6263 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 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
6516struct 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 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 Err(_) => return,
6569 };
6570
6571 match item.func() {
6572 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 }
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 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 (None, table_func)
6640 }
6641 _ => (None, None),
6642 };
6643 if let Some(func) = func {
6644 visit_mut::visit_expr_mut(self, expr);
6646 if let Function {
6648 name: _,
6649 args: _,
6650 filter: None,
6651 over: None,
6652 distinct: false,
6653 } = &func
6654 {
6655 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 *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 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 .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 }
6722}
6723
6724#[derive(Debug, Eq, PartialEq, Copy, Clone)]
6726pub enum QueryLifetime {
6727 OneShot,
6729 Index,
6731 MaterializedView,
6733 Subscribe,
6735 View,
6737 Source,
6739}
6740
6741impl QueryLifetime {
6742 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 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 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, QueryLifetime::View => false,
6779 QueryLifetime::Source => false,
6780 }
6781 }
6782}
6783
6784#[derive(Debug, Clone)]
6786pub struct CteDesc {
6787 pub name: String,
6788 pub desc: RelationDesc,
6789}
6790
6791#[derive(Debug, Clone)]
6793pub struct QueryContext<'a> {
6794 pub scx: &'a StatementContext<'a>,
6796 pub lifetime: QueryLifetime,
6798 pub outer_scopes: Vec<Scope>,
6800 pub outer_relation_types: Vec<SqlRelationType>,
6802 pub ctes: BTreeMap<LocalId, CteDesc>,
6804 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), }
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 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 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 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 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 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#[derive(Debug, Clone)]
6919pub struct ExprContext<'a> {
6920 pub qcx: &'a QueryContext<'a>,
6921 pub name: &'a str,
6923 pub scope: &'a Scope,
6926 pub relation_type: &'a SqlRelationType,
6929 pub allow_aggregates: bool,
6931 pub allow_subqueries: bool,
6933 pub allow_parameters: bool,
6935 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 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#[derive(Debug, Clone)]
7005pub struct NameManager(BTreeSet<Arc<str>>);
7006
7007impl NameManager {
7008 pub fn new() -> Self {
7010 Self(BTreeSet::new())
7011 }
7012
7013 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 pub fn intern_scope_item(&mut self, item: &ScopeItem) -> Arc<str> {
7029 self.intern(item.column_name.as_str())
7045 }
7046}
7047
7048#[cfg(test)]
7049mod test {
7050 use super::*;
7051
7052 #[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 let hi2 = nm.intern("hi");
7068 assert_eq!(hi.as_ptr(), hi2.as_ptr());
7069
7070 let s = format!(
7072 "{}{}",
7073 hi.chars().nth(0).unwrap(),
7074 hi2.chars().nth(1).unwrap()
7075 );
7076 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}