diff --git a/src/adapter/src/catalog.rs b/src/adapter/src/catalog.rs index 719f0a000523f..f84faf712181e 100644 --- a/src/adapter/src/catalog.rs +++ b/src/adapter/src/catalog.rs @@ -2237,7 +2237,7 @@ mod tests { use mz_catalog::builtin::{BUILTINS, Builtin, BuiltinType}; use mz_catalog::durable::{CatalogError, DurableCatalogError, FenceError, test_bootstrap_args}; use mz_controller_types::{ClusterId, ReplicaId}; - use mz_expr::MirScalarExpr; + use mz_expr::{Eval, MirScalarExpr}; use mz_ore::now::to_datetime; use mz_ore::{assert_err, assert_ok, soft_assert_eq_or_log, task}; use mz_persist_client::PersistClient; diff --git a/src/adapter/src/coord/sequencer.rs b/src/adapter/src/coord/sequencer.rs index ab20b787b64ee..2234bf467e848 100644 --- a/src/adapter/src/coord/sequencer.rs +++ b/src/adapter/src/coord/sequencer.rs @@ -26,7 +26,7 @@ use maplit::btreemap; use mz_catalog::memory::objects::Cluster; use mz_controller_types::ReplicaId; use mz_expr::row::RowCollection; -use mz_expr::{MapFilterProject, MirRelationExpr, ResultSpec, RowSetFinishing}; +use mz_expr::{Eval, MapFilterProject, MirRelationExpr, ResultSpec, RowSetFinishing}; use mz_ore::cast::CastFrom; use mz_ore::tracing::OpenTelemetryContext; use mz_persist_client::stats::SnapshotPartStats; diff --git a/src/adapter/src/coord/sequencer/inner.rs b/src/adapter/src/coord/sequencer/inner.rs index 7f9d5c4bfb20a..d287e7f907c32 100644 --- a/src/adapter/src/coord/sequencer/inner.rs +++ b/src/adapter/src/coord/sequencer/inner.rs @@ -26,7 +26,7 @@ use mz_catalog::memory::objects::{ CatalogItem, Connection, DataSourceDesc, Sink, Source, Table, TableDataSource, Type, }; use mz_expr::{ - CollectionPlan, MapFilterProject, OptimizedMirRelationExpr, ResultSpec, RowSetFinishing, + CollectionPlan, Eval, MapFilterProject, OptimizedMirRelationExpr, ResultSpec, RowSetFinishing, }; use mz_ore::cast::CastFrom; use mz_ore::collections::{CollectionExt, HashSet}; diff --git a/src/adapter/src/coord/sequencer/inner/copy_from.rs b/src/adapter/src/coord/sequencer/inner/copy_from.rs index 7e89505be4e41..82fa42cffa599 100644 --- a/src/adapter/src/coord/sequencer/inner/copy_from.rs +++ b/src/adapter/src/coord/sequencer/inner/copy_from.rs @@ -11,6 +11,7 @@ use std::str::FromStr; use std::sync::Arc; use mz_adapter_types::connection::ConnectionId; +use mz_expr::Eval; use mz_ore::cast::CastInto; use mz_persist_client::Diagnostics; use mz_persist_client::batch::ProtoBatch; diff --git a/src/adapter/src/coord/sequencer/inner/secret.rs b/src/adapter/src/coord/sequencer/inner/secret.rs index 24a9daa8b7ade..a13de3b39a209 100644 --- a/src/adapter/src/coord/sequencer/inner/secret.rs +++ b/src/adapter/src/coord/sequencer/inner/secret.rs @@ -12,7 +12,7 @@ use std::sync::Arc; use mz_catalog::memory::error::ErrorKind; use mz_catalog::memory::objects::{CatalogItem, Secret}; -use mz_expr::MirScalarExpr; +use mz_expr::{Eval, MirScalarExpr}; use mz_ore::collections::CollectionExt; use mz_ore::instrument; use mz_repr::{CatalogItemId, Datum, RowArena}; diff --git a/src/adapter/src/webhook.rs b/src/adapter/src/webhook.rs index 7bb865ee2289d..ce641983ba9c5 100644 --- a/src/adapter/src/webhook.rs +++ b/src/adapter/src/webhook.rs @@ -14,6 +14,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use anyhow::Context; use chrono::{DateTime, Utc}; use derivative::Derivative; +use mz_expr::Eval; use mz_ore::cast::CastFrom; use mz_repr::{Datum, Diff, Row, RowArena}; use mz_secrets::SecretsReader; diff --git a/src/compute-types/src/plan/join.rs b/src/compute-types/src/plan/join.rs index b3419e9d3ce54..95e677157ff27 100644 --- a/src/compute-types/src/plan/join.rs +++ b/src/compute-types/src/plan/join.rs @@ -29,7 +29,7 @@ use std::collections::BTreeMap; -use mz_expr::{MapFilterProject, MirScalarExpr}; +use mz_expr::{Columns, Eval, MapFilterProject, MirScalarExpr}; use mz_repr::{Datum, Row, RowArena}; use serde::{Deserialize, Serialize}; diff --git a/src/compute-types/src/plan/join/delta_join.rs b/src/compute-types/src/plan/join/delta_join.rs index 8e6d790fc4bfc..09ee562f143fc 100644 --- a/src/compute-types/src/plan/join/delta_join.rs +++ b/src/compute-types/src/plan/join/delta_join.rs @@ -18,8 +18,8 @@ //! not create any new stateful operators. use mz_expr::{ - JoinInputCharacteristics, JoinInputMapper, MapFilterProject, MirScalarExpr, join_permutations, - permutation_for_arrangement, + Columns, JoinInputCharacteristics, JoinInputMapper, MapFilterProject, MirScalarExpr, + join_permutations, permutation_for_arrangement, }; use serde::{Deserialize, Serialize}; diff --git a/src/compute-types/src/plan/join/linear_join.rs b/src/compute-types/src/plan/join/linear_join.rs index 6395f3e568378..a58b46e89000b 100644 --- a/src/compute-types/src/plan/join/linear_join.rs +++ b/src/compute-types/src/plan/join/linear_join.rs @@ -10,7 +10,7 @@ //! Planning of linear joins. use mz_expr::{ - JoinInputCharacteristics, MapFilterProject, MirScalarExpr, join_permutations, + Columns, JoinInputCharacteristics, MapFilterProject, MirScalarExpr, join_permutations, permutation_for_arrangement, }; use serde::{Deserialize, Serialize}; diff --git a/src/compute-types/src/plan/lowering.rs b/src/compute-types/src/plan/lowering.rs index 0545222982906..eaf03f4e09746 100644 --- a/src/compute-types/src/plan/lowering.rs +++ b/src/compute-types/src/plan/lowering.rs @@ -15,7 +15,7 @@ use columnar::Len; use itertools::Itertools; use mz_expr::JoinImplementation::{DeltaQuery, Differential, IndexedFilter, Unimplemented}; use mz_expr::{ - AggregateExpr, Id, JoinInputMapper, MapFilterProject, MirRelationExpr, MirScalarExpr, + AggregateExpr, Columns, Id, JoinInputMapper, MapFilterProject, MirRelationExpr, MirScalarExpr, OptimizedMirRelationExpr, TableFunc, permutation_for_arrangement, }; use mz_ore::{assert_none, soft_assert_eq_or_log, soft_panic_or_log}; diff --git a/src/compute/src/render/context.rs b/src/compute/src/render/context.rs index 5ba42239c74b6..6f920359caccb 100644 --- a/src/compute/src/render/context.rs +++ b/src/compute/src/render/context.rs @@ -25,7 +25,7 @@ use mz_compute_types::dyncfgs::{ }; use mz_compute_types::plan::{ArrangementStrategy, AvailableCollections}; use mz_dyncfg::ConfigSet; -use mz_expr::{Id, MapFilterProject, MirScalarExpr}; +use mz_expr::{Eval, Id, MapFilterProject, MirScalarExpr}; use mz_ore::soft_assert_or_log; use mz_repr::fixed_length::ToDatumIter; use mz_repr::{DatumVec, DatumVecBorrow, Diff, GlobalId, Row, RowArena, SharedRow}; diff --git a/src/compute/src/render/flat_map.rs b/src/compute/src/render/flat_map.rs index 6be509c61e4b9..2afec320bc9fa 100644 --- a/src/compute/src/render/flat_map.rs +++ b/src/compute/src/render/flat_map.rs @@ -11,7 +11,7 @@ use std::collections::VecDeque; use differential_dataflow::consolidation::ConsolidatingContainerBuilder; use mz_compute_types::dyncfgs::COMPUTE_FLAT_MAP_FUEL; -use mz_expr::MfpPlan; +use mz_expr::{Eval, MfpPlan}; use mz_expr::{MapFilterProject, MirScalarExpr, TableFunc}; use mz_repr::{DatumVec, RowArena, SharedRow}; use mz_repr::{Diff, Row, Timestamp}; diff --git a/src/compute/src/render/join/delta_join.rs b/src/compute/src/render/join/delta_join.rs index 67365693c33c1..b291cad478c0e 100644 --- a/src/compute/src/render/join/delta_join.rs +++ b/src/compute/src/render/join/delta_join.rs @@ -26,7 +26,7 @@ use mz_compute_types::dyncfgs::ENABLE_HALF_JOIN2; use mz_compute_types::plan::join::JoinClosure; use mz_compute_types::plan::join::delta_join::{DeltaJoinPlan, DeltaPathPlan, DeltaStagePlan}; use mz_dyncfg::ConfigSet; -use mz_expr::MirScalarExpr; +use mz_expr::{Eval, MirScalarExpr}; use mz_repr::fixed_length::ToDatumIter; use mz_repr::{DatumVec, Diff, Row, RowArena, SharedRow}; use mz_timely_util::operator::{CollectionExt, StreamExt}; diff --git a/src/compute/src/render/join/linear_join.rs b/src/compute/src/render/join/linear_join.rs index 285d1d90c7285..a265314a75d0d 100644 --- a/src/compute/src/render/join/linear_join.rs +++ b/src/compute/src/render/join/linear_join.rs @@ -22,6 +22,7 @@ use mz_compute_types::dyncfgs::{ENABLE_MZ_JOIN_CORE, LINEAR_JOIN_YIELDING}; use mz_compute_types::plan::join::JoinClosure; use mz_compute_types::plan::join::linear_join::{LinearJoinPlan, LinearStagePlan}; use mz_dyncfg::ConfigSet; +use mz_expr::Eval; use mz_repr::fixed_length::ToDatumIter; use mz_repr::{DatumVec, Diff, Row, RowArena, SharedRow}; use mz_timely_util::columnar::builder::ColumnBuilder; diff --git a/src/compute/src/render/top_k.rs b/src/compute/src/render/top_k.rs index 28df27f0d3369..a2f413a4979a3 100644 --- a/src/compute/src/render/top_k.rs +++ b/src/compute/src/render/top_k.rs @@ -28,7 +28,7 @@ use mz_compute_types::plan::top_k::{ BasicTopKPlan, MonotonicTop1Plan, MonotonicTopKPlan, TopKPlan, }; use mz_expr::func::CastUint64ToInt64; -use mz_expr::{BinaryFunc, EvalError, MirScalarExpr, UnaryFunc, func}; +use mz_expr::{BinaryFunc, Columns, Eval, EvalError, MirScalarExpr, UnaryFunc, func}; use mz_ore::cast::CastFrom; use mz_ore::soft_assert_or_log; use mz_repr::{Datum, DatumVec, Diff, ReprScalarType, Row, SharedRow}; diff --git a/src/expr/benches/case_literal.rs b/src/expr/benches/case_literal.rs index 4f9974319964a..f0225df9ffd09 100644 --- a/src/expr/benches/case_literal.rs +++ b/src/expr/benches/case_literal.rs @@ -10,8 +10,8 @@ use std::hint::black_box; use criterion::{Criterion, criterion_group, criterion_main}; -use mz_expr::MirScalarExpr; use mz_expr::func::{BinaryFunc, Eq}; +use mz_expr::{Eval, MirScalarExpr}; use mz_repr::{Datum, ReprColumnType, ReprRelationType, ReprScalarType, RowArena}; use mz_transform::Transform; use mz_transform::case_literal::CaseLiteralTransform; diff --git a/src/expr/src/interpret.rs b/src/expr/src/interpret.rs index 737464a9407a6..36d880421df8e 100644 --- a/src/expr/src/interpret.rs +++ b/src/expr/src/interpret.rs @@ -12,12 +12,12 @@ use std::fmt::Debug; use mz_repr::{Datum, ReprColumnType, ReprRelationType, ReprScalarType, Row, RowArena}; +use crate::func::Eval; use crate::scalar::func::variadic::And; use crate::{ BinaryFunc, EvalError, MapFilterProject, MfpPlan, MirScalarExpr, UnaryFunc, UnmaterializableFunc, VariadicFunc, func, }; - /// An inclusive range of non-null datum values. #[derive(Clone, Eq, PartialEq, Debug)] enum Values<'a> { diff --git a/src/expr/src/lib.rs b/src/expr/src/lib.rs index a58a3aaa8fbb1..3f3f3c7bfba30 100644 --- a/src/expr/src/lib.rs +++ b/src/expr/src/lib.rs @@ -48,7 +48,8 @@ pub use relation::{ }; pub use scalar::func::{self, BinaryFunc, UnaryFunc, UnmaterializableFunc, VariadicFunc}; pub use scalar::{ - EvalError, FilterCharacteristics, MirScalarExpr, ProtoDomainLimit, ProtoEvalError, like_pattern, + Columns, Eval, EvalError, FilterCharacteristics, MirScalarExpr, ProtoDomainLimit, + ProtoEvalError, like_pattern, }; /// A [`MirRelationExpr`] that claims to have been optimized, e.g., by an diff --git a/src/expr/src/linear.rs b/src/expr/src/linear.rs index 88e9d3e09719f..aff9c854e4f29 100644 --- a/src/expr/src/linear.rs +++ b/src/expr/src/linear.rs @@ -12,6 +12,7 @@ use std::fmt::Display; use mz_repr::{Datum, Row}; use serde::{Deserialize, Serialize}; +use crate::scalar::columns::Columns; use crate::visit::Visit; use crate::{MirRelationExpr, MirScalarExpr}; @@ -1509,6 +1510,7 @@ pub mod util { use std::collections::BTreeMap; use crate::MirScalarExpr; + use crate::scalar::columns::Columns; #[allow(dead_code)] /// A triple of actions that map from rows to (key, val) pairs and back again. @@ -1524,8 +1526,9 @@ pub mod util { /// Derive supporting logic to support transforming rows to (key, val) pairs, /// and back again. /// - /// We are given as input a list of key expressions and an input arity, and the - /// requirement the produced key should be the application of the key expressions. + /// We are given as input a list of mappings from columns to key indices, a key length, + /// and an input arity. (The produced key should be the application of the key expressions.) + /// /// To produce the `val` output, we will identify those input columns not found in /// the key expressions, and name all other columns. /// To reconstitute the original row, we identify the sequence of columns from the @@ -1536,10 +1539,10 @@ pub mod util { /// of a row that should become the value associated with its key. /// /// The permutations and thinning expressions generated here will be tracked in - /// `dataflow::plan::AvailableCollections`; see the + /// `compute_types::plan::AvailableCollections`; see the /// documentation there for more details. pub fn permutation_for_arrangement( - key: &[MirScalarExpr], + key: &[impl Columns], unthinned_arity: usize, ) -> (Vec, Vec) { let columns_in_key: BTreeMap<_, _> = key @@ -1547,7 +1550,9 @@ pub mod util { .enumerate() .filter_map(|(i, key_col)| key_col.as_column().map(|c| (c, i))) .collect(); - let mut input_cursor = key.len(); + let key_len = key.len(); + + let mut input_cursor = key_len; let permutation = (0..unthinned_arity) .map(|c| { if let Some(c) = columns_in_key.get(&c) { @@ -1604,6 +1609,7 @@ pub mod plan { use mz_repr::{Datum, Diff, Row, RowArena}; use serde::{Deserialize, Serialize}; + use crate::func::Eval; use crate::{BinaryFunc, EvalError, MapFilterProject, MirScalarExpr, UnaryFunc, func}; /// A wrapper type which indicates it is safe to simply evaluate all expressions. diff --git a/src/expr/src/relation.rs b/src/expr/src/relation.rs index bff2ebc3f8b26..a516152e64df5 100644 --- a/src/expr/src/relation.rs +++ b/src/expr/src/relation.rs @@ -45,6 +45,7 @@ use crate::Id::Local; use crate::explain::{HumanizedExpr, HumanizerMode}; use crate::relation::func::{AggregateFunc, LagLeadType, TableFunc}; use crate::row::{RowCollection, RowCollectionIter}; +use crate::scalar::columns::Columns; use crate::scalar::func::variadic::{ JsonbBuildArray, JsonbBuildObject, ListCreate, ListIndex, MapBuild, RecordCreate, }; diff --git a/src/expr/src/relation/join_input_mapper.rs b/src/expr/src/relation/join_input_mapper.rs index e0de5419ee5f9..0207172beca51 100644 --- a/src/expr/src/relation/join_input_mapper.rs +++ b/src/expr/src/relation/join_input_mapper.rs @@ -13,6 +13,7 @@ use std::ops::Range; use itertools::Itertools; use mz_repr::ReprRelationType; +use crate::scalar::columns::Columns; use crate::scalar::func::variadic::{And, Or}; use crate::visit::Visit; use crate::{MirRelationExpr, MirScalarExpr, VariadicFunc}; @@ -180,11 +181,9 @@ impl JoinInputMapper { /// Takes an expression from the global context and creates a new version /// where column references have been remapped to the local context. /// Assumes that all columns in `expr` are from the same input. - pub fn map_expr_to_local(&self, mut expr: MirScalarExpr) -> MirScalarExpr { - expr.visit_pre_mut(|e| { - if let MirScalarExpr::Column(c, _name) = e { - *c -= self.prior_arities[self.input_relation[*c]]; - } + pub fn map_expr_to_local(&self, mut expr: C) -> C { + expr.visit_columns(|c| { + *c -= self.prior_arities[self.input_relation[*c]]; }); expr } @@ -192,11 +191,9 @@ impl JoinInputMapper { /// Takes an expression from the local context of the `index`th input and /// creates a new version where column references have been remapped to the /// global context. - pub fn map_expr_to_global(&self, mut expr: MirScalarExpr, index: usize) -> MirScalarExpr { - expr.visit_pre_mut(|e| { - if let MirScalarExpr::Column(c, _name) = e { - *c += self.prior_arities[index]; - } + pub fn map_expr_to_global(&self, mut expr: C, index: usize) -> C { + expr.visit_columns(|c| { + *c += self.prior_arities[index]; }); expr } @@ -229,7 +226,7 @@ impl JoinInputMapper { } /// Find the sorted, dedupped set of inputs an expression references - pub fn lookup_inputs(&self, expr: &MirScalarExpr) -> impl Iterator + use<> { + pub fn lookup_inputs(&self, expr: &C) -> impl Iterator + use { expr.support() .iter() .map(|c| self.input_relation[*c]) @@ -238,7 +235,7 @@ impl JoinInputMapper { } /// Returns the index of the only input referenced in the given expression. - pub fn single_input(&self, expr: &MirScalarExpr) -> Option { + pub fn single_input(&self, expr: &impl Columns) -> Option { let mut inputs = self.lookup_inputs(expr); if let Some(first_input) = inputs.next() { if inputs.next().is_none() { @@ -249,7 +246,7 @@ impl JoinInputMapper { } /// Returns whether the given expr refers to columns of only the `index`th input. - pub fn is_localized(&self, expr: &MirScalarExpr, index: usize) -> bool { + pub fn is_localized(&self, expr: &impl Columns, index: usize) -> bool { if let Some(single_input) = self.single_input(expr) { if single_input == index { return true; @@ -296,16 +293,16 @@ impl JoinInputMapper { /// input_mapper.find_bound_expr(&MirScalarExpr::column(0), &[1], &equivalences) /// ); /// ``` - pub fn find_bound_expr( + pub fn find_bound_expr( &self, - expr: &MirScalarExpr, + expr: &C, bound_inputs: &[usize], - equivalences: &[Vec], - ) -> Option { + equivalences: &[Vec], + ) -> Option { if let Some(equivalence) = equivalences.iter().find(|equivs| equivs.contains(expr)) { if let Some(bound_expr) = equivalence .iter() - .find(|expr| self.lookup_inputs(expr).all(|i| bound_inputs.contains(&i))) + .find(|expr| self.lookup_inputs(*expr).all(|i| bound_inputs.contains(&i))) { return Some(bound_expr.clone()); } diff --git a/src/expr/src/scalar.rs b/src/expr/src/scalar.rs index 6741ad4a155ed..3c9cebac6a235 100644 --- a/src/expr/src/scalar.rs +++ b/src/expr/src/scalar.rs @@ -7,7 +7,7 @@ // the Business Source License, use of this software will be governed // by the Apache License, Version 2.0. -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::BTreeSet; use std::ops::BitOrAssign; use std::sync::Arc; use std::{fmt, mem}; @@ -36,11 +36,14 @@ use proptest_derive::Arbitrary; use serde::{Deserialize, Serialize}; use crate::explain::{HumanizedExplain, HumanizerMode}; +pub use crate::scalar::columns::Columns; +pub use crate::scalar::func::Eval; use crate::scalar::func::variadic::{And, Or}; use crate::scalar::func::{BinaryFunc, UnaryFunc, UnmaterializableFunc, VariadicFunc}; use crate::scalar::proto_eval_error::proto_incompatible_array_dimensions::ProtoDims; use crate::visit::{Visit, VisitChildren}; +pub mod columns; pub mod func; pub mod like_pattern; mod reduce; @@ -458,52 +461,6 @@ impl MirScalarExpr { } } - /// Rewrites column indices with their value in `permutation`. - /// - /// This method is applicable even when `permutation` is not a - /// strict permutation, and it only needs to have entries for - /// each column referenced in `self`. - pub fn permute(&mut self, permutation: &[usize]) { - self.visit_columns(|c| *c = permutation[*c]); - } - - /// Rewrites column indices with their value in `permutation`. - /// - /// This method is applicable even when `permutation` is not a - /// strict permutation, and it only needs to have entries for - /// each column referenced in `self`. - pub fn permute_map(&mut self, permutation: &BTreeMap) { - self.visit_columns(|c| *c = permutation[c]); - } - - /// Visits each column reference and applies `action` to the column. - /// - /// Useful for remapping columns, or for collecting expression support. - pub fn visit_columns(&mut self, mut action: F) - where - F: FnMut(&mut usize), - { - self.visit_pre_mut(|e| { - if let MirScalarExpr::Column(col, _) = e { - action(col); - } - }); - } - - pub fn support(&self) -> BTreeSet { - let mut support = BTreeSet::new(); - self.support_into(&mut support); - support - } - - pub fn support_into(&self, support: &mut BTreeSet) { - self.visit_pre(|e| { - if let MirScalarExpr::Column(i, _) = e { - support.insert(*i); - } - }); - } - pub fn take(&mut self) -> Self { mem::replace(self, MirScalarExpr::literal_null(ReprScalarType::String)) } @@ -584,10 +541,6 @@ impl MirScalarExpr { matches!(self, MirScalarExpr::Literal(Err(_), _typ)) } - pub fn is_column(&self) -> bool { - matches!(self, MirScalarExpr::Column(_col, _name)) - } - pub fn is_error_if_null(&self) -> bool { matches!( self, @@ -696,15 +649,6 @@ impl MirScalarExpr { false } - /// If self is a column, return the column index, otherwise `None`. - pub fn as_column(&self) -> Option { - if let MirScalarExpr::Column(c, _) = self { - Some(*c) - } else { - None - } - } - /// Reduces a complex expression where possible. /// /// This function uses nullability information present in `column_types`, @@ -1151,38 +1095,6 @@ impl MirScalarExpr { } } - pub fn eval<'a>( - &'a self, - datums: &[Datum<'a>], - temp_storage: &'a RowArena, - ) -> Result, EvalError> { - match self { - MirScalarExpr::Column(index, _name) => Ok(datums[*index]), - MirScalarExpr::Literal(res, _column_type) => match res { - Ok(row) => Ok(row.unpack_first()), - Err(e) => Err(e.clone()), - }, - // Unmaterializable functions must be transformed away before - // evaluation. Their purpose is as a placeholder for data that is - // not known at plan time but can be inlined before runtime. - MirScalarExpr::CallUnmaterializable(x) => Err(EvalError::Internal( - format!("cannot evaluate unmaterializable function: {:?}", x).into(), - )), - MirScalarExpr::CallUnary { func, expr } => func.eval(datums, temp_storage, expr), - MirScalarExpr::CallBinary { func, expr1, expr2 } => { - func.eval(datums, temp_storage, &[expr1, expr2]) - } - MirScalarExpr::CallVariadic { func, exprs } => func.eval(datums, temp_storage, exprs), - MirScalarExpr::If { cond, then, els } => match cond.eval(datums, temp_storage)? { - Datum::True => then.eval(datums, temp_storage), - Datum::False | Datum::Null => els.eval(datums, temp_storage), - d => Err(EvalError::Internal( - format!("if condition evaluated to non-boolean datum: {:?}", d).into(), - )), - }, - } - } - /// True iff the expression contains /// `UnmaterializableFunc::MzNow`. pub fn contains_temporal(&self) -> bool { @@ -1251,9 +1163,77 @@ impl MirScalarExpr { } } -impl MirScalarExpr { - /// True iff evaluation could possibly error on non-error input `Datum`. - pub fn could_error(&self) -> bool { +impl Columns for MirScalarExpr { + fn is_column(&self) -> bool { + matches!(self, MirScalarExpr::Column(_col, _name)) + } + + fn as_column(&self) -> Option { + if let MirScalarExpr::Column(c, _) = self { + Some(*c) + } else { + None + } + } + + fn support_into(&self, support: &mut BTreeSet) { + self.visit_pre(|e| { + if let MirScalarExpr::Column(i, _) = e { + support.insert(*i); + } + }); + } + + fn visit_columns(&mut self, mut action: F) + where + F: FnMut(&mut usize), + { + self.visit_pre_mut(|e| { + if let MirScalarExpr::Column(col, _) = e { + action(col); + } + }); + } +} + +impl Eval for MirScalarExpr { + fn eval<'a>( + &'a self, + datums: &[Datum<'a>], + temp_storage: &'a RowArena, + ) -> Result, EvalError> { + match self { + MirScalarExpr::Column(index, _name) => Ok(datums[*index]), + MirScalarExpr::Literal(res, _column_type) => match res { + Ok(row) => Ok(row.unpack_first()), + Err(e) => Err(e.clone()), + }, + // Unmaterializable functions must be transformed away before + // evaluation. Their purpose is as a placeholder for data that is + // not known at plan time but can be inlined before runtime. + MirScalarExpr::CallUnmaterializable(x) => Err(EvalError::Internal( + format!("cannot evaluate unmaterializable function: {:?}", x).into(), + )), + MirScalarExpr::CallUnary { func, expr } => { + func.eval(datums, temp_storage, expr.as_ref()) + } + MirScalarExpr::CallBinary { func, expr1, expr2 } => { + func.eval(datums, temp_storage, &[expr1.as_ref(), expr2.as_ref()]) + } + MirScalarExpr::CallVariadic { func, exprs } => { + func.eval(datums, temp_storage, exprs.as_slice()) + } + MirScalarExpr::If { cond, then, els } => match cond.eval(datums, temp_storage)? { + Datum::True => then.eval(datums, temp_storage), + Datum::False | Datum::Null => els.eval(datums, temp_storage), + d => Err(EvalError::Internal( + format!("if condition evaluated to non-boolean datum: {:?}", d).into(), + )), + }, + } + } + + fn could_error(&self) -> bool { match self { MirScalarExpr::Column(_col, _name) => false, MirScalarExpr::Literal(row, ..) => row.is_err(), diff --git a/src/expr/src/scalar/columns.rs b/src/expr/src/scalar/columns.rs new file mode 100644 index 0000000000000..d17313cb4704e --- /dev/null +++ b/src/expr/src/scalar/columns.rs @@ -0,0 +1,53 @@ +// Copyright Materialize, Inc. and contributors. All rights reserved. +// +// Use of this software is governed by the Business Source License +// included in the LICENSE file. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0. + +//! Generic interface for scalar expressions that hold columns. + +use std::collections::{BTreeMap, BTreeSet}; + +pub trait Columns: Sized { + /// True when the outermost structure is a column. + fn is_column(&self) -> bool; + + /// If self is a column, return the column index, otherwise `None`. + fn as_column(&self) -> Option; + + fn support(&self) -> BTreeSet { + let mut support = BTreeSet::new(); + self.support_into(&mut support); + support + } + + fn support_into(&self, support: &mut BTreeSet); + + /// Rewrites column indices with their value in `permutation`. + /// + /// This method is applicable even when `permutation` is not a + /// strict permutation, and it only needs to have entries for + /// each column referenced in `self`. + fn permute(&mut self, permutation: &[usize]) { + self.visit_columns(|c| *c = permutation[*c]); + } + + /// Rewrites column indices with their value in `permutation`. + /// + /// This method is applicable even when `permutation` is not a + /// strict permutation, and it only needs to have entries for + /// each column referenced in `self`. + fn permute_map(&mut self, permutation: &BTreeMap) { + self.visit_columns(|c| *c = permutation[c]); + } + + /// Visits each column reference and applies `action` to the column. + /// + /// Useful for remapping columns, or for collecting expression support. + fn visit_columns(&mut self, action: F) + where + F: FnMut(&mut usize); +} diff --git a/src/expr/src/scalar/func.rs b/src/expr/src/scalar/func.rs index 71c9c7bf6f5ec..09997d34a386b 100644 --- a/src/expr/src/scalar/func.rs +++ b/src/expr/src/scalar/func.rs @@ -53,6 +53,7 @@ use num::traits::CheckedNeg; use crate::scalar::func::format::DateTimeFormat; use crate::{EvalError, like_pattern}; +pub mod eval; #[macro_use] mod macros; mod binary; @@ -64,6 +65,7 @@ mod unmaterializable; pub mod variadic; pub use binary::BinaryFunc; +pub use eval::Eval; pub use impls::*; pub use unary::{EagerUnaryFunc, LazyUnaryFunc, UnaryFunc}; pub use unmaterializable::UnmaterializableFunc; diff --git a/src/expr/src/scalar/func/binary.rs b/src/expr/src/scalar/func/binary.rs index 6de0472112bc0..d4343b51e6325 100644 --- a/src/expr/src/scalar/func/binary.rs +++ b/src/expr/src/scalar/func/binary.rs @@ -12,7 +12,8 @@ use mz_ore::assert_none; use mz_repr::{Datum, InputDatumType, OutputDatumType, ReprColumnType, RowArena, SqlColumnType}; -use crate::{EvalError, MirScalarExpr}; +use crate::EvalError; +use crate::func::Eval; /// A description of an SQL binary function that has the ability to lazy evaluate its arguments // This trait will eventually be annotated with #[enum_dispatch] to autogenerate the UnaryFunc enum @@ -21,7 +22,7 @@ pub(crate) trait LazyBinaryFunc { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - exprs: &[&'a MirScalarExpr], + exprs: &[&'a impl Eval], ) -> Result, EvalError>; /// The output SqlColumnType of this function. @@ -130,7 +131,7 @@ impl LazyBinaryFunc for T { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - exprs: &[&'a MirScalarExpr], + exprs: &[&'a impl Eval], ) -> Result, EvalError> { let mut datums = exprs .into_iter() @@ -189,9 +190,9 @@ mod derive { use mz_repr::{Datum, ReprColumnType, RowArena, SqlColumnType}; + use crate::EvalError; use crate::scalar::func::binary::LazyBinaryFunc; use crate::scalar::func::*; - use crate::{EvalError, MirScalarExpr}; derive_binary! { AddInt16(AddInt16), diff --git a/src/expr/src/scalar/func/eval.rs b/src/expr/src/scalar/func/eval.rs new file mode 100644 index 0000000000000..05d7ff457ccfa --- /dev/null +++ b/src/expr/src/scalar/func/eval.rs @@ -0,0 +1,32 @@ +// Copyright Materialize, Inc. and contributors. All rights reserved. +// +// Use of this software is governed by the Business Source License +// included in the LICENSE file. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0. +// +// Portions of this file are derived from the PostgreSQL project. The original +// source code is subject to the terms of the PostgreSQL license, a copy of +// which can be found in the LICENSE file at the root of this repository. + +//! A trait for things that can evaluate (`MirScalarExpr`, `LirScalarExpr`). + +use mz_repr::{Datum, RowArena}; + +use crate::EvalError; + +pub trait Eval { + /// Evaluates, where `datums` are column references and `temp_storage` is used for allocation. + /// + /// Should not panic, but instead return an appropriate `EvalError`. + fn eval<'a>( + &'a self, + datums: &[Datum<'a>], + temp_storage: &'a RowArena, + ) -> Result, EvalError>; + + /// True iff evaluation could possibly error on non-error input `Datum`. + fn could_error(&self) -> bool; +} diff --git a/src/expr/src/scalar/func/impls/array.rs b/src/expr/src/scalar/func/impls/array.rs index 23c42dc0ca844..9981a03ac6f37 100644 --- a/src/expr/src/scalar/func/impls/array.rs +++ b/src/expr/src/scalar/func/impls/array.rs @@ -15,6 +15,7 @@ use mz_repr::adt::array::{Array, ArrayDimension}; use mz_repr::{Datum, DatumList, Row, RowArena, RowPacker, SqlColumnType, SqlScalarType}; use serde::{Deserialize, Serialize}; +use crate::func::Eval; use crate::scalar::func::{LazyUnaryFunc, stringify_datum}; use crate::{EvalError, MirScalarExpr}; @@ -59,7 +60,7 @@ impl LazyUnaryFunc for CastArrayToString { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { @@ -128,7 +129,7 @@ impl LazyUnaryFunc for CastArrayToJsonb { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { fn pack<'a>( temp_storage: &RowArena, @@ -239,7 +240,7 @@ impl LazyUnaryFunc for CastArrayToArray { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { diff --git a/src/expr/src/scalar/func/impls/case_literal.rs b/src/expr/src/scalar/func/impls/case_literal.rs index e29f7afa2f562..21451d19138d7 100644 --- a/src/expr/src/scalar/func/impls/case_literal.rs +++ b/src/expr/src/scalar/func/impls/case_literal.rs @@ -25,8 +25,9 @@ use mz_lowertest::MzReflect; use mz_repr::{Datum, Row, RowArena, SqlColumnType}; use serde::{Deserialize, Serialize}; +use crate::EvalError; +use crate::func::Eval; use crate::scalar::func::variadic::LazyVariadicFunc; -use crate::{EvalError, MirScalarExpr}; /// A single entry in a [`CaseLiteral`] lookup table: a literal `Row` value /// paired with the index of the corresponding result expression in `exprs`. @@ -81,7 +82,7 @@ impl LazyVariadicFunc for CaseLiteral { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - exprs: &'a [MirScalarExpr], + exprs: &'a [impl Eval], ) -> Result, EvalError> { let input = exprs[0].eval(datums, temp_storage)?; // SQL NULL = x is always NULL/falsy, so go straight to the fallback. diff --git a/src/expr/src/scalar/func/impls/list.rs b/src/expr/src/scalar/func/impls/list.rs index d8d48a58b47f6..7c2f50ca82431 100644 --- a/src/expr/src/scalar/func/impls/list.rs +++ b/src/expr/src/scalar/func/impls/list.rs @@ -14,6 +14,7 @@ use mz_lowertest::MzReflect; use mz_repr::{AsColumnType, Datum, DatumList, Row, RowArena, SqlColumnType, SqlScalarType}; use serde::{Deserialize, Serialize}; +use crate::func::Eval; use crate::func::binary::EagerBinaryFunc; use crate::scalar::func::{LazyUnaryFunc, stringify_datum}; use crate::{EvalError, MirScalarExpr}; @@ -39,7 +40,7 @@ impl LazyUnaryFunc for CastListToString { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { @@ -107,7 +108,7 @@ impl LazyUnaryFunc for CastListToJsonb { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { @@ -190,7 +191,7 @@ impl LazyUnaryFunc for CastList1ToList2 { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { diff --git a/src/expr/src/scalar/func/impls/map.rs b/src/expr/src/scalar/func/impls/map.rs index 520c02d412044..f5ce6ab4bf026 100644 --- a/src/expr/src/scalar/func/impls/map.rs +++ b/src/expr/src/scalar/func/impls/map.rs @@ -15,8 +15,9 @@ use mz_lowertest::MzReflect; use mz_repr::{Datum, DatumMap, RowArena, SqlColumnType, SqlScalarType}; use serde::{Deserialize, Serialize}; +use crate::EvalError; +use crate::func::Eval; use crate::scalar::func::{LazyUnaryFunc, stringify_datum}; -use crate::{EvalError, MirScalarExpr}; #[derive( Ord, @@ -39,7 +40,7 @@ impl LazyUnaryFunc for CastMapToString { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { @@ -115,7 +116,7 @@ impl LazyUnaryFunc for MapBuildFromRecordList { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { diff --git a/src/expr/src/scalar/func/impls/range.rs b/src/expr/src/scalar/func/impls/range.rs index 654f805aefe4a..807eac2e0a050 100644 --- a/src/expr/src/scalar/func/impls/range.rs +++ b/src/expr/src/scalar/func/impls/range.rs @@ -15,8 +15,9 @@ use mz_repr::adt::range::Range; use mz_repr::{Datum, RowArena, SqlColumnType, SqlScalarType}; use serde::{Deserialize, Serialize}; +use crate::EvalError; +use crate::func::Eval; use crate::scalar::func::{LazyUnaryFunc, stringify_datum}; -use crate::{EvalError, MirScalarExpr}; #[derive( Ord, @@ -39,7 +40,7 @@ impl LazyUnaryFunc for CastRangeToString { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { diff --git a/src/expr/src/scalar/func/impls/record.rs b/src/expr/src/scalar/func/impls/record.rs index 0faf1ec33716d..51c7bf508cad7 100644 --- a/src/expr/src/scalar/func/impls/record.rs +++ b/src/expr/src/scalar/func/impls/record.rs @@ -14,6 +14,7 @@ use mz_lowertest::MzReflect; use mz_repr::{Datum, RowArena, SqlColumnType, SqlScalarType}; use serde::{Deserialize, Serialize}; +use crate::func::Eval; use crate::scalar::func::{LazyUnaryFunc, stringify_datum}; use crate::{EvalError, MirScalarExpr}; @@ -38,7 +39,7 @@ impl LazyUnaryFunc for CastRecordToString { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { @@ -109,7 +110,7 @@ impl LazyUnaryFunc for CastRecord1ToRecord2 { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { @@ -182,7 +183,7 @@ impl LazyUnaryFunc for RecordGet { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { diff --git a/src/expr/src/scalar/func/impls/string.rs b/src/expr/src/scalar/func/impls/string.rs index 2470d1563ee61..97600d5080135 100644 --- a/src/expr/src/scalar/func/impls/string.rs +++ b/src/expr/src/scalar/func/impls/string.rs @@ -31,7 +31,7 @@ use mz_repr::{Datum, RowArena, SqlColumnType, SqlScalarType, strconv}; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::func::{binary, regexp_match_static}; +use crate::func::{Eval, binary, regexp_match_static}; use crate::scalar::func::{ EagerUnaryFunc, LazyUnaryFunc, array_create_scalar, regexp_split_to_array_re, }; @@ -352,7 +352,7 @@ impl LazyUnaryFunc for CastStringToArray { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { @@ -440,7 +440,7 @@ impl LazyUnaryFunc for CastStringToList { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { @@ -534,7 +534,7 @@ impl LazyUnaryFunc for CastStringToMap { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { @@ -704,7 +704,7 @@ impl LazyUnaryFunc for CastStringToRange { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { @@ -871,7 +871,7 @@ impl LazyUnaryFunc for CastStringToInt2Vector { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let a = a.eval(datums, temp_storage)?; if a.is_null() { @@ -1113,7 +1113,7 @@ impl LazyUnaryFunc for RegexpMatch { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let haystack = a.eval(datums, temp_storage)?; if haystack.is_null() { @@ -1186,7 +1186,7 @@ impl LazyUnaryFunc for RegexpSplitToArray { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { let haystack = a.eval(datums, temp_storage)?; if haystack.is_null() { diff --git a/src/expr/src/scalar/func/macros.rs b/src/expr/src/scalar/func/macros.rs index 6160de7702dbe..592aaa44c061c 100644 --- a/src/expr/src/scalar/func/macros.rs +++ b/src/expr/src/scalar/func/macros.rs @@ -159,7 +159,7 @@ macro_rules! derive_unary { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl crate::func::eval::Eval, ) -> Result, EvalError> { match self { $(Self::$name(f) => f.eval(datums, temp_storage, a),)* @@ -251,7 +251,7 @@ macro_rules! derive_variadic { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - exprs: &'a [MirScalarExpr], + exprs: &'a [impl Eval], ) -> Result, EvalError> { match self { $(Self::$name(f) => f.eval(datums, temp_storage, exprs),)* @@ -348,7 +348,7 @@ macro_rules! derive_binary { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - exprs: &[&'a MirScalarExpr], + exprs: &[&'a impl Eval], ) -> Result, EvalError> { match self { $(Self::$name(f) => f.eval(datums, temp_storage, exprs),)* diff --git a/src/expr/src/scalar/func/unary.rs b/src/expr/src/scalar/func/unary.rs index 0e3a8d1d7404c..7c853edb396a8 100644 --- a/src/expr/src/scalar/func/unary.rs +++ b/src/expr/src/scalar/func/unary.rs @@ -17,9 +17,10 @@ use std::{fmt, str}; use mz_repr::{Datum, InputDatumType, OutputDatumType, ReprColumnType, RowArena, SqlColumnType}; +use crate::EvalError; +use crate::func::Eval; use crate::scalar::func::RedactSql; use crate::scalar::func::impls::*; -use crate::{EvalError, MirScalarExpr}; /// A description of an SQL unary function that has the ability to lazy evaluate its arguments // This trait will eventually be annotated with #[enum_dispatch] to autogenerate the UnaryFunc enum @@ -28,7 +29,7 @@ pub trait LazyUnaryFunc { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError>; /// The output SqlColumnType of this function. @@ -160,7 +161,7 @@ impl LazyUnaryFunc for T { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - a: &'a MirScalarExpr, + a: &'a impl Eval, ) -> Result, EvalError> { match T::Input::<'_>::try_from_result(a.eval(datums, temp_storage)) { // If we can convert to the input type then we call the function @@ -558,7 +559,7 @@ mod test { use itertools::Itertools; use mz_repr::{PropDatum, SqlScalarType}; - use crate::like_pattern; + use crate::{MirScalarExpr, like_pattern}; use super::*; diff --git a/src/expr/src/scalar/func/variadic.rs b/src/expr/src/scalar/func/variadic.rs index c0c8f517d4508..19329ea1ba486 100644 --- a/src/expr/src/scalar/func/variadic.rs +++ b/src/expr/src/scalar/func/variadic.rs @@ -41,6 +41,7 @@ use mz_repr::{ use serde::{Deserialize, Serialize}; use crate::func::CaseLiteral; +use crate::func::Eval; use crate::func::{ MAX_STRING_FUNC_RESULT_BYTES, array_create_scalar, build_regex, date_bin, parse_timezone, regexp_match_static, regexp_replace_parse_flags, regexp_split_to_array_re, stringify_datum, @@ -76,7 +77,7 @@ impl LazyVariadicFunc for And { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - exprs: &'a [MirScalarExpr], + exprs: &'a [impl Eval], ) -> Result, EvalError> { // If any is false, then return false. Else, if any is null, then return null. Else, return true. let mut null = false; @@ -497,7 +498,7 @@ impl LazyVariadicFunc for Coalesce { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - exprs: &'a [MirScalarExpr], + exprs: &'a [impl Eval], ) -> Result, EvalError> { for e in exprs { let d = e.eval(datums, temp_storage)?; @@ -692,7 +693,7 @@ impl LazyVariadicFunc for ErrorIfNull { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - exprs: &'a [MirScalarExpr], + exprs: &'a [impl Eval], ) -> Result, EvalError> { let first = exprs[0].eval(datums, temp_storage)?; match first { @@ -749,7 +750,7 @@ impl LazyVariadicFunc for Greatest { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - exprs: &'a [MirScalarExpr], + exprs: &'a [impl Eval], ) -> Result, EvalError> { let datums = fallible_iterator::convert(exprs.iter().map(|e| e.eval(datums, temp_storage))); Ok(datums @@ -888,7 +889,7 @@ impl LazyVariadicFunc for Least { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - exprs: &'a [MirScalarExpr], + exprs: &'a [impl Eval], ) -> Result, EvalError> { let datums = fallible_iterator::convert(exprs.iter().map(|e| e.eval(datums, temp_storage))); Ok(datums @@ -1149,7 +1150,7 @@ impl LazyVariadicFunc for Or { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - exprs: &'a [MirScalarExpr], + exprs: &'a [impl Eval], ) -> Result, EvalError> { // If any is true, then return true. Else, if any is null, then return null. Else, return false. let mut null = false; @@ -1591,7 +1592,7 @@ pub(crate) trait LazyVariadicFunc: fmt::Display { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - exprs: &'a [MirScalarExpr], + exprs: &'a [impl Eval], ) -> Result, EvalError>; /// The output SqlColumnType of this function. @@ -1664,7 +1665,7 @@ impl LazyVariadicFunc for T { &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, - exprs: &'a [MirScalarExpr], + exprs: &'a [impl Eval], ) -> Result, EvalError> { let mut datums = exprs.iter().map(|e| e.eval(datums, temp_storage)); match T::Input::try_from_iter(&mut datums) { diff --git a/src/expr/src/scalar/reduce/binary.rs b/src/expr/src/scalar/reduce/binary.rs index 8761fb668c067..c7fec2430a460 100644 --- a/src/expr/src/scalar/reduce/binary.rs +++ b/src/expr/src/scalar/reduce/binary.rs @@ -21,7 +21,7 @@ use crate::EvalError; use crate::MirScalarExpr; use crate::scalar::func::format::DateTimeFormat; use crate::scalar::func::variadic::And; -use crate::scalar::func::{self, BinaryFunc, UnaryFunc, VariadicFunc, parse_timezone}; +use crate::scalar::func::{self, BinaryFunc, Eval, UnaryFunc, VariadicFunc, parse_timezone}; use crate::scalar::like_pattern; pub(super) fn reduce_call_binary( diff --git a/src/expr/src/scalar/reduce/unary.rs b/src/expr/src/scalar/reduce/unary.rs index 3885330a9dd4a..4d0cc610510c8 100644 --- a/src/expr/src/scalar/reduce/unary.rs +++ b/src/expr/src/scalar/reduce/unary.rs @@ -12,7 +12,7 @@ use mz_repr::{ReprColumnType, RowArena}; use crate::MirScalarExpr; -use crate::scalar::func::{self, UnaryFunc, VariadicFunc}; +use crate::scalar::func::{self, Eval, UnaryFunc, VariadicFunc}; pub(super) fn reduce_call_unary( e: &mut MirScalarExpr, diff --git a/src/expr/src/scalar/reduce/variadic.rs b/src/expr/src/scalar/reduce/variadic.rs index 0c6995e02a5ec..8b562d1684ef6 100644 --- a/src/expr/src/scalar/reduce/variadic.rs +++ b/src/expr/src/scalar/reduce/variadic.rs @@ -19,7 +19,7 @@ use mz_repr::{Datum, ReprColumnType, ReprScalarType, RowArena, SqlScalarType}; use crate::MirScalarExpr; use crate::scalar::func::variadic::{Coalesce, ListCreate, ListIndex}; use crate::scalar::func::{ - self, BinaryFunc, UnaryFunc, VariadicFunc, parse_timezone, regexp_replace_parse_flags, + self, BinaryFunc, Eval, UnaryFunc, VariadicFunc, parse_timezone, regexp_replace_parse_flags, }; pub(super) fn reduce_call_variadic( diff --git a/src/expr/tests/test_runner.rs b/src/expr/tests/test_runner.rs index 245be5f12a598..d7a224f4f90dc 100644 --- a/src/expr/tests/test_runner.rs +++ b/src/expr/tests/test_runner.rs @@ -10,7 +10,7 @@ mod test { use itertools::Itertools; use mz_expr::canonicalize::{canonicalize_equivalences, canonicalize_predicates}; - use mz_expr::{ColumnSpecs, Interpreter, MapFilterProject, MirScalarExpr}; + use mz_expr::{ColumnSpecs, Eval, Interpreter, MapFilterProject, MirScalarExpr}; use mz_expr_test_util::*; use mz_lowertest::{MzReflect, deserialize, deserialize_optional, tokenize}; use mz_ore::result::ResultExt; diff --git a/src/sql/src/plan/lowering.rs b/src/sql/src/plan/lowering.rs index d24fe983618af..9014f66401992 100644 --- a/src/sql/src/plan/lowering.rs +++ b/src/sql/src/plan/lowering.rs @@ -42,7 +42,7 @@ use std::iter::repeat; use itertools::Itertools; use mz_expr::func::variadic; use mz_expr::visit::Visit; -use mz_expr::{AccessStrategy, AggregateFunc, MirRelationExpr, MirScalarExpr, func}; +use mz_expr::{AccessStrategy, AggregateFunc, Columns, MirRelationExpr, MirScalarExpr, func}; use mz_ore::collections::CollectionExt; use mz_ore::stack::maybe_grow; use mz_repr::*; diff --git a/src/sql/src/plan/query.rs b/src/sql/src/plan/query.rs index 5449efb47042b..8f12e8ddea6e7 100644 --- a/src/sql/src/plan/query.rs +++ b/src/sql/src/plan/query.rs @@ -52,8 +52,8 @@ use mz_expr::func::variadic::{ }; use mz_expr::virtual_syntax::AlgExcept; use mz_expr::{ - Id, LetRecLimit, LocalId, MapFilterProject, MirScalarExpr, REPEAT_ROW_NAME, RowSetFinishing, - TableFunc, func as expr_func, + Eval, Id, LetRecLimit, LocalId, MapFilterProject, MirScalarExpr, REPEAT_ROW_NAME, + RowSetFinishing, TableFunc, func as expr_func, }; use mz_ore::assert_none; use mz_ore::collections::CollectionExt; diff --git a/src/sql/src/plan/side_effecting_func.rs b/src/sql/src/plan/side_effecting_func.rs index e6b3f22dbe85b..2aa624b9a38b2 100644 --- a/src/sql/src/plan/side_effecting_func.rs +++ b/src/sql/src/plan/side_effecting_func.rs @@ -34,6 +34,7 @@ use std::sync::LazyLock; use enum_kinds::EnumKind; use itertools::Itertools; +use mz_expr::Eval; use mz_ore::cast::ReinterpretCast; use mz_ore::collections::CollectionExt; use mz_ore::result::ResultExt; diff --git a/src/storage-types/src/sources/casts.rs b/src/storage-types/src/sources/casts.rs index 31bc99d5bb459..f0cb93a0dc2dc 100644 --- a/src/storage-types/src/sources/casts.rs +++ b/src/storage-types/src/sources/casts.rs @@ -931,7 +931,7 @@ mod tests { // (Ok values and Err variants) as MirScalarExpr for the same inputs. mod parity { - use mz_expr::{MirScalarExpr, UnaryFunc}; + use mz_expr::{Eval, MirScalarExpr, UnaryFunc}; use mz_repr::{Datum, RowArena}; use super::*; diff --git a/src/storage/src/sink/kafka.rs b/src/storage/src/sink/kafka.rs index f427e8d84cedd..fa1199bcfc378 100644 --- a/src/storage/src/sink/kafka.rs +++ b/src/storage/src/sink/kafka.rs @@ -89,7 +89,7 @@ use anyhow::{Context, anyhow, bail}; use differential_dataflow::{AsCollection, Hashable, VecCollection}; use futures::StreamExt; use maplit::btreemap; -use mz_expr::MirScalarExpr; +use mz_expr::{Eval, MirScalarExpr}; use mz_interchange::avro::AvroEncoder; use mz_interchange::encode::Encode; use mz_interchange::envelopes::{dbz_format, for_each_diff_pair}; diff --git a/src/transform/src/analysis.rs b/src/transform/src/analysis.rs index 1df27798f147c..2d0ee2712bb66 100644 --- a/src/transform/src/analysis.rs +++ b/src/transform/src/analysis.rs @@ -951,7 +951,7 @@ mod column_names { use std::sync::Arc; use super::Analysis; - use mz_expr::{AggregateFunc, Id, MirRelationExpr, MirScalarExpr, TableFunc}; + use mz_expr::{AggregateFunc, Columns, Id, MirRelationExpr, MirScalarExpr, TableFunc}; use mz_repr::explain::ExprHumanizer; use mz_repr::{GlobalId, UNKNOWN_COLUMN_NAME}; use mz_sql::ORDINALITY_COL_NAME; diff --git a/src/transform/src/analysis/equivalences.rs b/src/transform/src/analysis/equivalences.rs index 90b2cd848e716..d7bcee4f1bcf6 100644 --- a/src/transform/src/analysis/equivalences.rs +++ b/src/transform/src/analysis/equivalences.rs @@ -21,7 +21,7 @@ use std::fmt::Formatter; use itertools::Itertools; use mz_expr::canonicalize::{UnionFind, canonicalize_equivalence_classes}; use mz_expr::explain::{HumanizedExplain, HumanizerMode}; -use mz_expr::{AggregateFunc, Id, MirRelationExpr, MirScalarExpr}; +use mz_expr::{AggregateFunc, Columns, Id, MirRelationExpr, MirScalarExpr}; use mz_ore::str::{bracketed, separated}; use mz_repr::{Datum, ReprColumnType, ReprScalarType}; diff --git a/src/transform/src/canonicalization/projection_extraction.rs b/src/transform/src/canonicalization/projection_extraction.rs index 398d6e5be2350..d59cba403c8a4 100644 --- a/src/transform/src/canonicalization/projection_extraction.rs +++ b/src/transform/src/canonicalization/projection_extraction.rs @@ -10,7 +10,7 @@ //! Transform column references in a `Map` into a `Project`. use mz_expr::visit::Visit; -use mz_expr::{MirRelationExpr, MirScalarExpr}; +use mz_expr::{Columns, MirRelationExpr, MirScalarExpr}; use crate::TransformCtx; diff --git a/src/transform/src/case_literal.rs b/src/transform/src/case_literal.rs index 0a1ba289ec7da..a44e0e2e2992c 100644 --- a/src/transform/src/case_literal.rs +++ b/src/transform/src/case_literal.rs @@ -361,7 +361,7 @@ fn collect_if_chain_arms( #[cfg(test)] mod tests { use mz_expr::func::Eq; - use mz_expr::{MirRelationExpr, MirScalarExpr, VariadicFunc}; + use mz_expr::{Eval, MirRelationExpr, MirScalarExpr, VariadicFunc}; use mz_repr::{Datum, ReprColumnType, ReprRelationType, ReprScalarType}; use super::*; diff --git a/src/transform/src/demand.rs b/src/transform/src/demand.rs index 5c3cb970f5557..61c66801674f0 100644 --- a/src/transform/src/demand.rs +++ b/src/transform/src/demand.rs @@ -14,7 +14,7 @@ use mz_ore::assert_none; use std::collections::{BTreeMap, BTreeSet}; use mz_expr::{ - AggregateExpr, AggregateFunc, Id, JoinInputMapper, MirRelationExpr, MirScalarExpr, + AggregateExpr, AggregateFunc, Columns, Id, JoinInputMapper, MirRelationExpr, MirScalarExpr, RECURSION_LIMIT, }; use mz_ore::stack::{CheckedRecursion, RecursionGuard}; diff --git a/src/transform/src/equivalence_propagation.rs b/src/transform/src/equivalence_propagation.rs index df24bf2cf1904..e73fa21e93253 100644 --- a/src/transform/src/equivalence_propagation.rs +++ b/src/transform/src/equivalence_propagation.rs @@ -31,7 +31,7 @@ use std::collections::BTreeMap; use itertools::Itertools; -use mz_expr::{Id, MirRelationExpr, MirScalarExpr}; +use mz_expr::{Eval, Id, MirRelationExpr, MirScalarExpr}; use mz_repr::{Datum, ReprScalarType}; use tracing::debug; diff --git a/src/transform/src/fold_constants.rs b/src/transform/src/fold_constants.rs index fdfafc44529f7..7104fa390ccaa 100644 --- a/src/transform/src/fold_constants.rs +++ b/src/transform/src/fold_constants.rs @@ -16,7 +16,7 @@ use std::iter; use mz_expr::visit::Visit; use mz_expr::{ - AggregateExpr, ColumnOrder, EvalError, MirRelationExpr, MirScalarExpr, RowComparator, + AggregateExpr, ColumnOrder, Eval, EvalError, MirRelationExpr, MirScalarExpr, RowComparator, TableFunc, UnaryFunc, }; use mz_repr::{Datum, Diff, ReprRelationType, Row, RowArena}; diff --git a/src/transform/src/join_implementation.rs b/src/transform/src/join_implementation.rs index 0ca6a194325a0..1a552fa6e97c6 100644 --- a/src/transform/src/join_implementation.rs +++ b/src/transform/src/join_implementation.rs @@ -22,8 +22,8 @@ use itertools::Itertools; use mz_expr::JoinImplementation::{Differential, IndexedFilter, Unimplemented}; use mz_expr::visit::{Visit, VisitChildren}; use mz_expr::{ - FilterCharacteristics, Id, JoinInputCharacteristics, JoinInputMapper, MapFilterProject, - MirRelationExpr, MirScalarExpr, RECURSION_LIMIT, + Columns, FilterCharacteristics, Id, JoinInputCharacteristics, JoinInputMapper, + MapFilterProject, MirRelationExpr, MirScalarExpr, RECURSION_LIMIT, }; use mz_ore::stack::{CheckedRecursion, RecursionGuard}; use mz_ore::{soft_assert_or_log, soft_panic_or_log}; @@ -671,7 +671,7 @@ mod delta_queries { mod differential { use std::collections::BTreeSet; - use mz_expr::{JoinImplementation, JoinInputMapper, MirRelationExpr, MirScalarExpr}; + use mz_expr::{Columns, JoinImplementation, JoinInputMapper, MirRelationExpr, MirScalarExpr}; use mz_ore::soft_assert_eq_or_log; use mz_repr::optimize::OptimizerFeatures; diff --git a/src/transform/src/literal_lifting.rs b/src/transform/src/literal_lifting.rs index f4aa0bd807b9e..a7caf07492b6c 100644 --- a/src/transform/src/literal_lifting.rs +++ b/src/transform/src/literal_lifting.rs @@ -25,7 +25,7 @@ use std::collections::BTreeMap; use itertools::{Itertools, zip_eq}; use mz_expr::JoinImplementation::IndexedFilter; use mz_expr::visit::Visit; -use mz_expr::{Id, JoinInputMapper, MirRelationExpr, MirScalarExpr, RECURSION_LIMIT}; +use mz_expr::{Eval, Id, JoinInputMapper, MirRelationExpr, MirScalarExpr, RECURSION_LIMIT}; use mz_ore::stack::{CheckedRecursion, RecursionGuard}; use mz_repr::{Row, RowPacker}; diff --git a/src/transform/src/movement/projection_lifting.rs b/src/transform/src/movement/projection_lifting.rs index 68c91a11eb836..03680de10525e 100644 --- a/src/transform/src/movement/projection_lifting.rs +++ b/src/transform/src/movement/projection_lifting.rs @@ -15,7 +15,7 @@ use std::collections::BTreeMap; use std::mem; use itertools::zip_eq; -use mz_expr::{AccessStrategy, Id, MirRelationExpr, RECURSION_LIMIT}; +use mz_expr::{AccessStrategy, Columns, Id, MirRelationExpr, RECURSION_LIMIT}; use mz_ore::stack::{CheckedRecursion, RecursionGuard}; use mz_repr::ReprRelationType; diff --git a/src/transform/src/movement/projection_pushdown.rs b/src/transform/src/movement/projection_pushdown.rs index 86e0761e6aaad..9680f3895582d 100644 --- a/src/transform/src/movement/projection_pushdown.rs +++ b/src/transform/src/movement/projection_pushdown.rs @@ -34,7 +34,8 @@ use std::collections::{BTreeMap, BTreeSet}; use itertools::{Itertools, zip_eq}; use mz_expr::{ - Id, JoinImplementation, JoinInputMapper, MirRelationExpr, MirScalarExpr, RECURSION_LIMIT, + Columns, Id, JoinImplementation, JoinInputMapper, MirRelationExpr, MirScalarExpr, + RECURSION_LIMIT, }; use mz_ore::assert_none; use mz_ore::stack::{CheckedRecursion, RecursionGuard}; diff --git a/src/transform/src/predicate_pushdown.rs b/src/transform/src/predicate_pushdown.rs index 4f320ed89ebe1..cba9205213bf7 100644 --- a/src/transform/src/predicate_pushdown.rs +++ b/src/transform/src/predicate_pushdown.rs @@ -94,8 +94,8 @@ use itertools::Itertools; use mz_expr::func::variadic::And; use mz_expr::visit::{Visit, VisitChildren}; use mz_expr::{ - AggregateFunc, Id, JoinInputMapper, LocalId, MirRelationExpr, MirScalarExpr, RECURSION_LIMIT, - VariadicFunc, func, + AggregateFunc, Columns, Id, JoinInputMapper, LocalId, MirRelationExpr, MirScalarExpr, + RECURSION_LIMIT, VariadicFunc, func, }; use mz_ore::soft_assert_eq_no_log; use mz_ore::stack::{CheckedRecursion, RecursionGuard, RecursionLimitError}; diff --git a/src/transform/src/reduce_elision.rs b/src/transform/src/reduce_elision.rs index c3a4696636a71..f00bdcb26a40e 100644 --- a/src/transform/src/reduce_elision.rs +++ b/src/transform/src/reduce_elision.rs @@ -14,7 +14,7 @@ //! can be simplified to a map operation. use itertools::Itertools; -use mz_expr::MirRelationExpr; +use mz_expr::{Columns, MirRelationExpr}; use crate::TransformCtx; use crate::analysis::{DerivedBuilder, DerivedView}; diff --git a/src/transform/src/reduction_pushdown.rs b/src/transform/src/reduction_pushdown.rs index d753eb5d327d3..8cbe2334e1048 100644 --- a/src/transform/src/reduction_pushdown.rs +++ b/src/transform/src/reduction_pushdown.rs @@ -51,7 +51,7 @@ use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; use mz_expr::visit::Visit; -use mz_expr::{AggregateExpr, JoinInputMapper, MirRelationExpr, MirScalarExpr}; +use mz_expr::{AggregateExpr, Columns, JoinInputMapper, MirRelationExpr, MirScalarExpr}; use crate::TransformCtx; use crate::analysis::equivalences::EquivalenceClasses; diff --git a/src/transform/src/redundant_join.rs b/src/transform/src/redundant_join.rs index 53a179507230a..a576eed524b5c 100644 --- a/src/transform/src/redundant_join.rs +++ b/src/transform/src/redundant_join.rs @@ -26,7 +26,9 @@ use std::collections::BTreeMap; use itertools::Itertools; use mz_expr::visit::Visit; -use mz_expr::{Id, JoinInputMapper, LocalId, MirRelationExpr, MirScalarExpr, RECURSION_LIMIT}; +use mz_expr::{ + Columns, Id, JoinInputMapper, LocalId, MirRelationExpr, MirScalarExpr, RECURSION_LIMIT, +}; use mz_ore::stack::{CheckedRecursion, RecursionGuard}; use mz_ore::{assert_none, soft_panic_or_log}; diff --git a/src/transform/src/semijoin_idempotence.rs b/src/transform/src/semijoin_idempotence.rs index 3c87a9cd1fbff..7d9e24e360782 100644 --- a/src/transform/src/semijoin_idempotence.rs +++ b/src/transform/src/semijoin_idempotence.rs @@ -29,7 +29,9 @@ use itertools::Itertools; use mz_repr::ReprRelationType; use std::collections::BTreeMap; -use mz_expr::{Id, JoinInputMapper, LocalId, MirRelationExpr, MirScalarExpr, RECURSION_LIMIT}; +use mz_expr::{ + Columns, Id, JoinInputMapper, LocalId, MirRelationExpr, MirScalarExpr, RECURSION_LIMIT, +}; use mz_ore::id_gen::IdGen; use mz_ore::stack::{CheckedRecursion, RecursionGuard};