use std::collections::{BTreeMap, BTreeSet};
use std::fmt::{Display, Formatter};
use std::{fmt, mem};
use itertools::Itertools;
use mz_expr::virtual_syntax::{AlgExcept, Except, IR};
use mz_expr::visit::{Visit, VisitChildren};
use mz_expr::{func, CollectionPlan, Id, LetRecLimit, RowSetFinishing};
use mz_expr::AggregateFunc::WindowAggregate;
pub use mz_expr::{
BinaryFunc, ColumnOrder, TableFunc, UnaryFunc, UnmaterializableFunc, VariadicFunc, WindowFrame,
};
use mz_ore::collections::CollectionExt;
use mz_ore::stack;
use mz_ore::stack::RecursionLimitError;
use mz_repr::adt::array::ArrayDimension;
use mz_repr::adt::numeric::NumericMaxScale;
use mz_repr::*;
use serde::{Deserialize, Serialize};
use crate::plan::error::PlanError;
use crate::plan::query::ExprContext;
use crate::plan::typeconv::{self, CastContext};
use crate::plan::Params;
use super::plan_utils::GroupSizeHints;
#[allow(missing_debug_implementations)]
pub struct Hir;
impl IR for Hir {
type Relation = HirRelationExpr;
type Scalar = HirScalarExpr;
}
impl AlgExcept for Hir {
fn except(all: &bool, lhs: Self::Relation, rhs: Self::Relation) -> Self::Relation {
if *all {
let rhs = rhs.negate();
HirRelationExpr::union(lhs, rhs).threshold()
} else {
let lhs = lhs.distinct();
let rhs = rhs.distinct().negate();
HirRelationExpr::union(lhs, rhs).threshold()
}
}
fn un_except<'a>(expr: &'a Self::Relation) -> Option<Except<'a, Self>> {
let mut result = None;
use HirRelationExpr::*;
if let Threshold { input } = expr {
if let Union { base: lhs, inputs } = input.as_ref() {
if let [rhs] = &inputs[..] {
if let Negate { input: rhs } = rhs {
match (lhs.as_ref(), rhs.as_ref()) {
(Distinct { input: lhs }, Distinct { input: rhs }) => {
let all = false;
let lhs = lhs.as_ref();
let rhs = rhs.as_ref();
result = Some(Except { all, lhs, rhs })
}
(lhs, rhs) => {
let all = true;
result = Some(Except { all, lhs, rhs })
}
}
}
}
}
}
result
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum HirRelationExpr {
Constant {
rows: Vec<Row>,
typ: RelationType,
},
Get {
id: mz_expr::Id,
typ: RelationType,
},
LetRec {
limit: Option<LetRecLimit>,
bindings: Vec<(String, mz_expr::LocalId, HirRelationExpr, RelationType)>,
body: Box<HirRelationExpr>,
},
Let {
name: String,
id: mz_expr::LocalId,
value: Box<HirRelationExpr>,
body: Box<HirRelationExpr>,
},
Project {
input: Box<HirRelationExpr>,
outputs: Vec<usize>,
},
Map {
input: Box<HirRelationExpr>,
scalars: Vec<HirScalarExpr>,
},
CallTable {
func: TableFunc,
exprs: Vec<HirScalarExpr>,
},
Filter {
input: Box<HirRelationExpr>,
predicates: Vec<HirScalarExpr>,
},
Join {
left: Box<HirRelationExpr>,
right: Box<HirRelationExpr>,
on: HirScalarExpr,
kind: JoinKind,
},
Reduce {
input: Box<HirRelationExpr>,
group_key: Vec<usize>,
aggregates: Vec<AggregateExpr>,
expected_group_size: Option<u64>,
},
Distinct {
input: Box<HirRelationExpr>,
},
TopK {
input: Box<HirRelationExpr>,
group_key: Vec<usize>,
order_key: Vec<ColumnOrder>,
limit: Option<HirScalarExpr>,
offset: usize,
expected_group_size: Option<u64>,
},
Negate {
input: Box<HirRelationExpr>,
},
Threshold {
input: Box<HirRelationExpr>,
},
Union {
base: Box<HirRelationExpr>,
inputs: Vec<HirRelationExpr>,
},
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum HirScalarExpr {
Column(ColumnRef),
Parameter(usize),
Literal(Row, ColumnType),
CallUnmaterializable(UnmaterializableFunc),
CallUnary {
func: UnaryFunc,
expr: Box<HirScalarExpr>,
},
CallBinary {
func: BinaryFunc,
expr1: Box<HirScalarExpr>,
expr2: Box<HirScalarExpr>,
},
CallVariadic {
func: VariadicFunc,
exprs: Vec<HirScalarExpr>,
},
If {
cond: Box<HirScalarExpr>,
then: Box<HirScalarExpr>,
els: Box<HirScalarExpr>,
},
Exists(Box<HirRelationExpr>),
Select(Box<HirRelationExpr>),
Windowing(WindowExpr),
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct WindowExpr {
pub func: WindowExprType,
pub partition_by: Vec<HirScalarExpr>,
pub order_by: Vec<HirScalarExpr>,
}
impl WindowExpr {
pub fn visit_expressions<'a, F, E>(&'a self, f: &mut F) -> Result<(), E>
where
F: FnMut(&'a HirScalarExpr) -> Result<(), E>,
{
#[allow(deprecated)]
self.func.visit_expressions(f)?;
for expr in self.partition_by.iter() {
f(expr)?;
}
for expr in self.order_by.iter() {
f(expr)?;
}
Ok(())
}
pub fn visit_expressions_mut<'a, F, E>(&'a mut self, f: &mut F) -> Result<(), E>
where
F: FnMut(&'a mut HirScalarExpr) -> Result<(), E>,
{
#[allow(deprecated)]
self.func.visit_expressions_mut(f)?;
for expr in self.partition_by.iter_mut() {
f(expr)?;
}
for expr in self.order_by.iter_mut() {
f(expr)?;
}
Ok(())
}
}
impl VisitChildren<HirScalarExpr> for WindowExpr {
fn visit_children<F>(&self, mut f: F)
where
F: FnMut(&HirScalarExpr),
{
self.func.visit_children(&mut f);
for expr in self.partition_by.iter() {
f(expr);
}
for expr in self.order_by.iter() {
f(expr);
}
}
fn visit_mut_children<F>(&mut self, mut f: F)
where
F: FnMut(&mut HirScalarExpr),
{
self.func.visit_mut_children(&mut f);
for expr in self.partition_by.iter_mut() {
f(expr);
}
for expr in self.order_by.iter_mut() {
f(expr);
}
}
fn try_visit_children<F, E>(&self, mut f: F) -> Result<(), E>
where
F: FnMut(&HirScalarExpr) -> Result<(), E>,
E: From<RecursionLimitError>,
{
self.func.try_visit_children(&mut f)?;
for expr in self.partition_by.iter() {
f(expr)?;
}
for expr in self.order_by.iter() {
f(expr)?;
}
Ok(())
}
fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
where
F: FnMut(&mut HirScalarExpr) -> Result<(), E>,
E: From<RecursionLimitError>,
{
self.func.try_visit_mut_children(&mut f)?;
for expr in self.partition_by.iter_mut() {
f(expr)?;
}
for expr in self.order_by.iter_mut() {
f(expr)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum WindowExprType {
Scalar(ScalarWindowExpr),
Value(ValueWindowExpr),
Aggregate(AggregateWindowExpr),
}
impl WindowExprType {
#[deprecated = "Use `VisitChildren<HirScalarExpr>::visit_children` instead."]
pub fn visit_expressions<'a, F, E>(&'a self, f: &mut F) -> Result<(), E>
where
F: FnMut(&'a HirScalarExpr) -> Result<(), E>,
{
#[allow(deprecated)]
match self {
Self::Scalar(expr) => expr.visit_expressions(f),
Self::Value(expr) => expr.visit_expressions(f),
Self::Aggregate(expr) => expr.visit_expressions(f),
}
}
#[deprecated = "Use `VisitChildren<HirScalarExpr>::visit_mut_children` instead."]
pub fn visit_expressions_mut<'a, F, E>(&'a mut self, f: &mut F) -> Result<(), E>
where
F: FnMut(&'a mut HirScalarExpr) -> Result<(), E>,
{
#[allow(deprecated)]
match self {
Self::Scalar(expr) => expr.visit_expressions_mut(f),
Self::Value(expr) => expr.visit_expressions_mut(f),
Self::Aggregate(expr) => expr.visit_expressions_mut(f),
}
}
fn typ(
&self,
outers: &[RelationType],
inner: &RelationType,
params: &BTreeMap<usize, ScalarType>,
) -> ColumnType {
match self {
Self::Scalar(expr) => expr.typ(outers, inner, params),
Self::Value(expr) => expr.typ(outers, inner, params),
Self::Aggregate(expr) => expr.typ(outers, inner, params),
}
}
}
impl VisitChildren<HirScalarExpr> for WindowExprType {
fn visit_children<F>(&self, f: F)
where
F: FnMut(&HirScalarExpr),
{
match self {
Self::Scalar(_) => (),
Self::Value(expr) => expr.visit_children(f),
Self::Aggregate(expr) => expr.visit_children(f),
}
}
fn visit_mut_children<F>(&mut self, f: F)
where
F: FnMut(&mut HirScalarExpr),
{
match self {
Self::Scalar(_) => (),
Self::Value(expr) => expr.visit_mut_children(f),
Self::Aggregate(expr) => expr.visit_mut_children(f),
}
}
fn try_visit_children<F, E>(&self, f: F) -> Result<(), E>
where
F: FnMut(&HirScalarExpr) -> Result<(), E>,
E: From<RecursionLimitError>,
{
match self {
Self::Scalar(_) => Ok(()),
Self::Value(expr) => expr.try_visit_children(f),
Self::Aggregate(expr) => expr.try_visit_children(f),
}
}
fn try_visit_mut_children<F, E>(&mut self, f: F) -> Result<(), E>
where
F: FnMut(&mut HirScalarExpr) -> Result<(), E>,
E: From<RecursionLimitError>,
{
match self {
Self::Scalar(_) => Ok(()),
Self::Value(expr) => expr.try_visit_mut_children(f),
Self::Aggregate(expr) => expr.try_visit_mut_children(f),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct ScalarWindowExpr {
pub func: ScalarWindowFunc,
pub order_by: Vec<ColumnOrder>,
}
impl ScalarWindowExpr {
#[deprecated = "Implement `VisitChildren<HirScalarExpr>` if needed."]
pub fn visit_expressions<'a, F, E>(&'a self, _f: &mut F) -> Result<(), E>
where
F: FnMut(&'a HirScalarExpr) -> Result<(), E>,
{
match self.func {
ScalarWindowFunc::RowNumber => {}
ScalarWindowFunc::Rank => {}
ScalarWindowFunc::DenseRank => {}
}
Ok(())
}
#[deprecated = "Implement `VisitChildren<HirScalarExpr>` if needed."]
pub fn visit_expressions_mut<'a, F, E>(&'a mut self, _f: &mut F) -> Result<(), E>
where
F: FnMut(&'a mut HirScalarExpr) -> Result<(), E>,
{
match self.func {
ScalarWindowFunc::RowNumber => {}
ScalarWindowFunc::Rank => {}
ScalarWindowFunc::DenseRank => {}
}
Ok(())
}
fn typ(
&self,
_outers: &[RelationType],
_inner: &RelationType,
_params: &BTreeMap<usize, ScalarType>,
) -> ColumnType {
self.func.output_type()
}
pub fn into_expr(self) -> mz_expr::AggregateFunc {
match self.func {
ScalarWindowFunc::RowNumber => mz_expr::AggregateFunc::RowNumber {
order_by: self.order_by,
},
ScalarWindowFunc::Rank => mz_expr::AggregateFunc::Rank {
order_by: self.order_by,
},
ScalarWindowFunc::DenseRank => mz_expr::AggregateFunc::DenseRank {
order_by: self.order_by,
},
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum ScalarWindowFunc {
RowNumber,
Rank,
DenseRank,
}
impl Display for ScalarWindowFunc {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
ScalarWindowFunc::RowNumber => write!(f, "row_number"),
ScalarWindowFunc::Rank => write!(f, "rank"),
ScalarWindowFunc::DenseRank => write!(f, "dense_rank"),
}
}
}
impl ScalarWindowFunc {
pub fn output_type(&self) -> ColumnType {
match self {
ScalarWindowFunc::RowNumber => ScalarType::Int64.nullable(false),
ScalarWindowFunc::Rank => ScalarType::Int64.nullable(false),
ScalarWindowFunc::DenseRank => ScalarType::Int64.nullable(false),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct ValueWindowExpr {
pub func: ValueWindowFunc,
pub args: Box<HirScalarExpr>,
pub order_by: Vec<ColumnOrder>,
pub window_frame: WindowFrame,
pub ignore_nulls: bool,
}
impl Display for ValueWindowFunc {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
ValueWindowFunc::Lag => write!(f, "lag"),
ValueWindowFunc::Lead => write!(f, "lead"),
ValueWindowFunc::FirstValue => write!(f, "first_value"),
ValueWindowFunc::LastValue => write!(f, "last_value"),
}
}
}
impl ValueWindowExpr {
#[deprecated = "Use `VisitChildren<HirScalarExpr>::visit_children` instead."]
pub fn visit_expressions<'a, F, E>(&'a self, f: &mut F) -> Result<(), E>
where
F: FnMut(&'a HirScalarExpr) -> Result<(), E>,
{
f(&self.args)
}
#[deprecated = "Use `VisitChildren<HirScalarExpr>::visit_mut_children` instead."]
pub fn visit_expressions_mut<'a, F, E>(&'a mut self, f: &mut F) -> Result<(), E>
where
F: FnMut(&'a mut HirScalarExpr) -> Result<(), E>,
{
f(&mut self.args)
}
fn typ(
&self,
outers: &[RelationType],
inner: &RelationType,
params: &BTreeMap<usize, ScalarType>,
) -> ColumnType {
self.func.output_type(self.args.typ(outers, inner, params))
}
pub fn into_expr(self) -> (Box<HirScalarExpr>, mz_expr::AggregateFunc) {
(
self.args,
match self.func {
ValueWindowFunc::Lag => mz_expr::AggregateFunc::LagLead {
order_by: self.order_by,
lag_lead: mz_expr::LagLeadType::Lag,
ignore_nulls: self.ignore_nulls,
},
ValueWindowFunc::Lead => mz_expr::AggregateFunc::LagLead {
order_by: self.order_by,
lag_lead: mz_expr::LagLeadType::Lead,
ignore_nulls: self.ignore_nulls,
},
ValueWindowFunc::FirstValue => mz_expr::AggregateFunc::FirstValue {
order_by: self.order_by,
window_frame: self.window_frame,
},
ValueWindowFunc::LastValue => mz_expr::AggregateFunc::LastValue {
order_by: self.order_by,
window_frame: self.window_frame,
},
},
)
}
}
impl VisitChildren<HirScalarExpr> for ValueWindowExpr {
fn visit_children<F>(&self, mut f: F)
where
F: FnMut(&HirScalarExpr),
{
f(&self.args)
}
fn visit_mut_children<F>(&mut self, mut f: F)
where
F: FnMut(&mut HirScalarExpr),
{
f(&mut self.args)
}
fn try_visit_children<F, E>(&self, mut f: F) -> Result<(), E>
where
F: FnMut(&HirScalarExpr) -> Result<(), E>,
E: From<RecursionLimitError>,
{
f(&self.args)
}
fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
where
F: FnMut(&mut HirScalarExpr) -> Result<(), E>,
E: From<RecursionLimitError>,
{
f(&mut self.args)
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum ValueWindowFunc {
Lag,
Lead,
FirstValue,
LastValue,
}
impl ValueWindowFunc {
pub fn output_type(&self, input_type: ColumnType) -> ColumnType {
match self {
ValueWindowFunc::Lag | ValueWindowFunc::Lead => {
input_type.scalar_type.unwrap_record_element_type()[0]
.clone()
.nullable(true)
}
ValueWindowFunc::FirstValue | ValueWindowFunc::LastValue => {
input_type.scalar_type.nullable(true)
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct AggregateWindowExpr {
pub aggregate_expr: AggregateExpr,
pub order_by: Vec<ColumnOrder>,
pub window_frame: WindowFrame,
}
impl AggregateWindowExpr {
#[deprecated = "Use `VisitChildren<HirScalarExpr>::visit_children` instead."]
pub fn visit_expressions<'a, F, E>(&'a self, f: &mut F) -> Result<(), E>
where
F: FnMut(&'a HirScalarExpr) -> Result<(), E>,
{
f(&self.aggregate_expr.expr)
}
#[deprecated = "Use `VisitChildren<HirScalarExpr>::visit_mut_children` instead."]
pub fn visit_expressions_mut<'a, F, E>(&'a mut self, f: &mut F) -> Result<(), E>
where
F: FnMut(&'a mut HirScalarExpr) -> Result<(), E>,
{
f(&mut self.aggregate_expr.expr)
}
fn typ(
&self,
outers: &[RelationType],
inner: &RelationType,
params: &BTreeMap<usize, ScalarType>,
) -> ColumnType {
self.aggregate_expr
.func
.output_type(self.aggregate_expr.expr.typ(outers, inner, params))
}
pub fn into_expr(self) -> (Box<HirScalarExpr>, mz_expr::AggregateFunc) {
(
self.aggregate_expr.expr,
WindowAggregate {
wrapped_aggregate: Box::new(self.aggregate_expr.func.into_expr()),
order_by: self.order_by,
window_frame: self.window_frame,
},
)
}
}
impl VisitChildren<HirScalarExpr> for AggregateWindowExpr {
fn visit_children<F>(&self, mut f: F)
where
F: FnMut(&HirScalarExpr),
{
f(&self.aggregate_expr.expr)
}
fn visit_mut_children<F>(&mut self, mut f: F)
where
F: FnMut(&mut HirScalarExpr),
{
f(&mut self.aggregate_expr.expr)
}
fn try_visit_children<F, E>(&self, mut f: F) -> Result<(), E>
where
F: FnMut(&HirScalarExpr) -> Result<(), E>,
E: From<RecursionLimitError>,
{
f(&self.aggregate_expr.expr)
}
fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
where
F: FnMut(&mut HirScalarExpr) -> Result<(), E>,
E: From<RecursionLimitError>,
{
f(&mut self.aggregate_expr.expr)
}
}
#[derive(Clone, Debug)]
pub enum CoercibleScalarExpr {
Coerced(HirScalarExpr),
Parameter(usize),
LiteralNull,
LiteralString(String),
LiteralRecord(Vec<CoercibleScalarExpr>),
}
impl CoercibleScalarExpr {
pub fn type_as(self, ecx: &ExprContext, ty: &ScalarType) -> Result<HirScalarExpr, PlanError> {
let expr = typeconv::plan_coerce(ecx, self, ty)?;
let expr_ty = ecx.scalar_type(&expr);
if ty != &expr_ty {
sql_bail!(
"{} must have type {}, not type {}",
ecx.name,
ecx.humanize_scalar_type(ty),
ecx.humanize_scalar_type(&expr_ty),
);
}
Ok(expr)
}
pub fn type_as_any(self, ecx: &ExprContext) -> Result<HirScalarExpr, PlanError> {
typeconv::plan_coerce(ecx, self, &ScalarType::String)
}
pub fn cast_to(
self,
ecx: &ExprContext,
ccx: CastContext,
ty: &ScalarType,
) -> Result<HirScalarExpr, PlanError> {
let expr = typeconv::plan_coerce(ecx, self, ty)?;
typeconv::plan_cast(ecx, ccx, expr, ty)
}
}
pub trait AbstractExpr {
type Type: AbstractColumnType;
fn typ(
&self,
outers: &[RelationType],
inner: &RelationType,
params: &BTreeMap<usize, ScalarType>,
) -> Self::Type;
}
impl AbstractExpr for CoercibleScalarExpr {
type Type = Option<ColumnType>;
fn typ(
&self,
outers: &[RelationType],
inner: &RelationType,
params: &BTreeMap<usize, ScalarType>,
) -> Self::Type {
match self {
CoercibleScalarExpr::Coerced(expr) => Some(expr.typ(outers, inner, params)),
CoercibleScalarExpr::LiteralRecord(scalars) => {
let mut fields = vec![];
for (i, scalar) in scalars.iter().enumerate() {
fields.push((
format!("f{}", i + 1).into(),
scalar.typ(outers, inner, params)?,
));
}
Some(ColumnType {
scalar_type: ScalarType::Record {
fields,
custom_id: None,
},
nullable: false,
})
}
_ => None,
}
}
}
pub trait AbstractColumnType {
type AbstractScalarType;
fn scalar_type(self) -> Self::AbstractScalarType;
}
impl AbstractColumnType for ColumnType {
type AbstractScalarType = ScalarType;
fn scalar_type(self) -> Self::AbstractScalarType {
self.scalar_type
}
}
impl AbstractColumnType for Option<ColumnType> {
type AbstractScalarType = Option<ScalarType>;
fn scalar_type(self) -> Self::AbstractScalarType {
self.map(|t| t.scalar_type)
}
}
impl From<HirScalarExpr> for CoercibleScalarExpr {
fn from(expr: HirScalarExpr) -> CoercibleScalarExpr {
CoercibleScalarExpr::Coerced(expr)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)]
pub struct ColumnRef {
pub level: usize,
pub column: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum JoinKind {
Inner,
LeftOuter,
RightOuter,
FullOuter,
}
impl fmt::Display for JoinKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
JoinKind::Inner => "Inner",
JoinKind::LeftOuter => "LeftOuter",
JoinKind::RightOuter => "RightOuter",
JoinKind::FullOuter => "FullOuter",
}
)
}
}
impl JoinKind {
pub fn can_be_correlated(&self) -> bool {
match self {
JoinKind::Inner | JoinKind::LeftOuter => true,
JoinKind::RightOuter | JoinKind::FullOuter => false,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct AggregateExpr {
pub func: AggregateFunc,
pub expr: Box<HirScalarExpr>,
pub distinct: bool,
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum AggregateFunc {
MaxNumeric,
MaxInt16,
MaxInt32,
MaxInt64,
MaxUInt16,
MaxUInt32,
MaxUInt64,
MaxMzTimestamp,
MaxFloat32,
MaxFloat64,
MaxBool,
MaxString,
MaxDate,
MaxTimestamp,
MaxTimestampTz,
MaxInterval,
MaxTime,
MinNumeric,
MinInt16,
MinInt32,
MinInt64,
MinUInt16,
MinUInt32,
MinUInt64,
MinMzTimestamp,
MinFloat32,
MinFloat64,
MinBool,
MinString,
MinDate,
MinTimestamp,
MinTimestampTz,
MinInterval,
MinTime,
SumInt16,
SumInt32,
SumInt64,
SumUInt16,
SumUInt32,
SumUInt64,
SumFloat32,
SumFloat64,
SumNumeric,
Count,
Any,
All,
JsonbAgg {
order_by: Vec<ColumnOrder>,
},
JsonbObjectAgg {
order_by: Vec<ColumnOrder>,
},
MapAgg {
order_by: Vec<ColumnOrder>,
value_type: ScalarType,
},
ArrayConcat {
order_by: Vec<ColumnOrder>,
},
ListConcat {
order_by: Vec<ColumnOrder>,
},
StringAgg {
order_by: Vec<ColumnOrder>,
},
Dummy,
}
impl AggregateFunc {
pub fn into_expr(self) -> mz_expr::AggregateFunc {
match self {
AggregateFunc::MaxNumeric => mz_expr::AggregateFunc::MaxNumeric,
AggregateFunc::MaxInt16 => mz_expr::AggregateFunc::MaxInt16,
AggregateFunc::MaxInt32 => mz_expr::AggregateFunc::MaxInt32,
AggregateFunc::MaxInt64 => mz_expr::AggregateFunc::MaxInt64,
AggregateFunc::MaxUInt16 => mz_expr::AggregateFunc::MaxUInt16,
AggregateFunc::MaxUInt32 => mz_expr::AggregateFunc::MaxUInt32,
AggregateFunc::MaxUInt64 => mz_expr::AggregateFunc::MaxUInt64,
AggregateFunc::MaxMzTimestamp => mz_expr::AggregateFunc::MaxMzTimestamp,
AggregateFunc::MaxFloat32 => mz_expr::AggregateFunc::MaxFloat32,
AggregateFunc::MaxFloat64 => mz_expr::AggregateFunc::MaxFloat64,
AggregateFunc::MaxBool => mz_expr::AggregateFunc::MaxBool,
AggregateFunc::MaxString => mz_expr::AggregateFunc::MaxString,
AggregateFunc::MaxDate => mz_expr::AggregateFunc::MaxDate,
AggregateFunc::MaxTimestamp => mz_expr::AggregateFunc::MaxTimestamp,
AggregateFunc::MaxTimestampTz => mz_expr::AggregateFunc::MaxTimestampTz,
AggregateFunc::MaxInterval => mz_expr::AggregateFunc::MaxInterval,
AggregateFunc::MaxTime => mz_expr::AggregateFunc::MaxTime,
AggregateFunc::MinNumeric => mz_expr::AggregateFunc::MinNumeric,
AggregateFunc::MinInt16 => mz_expr::AggregateFunc::MinInt16,
AggregateFunc::MinInt32 => mz_expr::AggregateFunc::MinInt32,
AggregateFunc::MinInt64 => mz_expr::AggregateFunc::MinInt64,
AggregateFunc::MinUInt16 => mz_expr::AggregateFunc::MinUInt16,
AggregateFunc::MinUInt32 => mz_expr::AggregateFunc::MinUInt32,
AggregateFunc::MinUInt64 => mz_expr::AggregateFunc::MinUInt64,
AggregateFunc::MinMzTimestamp => mz_expr::AggregateFunc::MinMzTimestamp,
AggregateFunc::MinFloat32 => mz_expr::AggregateFunc::MinFloat32,
AggregateFunc::MinFloat64 => mz_expr::AggregateFunc::MinFloat64,
AggregateFunc::MinBool => mz_expr::AggregateFunc::MinBool,
AggregateFunc::MinString => mz_expr::AggregateFunc::MinString,
AggregateFunc::MinDate => mz_expr::AggregateFunc::MinDate,
AggregateFunc::MinTimestamp => mz_expr::AggregateFunc::MinTimestamp,
AggregateFunc::MinTimestampTz => mz_expr::AggregateFunc::MinTimestampTz,
AggregateFunc::MinInterval => mz_expr::AggregateFunc::MinInterval,
AggregateFunc::MinTime => mz_expr::AggregateFunc::MinTime,
AggregateFunc::SumInt16 => mz_expr::AggregateFunc::SumInt16,
AggregateFunc::SumInt32 => mz_expr::AggregateFunc::SumInt32,
AggregateFunc::SumInt64 => mz_expr::AggregateFunc::SumInt64,
AggregateFunc::SumUInt16 => mz_expr::AggregateFunc::SumUInt16,
AggregateFunc::SumUInt32 => mz_expr::AggregateFunc::SumUInt32,
AggregateFunc::SumUInt64 => mz_expr::AggregateFunc::SumUInt64,
AggregateFunc::SumFloat32 => mz_expr::AggregateFunc::SumFloat32,
AggregateFunc::SumFloat64 => mz_expr::AggregateFunc::SumFloat64,
AggregateFunc::SumNumeric => mz_expr::AggregateFunc::SumNumeric,
AggregateFunc::Count => mz_expr::AggregateFunc::Count,
AggregateFunc::Any => mz_expr::AggregateFunc::Any,
AggregateFunc::All => mz_expr::AggregateFunc::All,
AggregateFunc::JsonbAgg { order_by } => mz_expr::AggregateFunc::JsonbAgg { order_by },
AggregateFunc::JsonbObjectAgg { order_by } => {
mz_expr::AggregateFunc::JsonbObjectAgg { order_by }
}
AggregateFunc::MapAgg {
order_by,
value_type,
} => mz_expr::AggregateFunc::MapAgg {
order_by,
value_type,
},
AggregateFunc::ArrayConcat { order_by } => {
mz_expr::AggregateFunc::ArrayConcat { order_by }
}
AggregateFunc::ListConcat { order_by } => {
mz_expr::AggregateFunc::ListConcat { order_by }
}
AggregateFunc::StringAgg { order_by } => mz_expr::AggregateFunc::StringAgg { order_by },
AggregateFunc::Dummy => mz_expr::AggregateFunc::Dummy,
}
}
pub fn identity_datum(&self) -> Datum<'static> {
match self {
AggregateFunc::Any => Datum::False,
AggregateFunc::All => Datum::True,
AggregateFunc::Dummy => Datum::Dummy,
AggregateFunc::ArrayConcat { .. } => Datum::empty_array(),
AggregateFunc::ListConcat { .. } => Datum::empty_list(),
_ => Datum::Null,
}
}
pub fn output_type(&self, input_type: ColumnType) -> ColumnType {
let scalar_type = match self {
AggregateFunc::Count => ScalarType::Int64,
AggregateFunc::Any => ScalarType::Bool,
AggregateFunc::All => ScalarType::Bool,
AggregateFunc::JsonbAgg { .. } => ScalarType::Jsonb,
AggregateFunc::JsonbObjectAgg { .. } => ScalarType::Jsonb,
AggregateFunc::StringAgg { .. } => ScalarType::String,
AggregateFunc::SumInt16 | AggregateFunc::SumInt32 => ScalarType::Int64,
AggregateFunc::SumInt64 => ScalarType::Numeric {
max_scale: Some(NumericMaxScale::ZERO),
},
AggregateFunc::SumUInt16 | AggregateFunc::SumUInt32 => ScalarType::UInt64,
AggregateFunc::SumUInt64 => ScalarType::Numeric {
max_scale: Some(NumericMaxScale::ZERO),
},
AggregateFunc::MapAgg { value_type, .. } => ScalarType::Map {
value_type: Box::new(value_type.clone()),
custom_id: None,
},
AggregateFunc::ArrayConcat { .. } | AggregateFunc::ListConcat { .. } => {
match input_type.scalar_type {
ScalarType::Record { fields, .. } => fields[0].1.scalar_type.clone(),
_ => unreachable!(),
}
}
_ => input_type.scalar_type,
};
let nullable = !matches!(self, AggregateFunc::Count);
scalar_type.nullable(nullable)
}
pub fn is_order_sensitive(&self) -> bool {
use AggregateFunc::*;
matches!(
self,
JsonbAgg { .. }
| JsonbObjectAgg { .. }
| MapAgg { .. }
| ArrayConcat { .. }
| ListConcat { .. }
| StringAgg { .. }
)
}
}
impl HirRelationExpr {
pub fn typ(
&self,
outers: &[RelationType],
params: &BTreeMap<usize, ScalarType>,
) -> RelationType {
stack::maybe_grow(|| match self {
HirRelationExpr::Constant { typ, .. } => typ.clone(),
HirRelationExpr::Get { typ, .. } => typ.clone(),
HirRelationExpr::Let { body, .. } => body.typ(outers, params),
HirRelationExpr::LetRec { body, .. } => body.typ(outers, params),
HirRelationExpr::Project { input, outputs } => {
let input_typ = input.typ(outers, params);
RelationType::new(
outputs
.iter()
.map(|&i| input_typ.column_types[i].clone())
.collect(),
)
}
HirRelationExpr::Map { input, scalars } => {
let mut typ = input.typ(outers, params);
for scalar in scalars {
typ.column_types.push(scalar.typ(outers, &typ, params));
}
typ
}
HirRelationExpr::CallTable { func, exprs: _ } => func.output_type(),
HirRelationExpr::Filter { input, .. } | HirRelationExpr::TopK { input, .. } => {
input.typ(outers, params)
}
HirRelationExpr::Join {
left, right, kind, ..
} => {
let left_nullable = matches!(kind, JoinKind::RightOuter | JoinKind::FullOuter);
let right_nullable =
matches!(kind, JoinKind::LeftOuter { .. } | JoinKind::FullOuter);
let lt = left.typ(outers, params).column_types.into_iter().map(|t| {
let nullable = t.nullable || left_nullable;
t.nullable(nullable)
});
let mut outers = outers.to_vec();
outers.insert(0, RelationType::new(lt.clone().collect()));
let rt = right
.typ(&outers, params)
.column_types
.into_iter()
.map(|t| {
let nullable = t.nullable || right_nullable;
t.nullable(nullable)
});
RelationType::new(lt.chain(rt).collect())
}
HirRelationExpr::Reduce {
input,
group_key,
aggregates,
expected_group_size: _,
} => {
let input_typ = input.typ(outers, params);
let mut column_types = group_key
.iter()
.map(|&i| input_typ.column_types[i].clone())
.collect::<Vec<_>>();
for agg in aggregates {
column_types.push(agg.typ(outers, &input_typ, params));
}
RelationType::new(column_types)
}
HirRelationExpr::Distinct { input }
| HirRelationExpr::Negate { input }
| HirRelationExpr::Threshold { input } => input.typ(outers, params),
HirRelationExpr::Union { base, inputs } => {
let mut base_cols = base.typ(outers, params).column_types;
for input in inputs {
for (base_col, col) in base_cols
.iter_mut()
.zip_eq(input.typ(outers, params).column_types)
{
*base_col = base_col.union(&col).unwrap();
}
}
RelationType::new(base_cols)
}
})
}
pub fn arity(&self) -> usize {
match self {
HirRelationExpr::Constant { typ, .. } => typ.column_types.len(),
HirRelationExpr::Get { typ, .. } => typ.column_types.len(),
HirRelationExpr::Let { body, .. } => body.arity(),
HirRelationExpr::LetRec { body, .. } => body.arity(),
HirRelationExpr::Project { outputs, .. } => outputs.len(),
HirRelationExpr::Map { input, scalars } => input.arity() + scalars.len(),
HirRelationExpr::CallTable { func, .. } => func.output_arity(),
HirRelationExpr::Filter { input, .. }
| HirRelationExpr::TopK { input, .. }
| HirRelationExpr::Distinct { input }
| HirRelationExpr::Negate { input }
| HirRelationExpr::Threshold { input } => input.arity(),
HirRelationExpr::Join { left, right, .. } => left.arity() + right.arity(),
HirRelationExpr::Union { base, .. } => base.arity(),
HirRelationExpr::Reduce {
group_key,
aggregates,
..
} => group_key.len() + aggregates.len(),
}
}
pub fn as_const(&self) -> Option<(&Vec<Row>, &RelationType)> {
match self {
Self::Constant { rows, typ } => Some((rows, typ)),
_ => None,
}
}
pub fn is_correlated(&self) -> bool {
let mut correlated = false;
#[allow(deprecated)]
self.visit_columns(0, &mut |depth, col| {
if col.level > depth && col.level - depth == 1 {
correlated = true;
}
});
correlated
}
pub fn is_join_identity(&self) -> bool {
match self {
HirRelationExpr::Constant { rows, .. } => rows.len() == 1 && self.arity() == 0,
_ => false,
}
}
pub fn project(self, outputs: Vec<usize>) -> Self {
if outputs.iter().copied().eq(0..self.arity()) {
self
} else {
HirRelationExpr::Project {
input: Box::new(self),
outputs,
}
}
}
pub fn map(mut self, scalars: Vec<HirScalarExpr>) -> Self {
if scalars.is_empty() {
self
} else if let HirRelationExpr::Map {
scalars: old_scalars,
input: _,
} = &mut self
{
old_scalars.extend(scalars);
self
} else {
HirRelationExpr::Map {
input: Box::new(self),
scalars,
}
}
}
pub fn filter(mut self, mut preds: Vec<HirScalarExpr>) -> Self {
if let HirRelationExpr::Filter {
input: _,
predicates,
} = &mut self
{
predicates.extend(preds);
predicates.sort();
predicates.dedup();
self
} else {
preds.sort();
preds.dedup();
HirRelationExpr::Filter {
input: Box::new(self),
predicates: preds,
}
}
}
pub fn reduce(
self,
group_key: Vec<usize>,
aggregates: Vec<AggregateExpr>,
expected_group_size: Option<u64>,
) -> Self {
HirRelationExpr::Reduce {
input: Box::new(self),
group_key,
aggregates,
expected_group_size,
}
}
pub fn top_k(
self,
group_key: Vec<usize>,
order_key: Vec<ColumnOrder>,
limit: Option<HirScalarExpr>,
offset: usize,
expected_group_size: Option<u64>,
) -> Self {
HirRelationExpr::TopK {
input: Box::new(self),
group_key,
order_key,
limit,
offset,
expected_group_size,
}
}
pub fn negate(self) -> Self {
if let HirRelationExpr::Negate { input } = self {
*input
} else {
HirRelationExpr::Negate {
input: Box::new(self),
}
}
}
pub fn distinct(self) -> Self {
if let HirRelationExpr::Distinct { .. } = self {
self
} else {
HirRelationExpr::Distinct {
input: Box::new(self),
}
}
}
pub fn threshold(self) -> Self {
if let HirRelationExpr::Threshold { .. } = self {
self
} else {
HirRelationExpr::Threshold {
input: Box::new(self),
}
}
}
pub fn union(self, other: Self) -> Self {
let mut terms = Vec::new();
if let HirRelationExpr::Union { base, inputs } = self {
terms.push(*base);
terms.extend(inputs);
} else {
terms.push(self);
}
if let HirRelationExpr::Union { base, inputs } = other {
terms.push(*base);
terms.extend(inputs);
} else {
terms.push(other);
}
HirRelationExpr::Union {
base: Box::new(terms.remove(0)),
inputs: terms,
}
}
pub fn exists(self) -> HirScalarExpr {
HirScalarExpr::Exists(Box::new(self))
}
pub fn select(self) -> HirScalarExpr {
HirScalarExpr::Select(Box::new(self))
}
pub fn join(
self,
mut right: HirRelationExpr,
on: HirScalarExpr,
kind: JoinKind,
) -> HirRelationExpr {
if self.is_join_identity() && !right.is_correlated() && on == HirScalarExpr::literal_true()
{
#[allow(deprecated)]
right.visit_columns_mut(0, &mut |depth, col| {
if col.level > depth {
col.level -= 1;
}
});
right
} else if right.is_join_identity() && on == HirScalarExpr::literal_true() {
self
} else {
HirRelationExpr::Join {
left: Box::new(self),
right: Box::new(right),
on,
kind,
}
}
}
pub fn take(&mut self) -> HirRelationExpr {
mem::replace(
self,
HirRelationExpr::constant(vec![], RelationType::new(Vec::new())),
)
}
#[deprecated = "Use `Visit::visit_post`."]
pub fn visit<'a, F>(&'a self, depth: usize, f: &mut F)
where
F: FnMut(&'a Self, usize),
{
#[allow(deprecated)]
let _ = self.visit_fallible(depth, &mut |e: &HirRelationExpr,
depth: usize|
-> Result<(), ()> {
f(e, depth);
Ok(())
});
}
#[deprecated = "Use `Visit::try_visit_post`."]
pub fn visit_fallible<'a, F, E>(&'a self, depth: usize, f: &mut F) -> Result<(), E>
where
F: FnMut(&'a Self, usize) -> Result<(), E>,
{
#[allow(deprecated)]
self.visit1(depth, |e: &HirRelationExpr, depth: usize| {
e.visit_fallible(depth, f)
})?;
f(self, depth)
}
#[deprecated = "Use `VisitChildren<HirRelationExpr>::try_visit_children` instead."]
pub fn visit1<'a, F, E>(&'a self, depth: usize, mut f: F) -> Result<(), E>
where
F: FnMut(&'a Self, usize) -> Result<(), E>,
{
match self {
HirRelationExpr::Constant { .. }
| HirRelationExpr::Get { .. }
| HirRelationExpr::CallTable { .. } => (),
HirRelationExpr::Let { body, value, .. } => {
f(value, depth)?;
f(body, depth)?;
}
HirRelationExpr::LetRec {
limit: _,
bindings,
body,
} => {
for (_, _, value, _) in bindings.iter() {
f(value, depth)?;
}
f(body, depth)?;
}
HirRelationExpr::Project { input, .. } => {
f(input, depth)?;
}
HirRelationExpr::Map { input, .. } => {
f(input, depth)?;
}
HirRelationExpr::Filter { input, .. } => {
f(input, depth)?;
}
HirRelationExpr::Join { left, right, .. } => {
f(left, depth)?;
f(right, depth + 1)?;
}
HirRelationExpr::Reduce { input, .. } => {
f(input, depth)?;
}
HirRelationExpr::Distinct { input } => {
f(input, depth)?;
}
HirRelationExpr::TopK { input, .. } => {
f(input, depth)?;
}
HirRelationExpr::Negate { input } => {
f(input, depth)?;
}
HirRelationExpr::Threshold { input } => {
f(input, depth)?;
}
HirRelationExpr::Union { base, inputs } => {
f(base, depth)?;
for input in inputs {
f(input, depth)?;
}
}
}
Ok(())
}
#[deprecated = "Use `Visit::visit_mut_post` instead."]
pub fn visit_mut<F>(&mut self, depth: usize, f: &mut F)
where
F: FnMut(&mut Self, usize),
{
#[allow(deprecated)]
let _ = self.visit_mut_fallible(depth, &mut |e: &mut HirRelationExpr,
depth: usize|
-> Result<(), ()> {
f(e, depth);
Ok(())
});
}
#[deprecated = "Use `Visit::try_visit_mut_post` instead."]
pub fn visit_mut_fallible<F, E>(&mut self, depth: usize, f: &mut F) -> Result<(), E>
where
F: FnMut(&mut Self, usize) -> Result<(), E>,
{
#[allow(deprecated)]
self.visit1_mut(depth, |e: &mut HirRelationExpr, depth: usize| {
e.visit_mut_fallible(depth, f)
})?;
f(self, depth)
}
#[deprecated = "Use `VisitChildren<HirRelationExpr>::try_visit_mut_children` instead."]
pub fn visit1_mut<'a, F, E>(&'a mut self, depth: usize, mut f: F) -> Result<(), E>
where
F: FnMut(&'a mut Self, usize) -> Result<(), E>,
{
match self {
HirRelationExpr::Constant { .. }
| HirRelationExpr::Get { .. }
| HirRelationExpr::CallTable { .. } => (),
HirRelationExpr::Let { body, value, .. } => {
f(value, depth)?;
f(body, depth)?;
}
HirRelationExpr::LetRec {
limit: _,
bindings,
body,
} => {
for (_, _, value, _) in bindings.iter_mut() {
f(value, depth)?;
}
f(body, depth)?;
}
HirRelationExpr::Project { input, .. } => {
f(input, depth)?;
}
HirRelationExpr::Map { input, .. } => {
f(input, depth)?;
}
HirRelationExpr::Filter { input, .. } => {
f(input, depth)?;
}
HirRelationExpr::Join { left, right, .. } => {
f(left, depth)?;
f(right, depth + 1)?;
}
HirRelationExpr::Reduce { input, .. } => {
f(input, depth)?;
}
HirRelationExpr::Distinct { input } => {
f(input, depth)?;
}
HirRelationExpr::TopK { input, .. } => {
f(input, depth)?;
}
HirRelationExpr::Negate { input } => {
f(input, depth)?;
}
HirRelationExpr::Threshold { input } => {
f(input, depth)?;
}
HirRelationExpr::Union { base, inputs } => {
f(base, depth)?;
for input in inputs {
f(input, depth)?;
}
}
}
Ok(())
}
#[deprecated = "Use a combination of `Visit` and `VisitChildren` methods."]
pub fn visit_scalar_expressions<F, E>(&self, depth: usize, f: &mut F) -> Result<(), E>
where
F: FnMut(&HirScalarExpr, usize) -> Result<(), E>,
{
#[allow(deprecated)]
self.visit_fallible(depth, &mut |e: &HirRelationExpr,
depth: usize|
-> Result<(), E> {
match e {
HirRelationExpr::Join { on, .. } => {
f(on, depth)?;
}
HirRelationExpr::Map { scalars, .. } => {
for scalar in scalars {
f(scalar, depth)?;
}
}
HirRelationExpr::CallTable { exprs, .. } => {
for expr in exprs {
f(expr, depth)?;
}
}
HirRelationExpr::Filter { predicates, .. } => {
for predicate in predicates {
f(predicate, depth)?;
}
}
HirRelationExpr::Reduce { aggregates, .. } => {
for aggregate in aggregates {
f(&aggregate.expr, depth)?;
}
}
HirRelationExpr::TopK { limit, .. } => {
if let Some(limit) = limit {
f(limit, depth)?;
}
}
HirRelationExpr::Union { .. }
| HirRelationExpr::Let { .. }
| HirRelationExpr::LetRec { .. }
| HirRelationExpr::Project { .. }
| HirRelationExpr::Distinct { .. }
| HirRelationExpr::Negate { .. }
| HirRelationExpr::Threshold { .. }
| HirRelationExpr::Constant { .. }
| HirRelationExpr::Get { .. } => (),
}
Ok(())
})
}
#[deprecated = "Use a combination of `Visit` and `VisitChildren` methods."]
pub fn visit_scalar_expressions_mut<F, E>(&mut self, depth: usize, f: &mut F) -> Result<(), E>
where
F: FnMut(&mut HirScalarExpr, usize) -> Result<(), E>,
{
#[allow(deprecated)]
self.visit_mut_fallible(depth, &mut |e: &mut HirRelationExpr,
depth: usize|
-> Result<(), E> {
match e {
HirRelationExpr::Join { on, .. } => {
f(on, depth)?;
}
HirRelationExpr::Map { scalars, .. } => {
for scalar in scalars.iter_mut() {
f(scalar, depth)?;
}
}
HirRelationExpr::CallTable { exprs, .. } => {
for expr in exprs.iter_mut() {
f(expr, depth)?;
}
}
HirRelationExpr::Filter { predicates, .. } => {
for predicate in predicates.iter_mut() {
f(predicate, depth)?;
}
}
HirRelationExpr::Reduce { aggregates, .. } => {
for aggregate in aggregates.iter_mut() {
f(&mut aggregate.expr, depth)?;
}
}
HirRelationExpr::TopK { limit, .. } => {
if let Some(limit) = limit {
f(limit, depth)?;
}
}
HirRelationExpr::Union { .. }
| HirRelationExpr::Let { .. }
| HirRelationExpr::LetRec { .. }
| HirRelationExpr::Project { .. }
| HirRelationExpr::Distinct { .. }
| HirRelationExpr::Negate { .. }
| HirRelationExpr::Threshold { .. }
| HirRelationExpr::Constant { .. }
| HirRelationExpr::Get { .. } => (),
}
Ok(())
})
}
#[deprecated = "Redefine this based on the `Visit` and `VisitChildren` methods."]
pub fn visit_columns<F>(&self, depth: usize, f: &mut F)
where
F: FnMut(usize, &ColumnRef),
{
#[allow(deprecated)]
let _ = self.visit_scalar_expressions(depth, &mut |e: &HirScalarExpr,
depth: usize|
-> Result<(), ()> {
e.visit_columns(depth, f);
Ok(())
});
}
#[deprecated = "Redefine this based on the `Visit` and `VisitChildren` methods."]
pub fn visit_columns_mut<F>(&mut self, depth: usize, f: &mut F)
where
F: FnMut(usize, &mut ColumnRef),
{
#[allow(deprecated)]
let _ = self.visit_scalar_expressions_mut(depth, &mut |e: &mut HirScalarExpr,
depth: usize|
-> Result<(), ()> {
e.visit_columns_mut(depth, f);
Ok(())
});
}
pub fn bind_parameters(&mut self, params: &Params) -> Result<(), PlanError> {
#[allow(deprecated)]
self.visit_scalar_expressions_mut(0, &mut |e: &mut HirScalarExpr, _: usize| {
e.bind_parameters(params)
})
}
pub fn splice_parameters(&mut self, params: &[HirScalarExpr], depth: usize) {
#[allow(deprecated)]
let _ = self.visit_scalar_expressions_mut(depth, &mut |e: &mut HirScalarExpr,
depth: usize|
-> Result<(), ()> {
e.splice_parameters(params, depth);
Ok(())
});
}
pub fn constant(rows: Vec<Vec<Datum>>, typ: RelationType) -> Self {
let rows = rows
.into_iter()
.map(move |datums| Row::pack_slice(&datums))
.collect();
HirRelationExpr::Constant { rows, typ }
}
pub fn finish_maintained(
&mut self,
finishing: &mut RowSetFinishing<HirScalarExpr>,
group_size_hints: GroupSizeHints,
) {
if !finishing.is_trivial(self.arity()) {
let old_finishing =
mem::replace(finishing, RowSetFinishing::trivial(finishing.project.len()));
*self = HirRelationExpr::top_k(
std::mem::replace(
self,
HirRelationExpr::Constant {
rows: vec![],
typ: RelationType::new(Vec::new()),
},
),
vec![],
old_finishing.order_by,
old_finishing.limit,
old_finishing.offset,
group_size_hints.limit_input_group_size,
)
.project(old_finishing.project);
}
}
pub fn could_run_expensive_function(&self) -> bool {
let mut result = false;
if let Err(_) = self.visit_pre(&mut |e: &HirRelationExpr| {
use HirRelationExpr::*;
use HirScalarExpr::*;
self.visit_children(|scalar: &HirScalarExpr| {
if let Err(_) = scalar.visit_pre(&mut |scalar: &HirScalarExpr| {
result |= match scalar {
Column(_)
| Literal(_, _)
| CallUnmaterializable(_)
| If { .. }
| Parameter(..)
| Select(..)
| Exists(..) => false,
CallUnary { .. }
| CallBinary { .. }
| CallVariadic { .. }
| Windowing(..) => true,
};
}) {
result = true;
}
});
result |= matches!(e, CallTable { .. } | Reduce { .. });
}) {
result = true;
}
result
}
pub fn contains_temporal(&self) -> Result<bool, RecursionLimitError> {
let mut contains = false;
self.visit_post(&mut |expr| {
expr.visit_children(|expr: &HirScalarExpr| {
contains = contains || expr.contains_temporal()
})
})?;
Ok(contains)
}
}
impl CollectionPlan for HirRelationExpr {
fn depends_on_into(&self, out: &mut BTreeSet<GlobalId>) {
if let Self::Get {
id: Id::Global(id), ..
} = self
{
out.insert(*id);
}
self.visit_children(|expr: &HirRelationExpr| expr.depends_on_into(out))
}
}
impl VisitChildren<Self> for HirRelationExpr {
fn visit_children<F>(&self, mut f: F)
where
F: FnMut(&Self),
{
VisitChildren::visit_children(self, |expr: &HirScalarExpr| {
#[allow(deprecated)]
Visit::visit_post_nolimit(expr, &mut |expr| match expr {
HirScalarExpr::Exists(expr) | HirScalarExpr::Select(expr) => f(expr.as_ref()),
_ => (),
});
});
use HirRelationExpr::*;
match self {
Constant { rows: _, typ: _ } | Get { id: _, typ: _ } => (),
Let {
name: _,
id: _,
value,
body,
} => {
f(value);
f(body);
}
LetRec {
limit: _,
bindings,
body,
} => {
for (_, _, value, _) in bindings.iter() {
f(value);
}
f(body);
}
Project { input, outputs: _ } => f(input),
Map { input, scalars: _ } => {
f(input);
}
CallTable { func: _, exprs: _ } => (),
Filter {
input,
predicates: _,
} => {
f(input);
}
Join {
left,
right,
on: _,
kind: _,
} => {
f(left);
f(right);
}
Reduce {
input,
group_key: _,
aggregates: _,
expected_group_size: _,
} => {
f(input);
}
Distinct { input }
| TopK {
input,
group_key: _,
order_key: _,
limit: _,
offset: _,
expected_group_size: _,
}
| Negate { input }
| Threshold { input } => {
f(input);
}
Union { base, inputs } => {
f(base);
for input in inputs {
f(input);
}
}
}
}
fn visit_mut_children<F>(&mut self, mut f: F)
where
F: FnMut(&mut Self),
{
VisitChildren::visit_mut_children(self, |expr: &mut HirScalarExpr| {
#[allow(deprecated)]
Visit::visit_mut_post_nolimit(expr, &mut |expr| match expr {
HirScalarExpr::Exists(expr) | HirScalarExpr::Select(expr) => f(expr.as_mut()),
_ => (),
});
});
use HirRelationExpr::*;
match self {
Constant { rows: _, typ: _ } | Get { id: _, typ: _ } => (),
Let {
name: _,
id: _,
value,
body,
} => {
f(value);
f(body);
}
LetRec {
limit: _,
bindings,
body,
} => {
for (_, _, value, _) in bindings.iter_mut() {
f(value);
}
f(body);
}
Project { input, outputs: _ } => f(input),
Map { input, scalars: _ } => {
f(input);
}
CallTable { func: _, exprs: _ } => (),
Filter {
input,
predicates: _,
} => {
f(input);
}
Join {
left,
right,
on: _,
kind: _,
} => {
f(left);
f(right);
}
Reduce {
input,
group_key: _,
aggregates: _,
expected_group_size: _,
} => {
f(input);
}
Distinct { input }
| TopK {
input,
group_key: _,
order_key: _,
limit: _,
offset: _,
expected_group_size: _,
}
| Negate { input }
| Threshold { input } => {
f(input);
}
Union { base, inputs } => {
f(base);
for input in inputs {
f(input);
}
}
}
}
fn try_visit_children<F, E>(&self, mut f: F) -> Result<(), E>
where
F: FnMut(&Self) -> Result<(), E>,
E: From<RecursionLimitError>,
{
VisitChildren::try_visit_children(self, |expr: &HirScalarExpr| {
Visit::try_visit_post(expr, &mut |expr| match expr {
HirScalarExpr::Exists(expr) | HirScalarExpr::Select(expr) => f(expr.as_ref()),
_ => Ok(()),
})
})?;
use HirRelationExpr::*;
match self {
Constant { rows: _, typ: _ } | Get { id: _, typ: _ } => (),
Let {
name: _,
id: _,
value,
body,
} => {
f(value)?;
f(body)?;
}
LetRec {
limit: _,
bindings,
body,
} => {
for (_, _, value, _) in bindings.iter() {
f(value)?;
}
f(body)?;
}
Project { input, outputs: _ } => f(input)?,
Map { input, scalars: _ } => {
f(input)?;
}
CallTable { func: _, exprs: _ } => (),
Filter {
input,
predicates: _,
} => {
f(input)?;
}
Join {
left,
right,
on: _,
kind: _,
} => {
f(left)?;
f(right)?;
}
Reduce {
input,
group_key: _,
aggregates: _,
expected_group_size: _,
} => {
f(input)?;
}
Distinct { input }
| TopK {
input,
group_key: _,
order_key: _,
limit: _,
offset: _,
expected_group_size: _,
}
| Negate { input }
| Threshold { input } => {
f(input)?;
}
Union { base, inputs } => {
f(base)?;
for input in inputs {
f(input)?;
}
}
}
Ok(())
}
fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
where
F: FnMut(&mut Self) -> Result<(), E>,
E: From<RecursionLimitError>,
{
VisitChildren::try_visit_mut_children(self, |expr: &mut HirScalarExpr| {
Visit::try_visit_mut_post(expr, &mut |expr| match expr {
HirScalarExpr::Exists(expr) | HirScalarExpr::Select(expr) => f(expr.as_mut()),
_ => Ok(()),
})
})?;
use HirRelationExpr::*;
match self {
Constant { rows: _, typ: _ } | Get { id: _, typ: _ } => (),
Let {
name: _,
id: _,
value,
body,
} => {
f(value)?;
f(body)?;
}
LetRec {
limit: _,
bindings,
body,
} => {
for (_, _, value, _) in bindings.iter_mut() {
f(value)?;
}
f(body)?;
}
Project { input, outputs: _ } => f(input)?,
Map { input, scalars: _ } => {
f(input)?;
}
CallTable { func: _, exprs: _ } => (),
Filter {
input,
predicates: _,
} => {
f(input)?;
}
Join {
left,
right,
on: _,
kind: _,
} => {
f(left)?;
f(right)?;
}
Reduce {
input,
group_key: _,
aggregates: _,
expected_group_size: _,
} => {
f(input)?;
}
Distinct { input }
| TopK {
input,
group_key: _,
order_key: _,
limit: _,
offset: _,
expected_group_size: _,
}
| Negate { input }
| Threshold { input } => {
f(input)?;
}
Union { base, inputs } => {
f(base)?;
for input in inputs {
f(input)?;
}
}
}
Ok(())
}
}
impl VisitChildren<HirScalarExpr> for HirRelationExpr {
fn visit_children<F>(&self, mut f: F)
where
F: FnMut(&HirScalarExpr),
{
use HirRelationExpr::*;
match self {
Constant { rows: _, typ: _ }
| Get { id: _, typ: _ }
| Let {
name: _,
id: _,
value: _,
body: _,
}
| LetRec {
limit: _,
bindings: _,
body: _,
}
| Project {
input: _,
outputs: _,
} => (),
Map { input: _, scalars } => {
for scalar in scalars {
f(scalar);
}
}
CallTable { func: _, exprs } => {
for expr in exprs {
f(expr);
}
}
Filter {
input: _,
predicates,
} => {
for predicate in predicates {
f(predicate);
}
}
Join {
left: _,
right: _,
on,
kind: _,
} => f(on),
Reduce {
input: _,
group_key: _,
aggregates,
expected_group_size: _,
} => {
for aggregate in aggregates {
f(aggregate.expr.as_ref());
}
}
TopK {
input: _,
group_key: _,
order_key: _,
limit,
offset: _,
expected_group_size: _,
} => {
if let Some(limit) = limit {
f(limit)
}
}
Distinct { input: _ }
| Negate { input: _ }
| Threshold { input: _ }
| Union { base: _, inputs: _ } => (),
}
}
fn visit_mut_children<F>(&mut self, mut f: F)
where
F: FnMut(&mut HirScalarExpr),
{
use HirRelationExpr::*;
match self {
Constant { rows: _, typ: _ }
| Get { id: _, typ: _ }
| Let {
name: _,
id: _,
value: _,
body: _,
}
| LetRec {
limit: _,
bindings: _,
body: _,
}
| Project {
input: _,
outputs: _,
} => (),
Map { input: _, scalars } => {
for scalar in scalars {
f(scalar);
}
}
CallTable { func: _, exprs } => {
for expr in exprs {
f(expr);
}
}
Filter {
input: _,
predicates,
} => {
for predicate in predicates {
f(predicate);
}
}
Join {
left: _,
right: _,
on,
kind: _,
} => f(on),
Reduce {
input: _,
group_key: _,
aggregates,
expected_group_size: _,
} => {
for aggregate in aggregates {
f(aggregate.expr.as_mut());
}
}
Distinct { input: _ }
| TopK {
input: _,
group_key: _,
order_key: _,
limit: _,
offset: _,
expected_group_size: _,
}
| Negate { input: _ }
| Threshold { input: _ }
| Union { base: _, inputs: _ } => (),
}
}
fn try_visit_children<F, E>(&self, mut f: F) -> Result<(), E>
where
F: FnMut(&HirScalarExpr) -> Result<(), E>,
E: From<RecursionLimitError>,
{
use HirRelationExpr::*;
match self {
Constant { rows: _, typ: _ }
| Get { id: _, typ: _ }
| Let {
name: _,
id: _,
value: _,
body: _,
}
| LetRec {
limit: _,
bindings: _,
body: _,
}
| Project {
input: _,
outputs: _,
} => (),
Map { input: _, scalars } => {
for scalar in scalars {
f(scalar)?;
}
}
CallTable { func: _, exprs } => {
for expr in exprs {
f(expr)?;
}
}
Filter {
input: _,
predicates,
} => {
for predicate in predicates {
f(predicate)?;
}
}
Join {
left: _,
right: _,
on,
kind: _,
} => f(on)?,
Reduce {
input: _,
group_key: _,
aggregates,
expected_group_size: _,
} => {
for aggregate in aggregates {
f(aggregate.expr.as_ref())?;
}
}
Distinct { input: _ }
| TopK {
input: _,
group_key: _,
order_key: _,
limit: _,
offset: _,
expected_group_size: _,
}
| Negate { input: _ }
| Threshold { input: _ }
| Union { base: _, inputs: _ } => (),
}
Ok(())
}
fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
where
F: FnMut(&mut HirScalarExpr) -> Result<(), E>,
E: From<RecursionLimitError>,
{
use HirRelationExpr::*;
match self {
Constant { rows: _, typ: _ }
| Get { id: _, typ: _ }
| Let {
name: _,
id: _,
value: _,
body: _,
}
| LetRec {
limit: _,
bindings: _,
body: _,
}
| Project {
input: _,
outputs: _,
} => (),
Map { input: _, scalars } => {
for scalar in scalars {
f(scalar)?;
}
}
CallTable { func: _, exprs } => {
for expr in exprs {
f(expr)?;
}
}
Filter {
input: _,
predicates,
} => {
for predicate in predicates {
f(predicate)?;
}
}
Join {
left: _,
right: _,
on,
kind: _,
} => f(on)?,
Reduce {
input: _,
group_key: _,
aggregates,
expected_group_size: _,
} => {
for aggregate in aggregates {
f(aggregate.expr.as_mut())?;
}
}
Distinct { input: _ }
| TopK {
input: _,
group_key: _,
order_key: _,
limit: _,
offset: _,
expected_group_size: _,
}
| Negate { input: _ }
| Threshold { input: _ }
| Union { base: _, inputs: _ } => (),
}
Ok(())
}
}
impl HirScalarExpr {
pub fn bind_parameters(&mut self, params: &Params) -> Result<(), PlanError> {
#[allow(deprecated)]
self.visit_recursively_mut(0, &mut |_: usize, e: &mut HirScalarExpr| {
if let HirScalarExpr::Parameter(n) = e {
let datum = match params.datums.iter().nth(*n - 1) {
None => sql_bail!("there is no parameter ${}", n),
Some(datum) => datum,
};
let scalar_type = ¶ms.types[*n - 1];
let row = Row::pack([datum]);
let column_type = scalar_type.clone().nullable(datum.is_null());
*e = HirScalarExpr::Literal(row, column_type);
}
Ok(())
})
}
pub fn splice_parameters(&mut self, params: &[HirScalarExpr], depth: usize) {
#[allow(deprecated)]
let _ = self.visit_recursively_mut(depth, &mut |depth: usize,
e: &mut HirScalarExpr|
-> Result<(), ()> {
if let HirScalarExpr::Parameter(i) = e {
*e = params[*i - 1].clone();
e.visit_columns_mut(0, &mut |d: usize, col: &mut ColumnRef| {
if col.level >= d {
col.level += depth
}
});
}
Ok(())
});
}
pub fn contains_temporal(&self) -> bool {
let mut contains = false;
#[allow(deprecated)]
self.visit_post_nolimit(&mut |e| {
if let Self::CallUnmaterializable(UnmaterializableFunc::MzNow) = e {
contains = true;
}
});
contains
}
pub fn column(index: usize) -> HirScalarExpr {
HirScalarExpr::Column(ColumnRef {
level: 0,
column: index,
})
}
pub fn literal(datum: Datum, scalar_type: ScalarType) -> HirScalarExpr {
let row = Row::pack([datum]);
HirScalarExpr::Literal(row, scalar_type.nullable(datum.is_null()))
}
pub fn literal_true() -> HirScalarExpr {
HirScalarExpr::literal(Datum::True, ScalarType::Bool)
}
pub fn literal_false() -> HirScalarExpr {
HirScalarExpr::literal(Datum::False, ScalarType::Bool)
}
pub fn literal_null(scalar_type: ScalarType) -> HirScalarExpr {
HirScalarExpr::literal(Datum::Null, scalar_type)
}
pub fn literal_1d_array(
datums: Vec<Datum>,
element_scalar_type: ScalarType,
) -> Result<HirScalarExpr, PlanError> {
let scalar_type = match element_scalar_type {
ScalarType::Array(_) => {
sql_bail!("cannot build array from array type");
}
typ => ScalarType::Array(Box::new(typ)).nullable(false),
};
let mut row = Row::default();
row.packer()
.push_array(
&[ArrayDimension {
lower_bound: 1,
length: datums.len(),
}],
datums,
)
.expect("array constructed to be valid");
Ok(HirScalarExpr::Literal(row, scalar_type))
}
pub fn as_literal(&self) -> Option<Datum> {
if let HirScalarExpr::Literal(row, _column_type) = self {
Some(row.unpack_first())
} else {
None
}
}
pub fn is_literal_true(&self) -> bool {
Some(Datum::True) == self.as_literal()
}
pub fn is_literal_false(&self) -> bool {
Some(Datum::False) == self.as_literal()
}
pub fn is_literal_null(&self) -> bool {
Some(Datum::Null) == self.as_literal()
}
pub fn is_constant(&self) -> bool {
let mut worklist = vec![self];
while let Some(expr) = worklist.pop() {
match expr {
Self::Literal(_, _) => {
}
Self::CallUnary { expr, .. } => {
worklist.push(expr);
}
Self::CallBinary {
func: _,
expr1,
expr2,
} => {
worklist.push(expr1);
worklist.push(expr2);
}
Self::CallVariadic { func: _, exprs } => {
worklist.extend(exprs.iter());
}
Self::If { cond, then, els } => {
worklist.push(cond);
worklist.push(then);
worklist.push(els);
}
_ => {
return false; }
}
}
true
}
pub fn call_unary(self, func: UnaryFunc) -> Self {
HirScalarExpr::CallUnary {
func,
expr: Box::new(self),
}
}
pub fn call_binary(self, other: Self, func: BinaryFunc) -> Self {
HirScalarExpr::CallBinary {
func,
expr1: Box::new(self),
expr2: Box::new(other),
}
}
pub fn or(self, other: Self) -> Self {
HirScalarExpr::CallVariadic {
func: VariadicFunc::Or,
exprs: vec![self, other],
}
}
pub fn and(self, other: Self) -> Self {
HirScalarExpr::CallVariadic {
func: VariadicFunc::And,
exprs: vec![self, other],
}
}
pub fn not(self) -> Self {
self.call_unary(UnaryFunc::Not(func::Not))
}
pub fn call_is_null(self) -> Self {
self.call_unary(UnaryFunc::IsNull(func::IsNull))
}
pub fn variadic_and(mut args: Vec<HirScalarExpr>) -> HirScalarExpr {
match args.len() {
0 => HirScalarExpr::literal_true(), 1 => args.swap_remove(0),
_ => HirScalarExpr::CallVariadic {
func: VariadicFunc::And,
exprs: args,
},
}
}
pub fn variadic_or(mut args: Vec<HirScalarExpr>) -> HirScalarExpr {
match args.len() {
0 => HirScalarExpr::literal_false(), 1 => args.swap_remove(0),
_ => HirScalarExpr::CallVariadic {
func: VariadicFunc::Or,
exprs: args,
},
}
}
pub fn take(&mut self) -> Self {
mem::replace(self, HirScalarExpr::literal_null(ScalarType::String))
}
pub fn visit<'a, F>(&'a self, f: &mut F)
where
F: FnMut(&'a Self),
{
self.visit1(|e: &HirScalarExpr| e.visit(f));
f(self);
}
pub fn visit1<'a, F>(&'a self, mut f: F)
where
F: FnMut(&'a Self),
{
use HirScalarExpr::*;
match self {
Column(..) | Parameter(..) | Literal(..) | CallUnmaterializable(..) => (),
CallUnary { expr, .. } => f(expr),
CallBinary { expr1, expr2, .. } => {
f(expr1);
f(expr2);
}
CallVariadic { exprs, .. } => {
for expr in exprs {
f(expr);
}
}
If { cond, then, els } => {
f(cond);
f(then);
f(els);
}
Exists(..) | Select(..) => (),
Windowing(expr) => {
let _ = expr.visit_expressions(&mut |e| -> Result<(), ()> {
f(e);
Ok(())
});
}
}
}
#[deprecated = "Use `Visit::visit_post` instead."]
pub fn visit_mut<F>(&mut self, f: &mut F)
where
F: FnMut(&mut Self),
{
#[allow(deprecated)]
self.visit1_mut(|e: &mut HirScalarExpr| e.visit_mut(f));
f(self);
}
#[deprecated = "Use `Visit::visit_mut_pre` instead."]
pub fn visit_mut_pre<F>(&mut self, f: &mut F)
where
F: FnMut(&mut Self),
{
f(self);
#[allow(deprecated)]
self.visit1_mut(|e: &mut HirScalarExpr| e.visit_mut(f));
}
#[deprecated = "Use `VisitChildren<HirScalarExpr>::visit_children` instead."]
pub fn visit1_mut<F>(&mut self, mut f: F)
where
F: FnMut(&mut Self),
{
use HirScalarExpr::*;
match self {
Column(..) | Parameter(..) | Literal(..) | CallUnmaterializable(..) => (),
CallUnary { expr, .. } => f(expr),
CallBinary { expr1, expr2, .. } => {
f(expr1);
f(expr2);
}
CallVariadic { exprs, .. } => {
for expr in exprs {
f(expr);
}
}
If { cond, then, els } => {
f(cond);
f(then);
f(els);
}
Exists(..) | Select(..) => (),
Windowing(expr) => {
let _ = expr.visit_expressions_mut(&mut |e| -> Result<(), ()> {
f(e);
Ok(())
});
}
}
}
#[deprecated = "Use `Visit::visit_pre_post` instead."]
pub fn visit_pre_post<F1, F2>(&self, pre: &mut F1, post: &mut F2)
where
F1: FnMut(&Self) -> Option<Vec<&Self>>,
F2: FnMut(&Self),
{
let to_visit = pre(self);
if let Some(to_visit) = to_visit {
for e in to_visit {
e.visit_pre_post(pre, post);
}
} else {
self.visit1(|e| e.visit_pre_post(pre, post));
}
post(self);
}
#[deprecated = "Redefine this based on the `Visit` and `VisitChildren` methods."]
pub fn visit_columns<F>(&self, depth: usize, f: &mut F)
where
F: FnMut(usize, &ColumnRef),
{
#[allow(deprecated)]
let _ = self.visit_recursively(depth, &mut |depth: usize,
e: &HirScalarExpr|
-> Result<(), ()> {
if let HirScalarExpr::Column(col) = e {
f(depth, col)
}
Ok(())
});
}
#[deprecated = "Redefine this based on the `Visit` and `VisitChildren` methods."]
pub fn visit_columns_mut<F>(&mut self, depth: usize, f: &mut F)
where
F: FnMut(usize, &mut ColumnRef),
{
#[allow(deprecated)]
let _ = self.visit_recursively_mut(depth, &mut |depth: usize,
e: &mut HirScalarExpr|
-> Result<(), ()> {
if let HirScalarExpr::Column(col) = e {
f(depth, col)
}
Ok(())
});
}
#[deprecated = "Redefine this based on the `Visit` and `VisitChildren` methods."]
pub fn visit_recursively<F, E>(&self, depth: usize, f: &mut F) -> Result<(), E>
where
F: FnMut(usize, &HirScalarExpr) -> Result<(), E>,
{
match self {
HirScalarExpr::Literal(_, _)
| HirScalarExpr::Parameter(_)
| HirScalarExpr::CallUnmaterializable(_)
| HirScalarExpr::Column(_) => (),
HirScalarExpr::CallUnary { expr, .. } => expr.visit_recursively(depth, f)?,
HirScalarExpr::CallBinary { expr1, expr2, .. } => {
expr1.visit_recursively(depth, f)?;
expr2.visit_recursively(depth, f)?;
}
HirScalarExpr::CallVariadic { exprs, .. } => {
for expr in exprs {
expr.visit_recursively(depth, f)?;
}
}
HirScalarExpr::If { cond, then, els } => {
cond.visit_recursively(depth, f)?;
then.visit_recursively(depth, f)?;
els.visit_recursively(depth, f)?;
}
HirScalarExpr::Exists(expr) | HirScalarExpr::Select(expr) => {
#[allow(deprecated)]
expr.visit_scalar_expressions(depth + 1, &mut |e, depth| {
e.visit_recursively(depth, f)
})?;
}
HirScalarExpr::Windowing(expr) => {
expr.visit_expressions(&mut |e| e.visit_recursively(depth, f))?;
}
}
f(depth, self)
}
#[deprecated = "Redefine this based on the `Visit` and `VisitChildren` methods."]
pub fn visit_recursively_mut<F, E>(&mut self, depth: usize, f: &mut F) -> Result<(), E>
where
F: FnMut(usize, &mut HirScalarExpr) -> Result<(), E>,
{
match self {
HirScalarExpr::Literal(_, _)
| HirScalarExpr::Parameter(_)
| HirScalarExpr::CallUnmaterializable(_)
| HirScalarExpr::Column(_) => (),
HirScalarExpr::CallUnary { expr, .. } => expr.visit_recursively_mut(depth, f)?,
HirScalarExpr::CallBinary { expr1, expr2, .. } => {
expr1.visit_recursively_mut(depth, f)?;
expr2.visit_recursively_mut(depth, f)?;
}
HirScalarExpr::CallVariadic { exprs, .. } => {
for expr in exprs {
expr.visit_recursively_mut(depth, f)?;
}
}
HirScalarExpr::If { cond, then, els } => {
cond.visit_recursively_mut(depth, f)?;
then.visit_recursively_mut(depth, f)?;
els.visit_recursively_mut(depth, f)?;
}
HirScalarExpr::Exists(expr) | HirScalarExpr::Select(expr) => {
#[allow(deprecated)]
expr.visit_scalar_expressions_mut(depth + 1, &mut |e, depth| {
e.visit_recursively_mut(depth, f)
})?;
}
HirScalarExpr::Windowing(expr) => {
expr.visit_expressions_mut(&mut |e| e.visit_recursively_mut(depth, f))?;
}
}
f(depth, self)
}
fn simplify_to_literal(self) -> Option<Row> {
let mut expr = self.lower_uncorrelated().ok()?;
expr.reduce(&[]);
match expr {
mz_expr::MirScalarExpr::Literal(Ok(row), _) => Some(row),
_ => None,
}
}
pub fn into_literal_int64(self) -> Option<i64> {
self.simplify_to_literal().and_then(|row| {
let datum = row.unpack_first();
if datum.is_null() {
None
} else {
Some(datum.unwrap_int64())
}
})
}
pub fn into_literal_string(self) -> Option<String> {
self.simplify_to_literal().and_then(|row| {
let datum = row.unpack_first();
if datum.is_null() {
None
} else {
Some(datum.unwrap_str().to_owned())
}
})
}
pub fn into_literal_mz_timestamp(self) -> Option<Timestamp> {
self.simplify_to_literal().and_then(|row| {
let datum = row.unpack_first();
if datum.is_null() {
None
} else {
Some(datum.unwrap_mz_timestamp())
}
})
}
}
impl VisitChildren<Self> for HirScalarExpr {
fn visit_children<F>(&self, mut f: F)
where
F: FnMut(&Self),
{
use HirScalarExpr::*;
match self {
Column(..) | Parameter(..) | Literal(..) | CallUnmaterializable(..) => (),
CallUnary { expr, .. } => f(expr),
CallBinary { expr1, expr2, .. } => {
f(expr1);
f(expr2);
}
CallVariadic { exprs, .. } => {
for expr in exprs {
f(expr);
}
}
If { cond, then, els } => {
f(cond);
f(then);
f(els);
}
Exists(..) | Select(..) => (),
Windowing(expr) => expr.visit_children(f),
}
}
fn visit_mut_children<F>(&mut self, mut f: F)
where
F: FnMut(&mut Self),
{
use HirScalarExpr::*;
match self {
Column(..) | Parameter(..) | Literal(..) | CallUnmaterializable(..) => (),
CallUnary { expr, .. } => f(expr),
CallBinary { expr1, expr2, .. } => {
f(expr1);
f(expr2);
}
CallVariadic { exprs, .. } => {
for expr in exprs {
f(expr);
}
}
If { cond, then, els } => {
f(cond);
f(then);
f(els);
}
Exists(..) | Select(..) => (),
Windowing(expr) => expr.visit_mut_children(f),
}
}
fn try_visit_children<F, E>(&self, mut f: F) -> Result<(), E>
where
F: FnMut(&Self) -> Result<(), E>,
E: From<RecursionLimitError>,
{
use HirScalarExpr::*;
match self {
Column(..) | Parameter(..) | Literal(..) | CallUnmaterializable(..) => (),
CallUnary { expr, .. } => f(expr)?,
CallBinary { expr1, expr2, .. } => {
f(expr1)?;
f(expr2)?;
}
CallVariadic { exprs, .. } => {
for expr in exprs {
f(expr)?;
}
}
If { cond, then, els } => {
f(cond)?;
f(then)?;
f(els)?;
}
Exists(..) | Select(..) => (),
Windowing(expr) => expr.try_visit_children(f)?,
}
Ok(())
}
fn try_visit_mut_children<F, E>(&mut self, mut f: F) -> Result<(), E>
where
F: FnMut(&mut Self) -> Result<(), E>,
E: From<RecursionLimitError>,
{
use HirScalarExpr::*;
match self {
Column(..) | Parameter(..) | Literal(..) | CallUnmaterializable(..) => (),
CallUnary { expr, .. } => f(expr)?,
CallBinary { expr1, expr2, .. } => {
f(expr1)?;
f(expr2)?;
}
CallVariadic { exprs, .. } => {
for expr in exprs {
f(expr)?;
}
}
If { cond, then, els } => {
f(cond)?;
f(then)?;
f(els)?;
}
Exists(..) | Select(..) => (),
Windowing(expr) => expr.try_visit_mut_children(f)?,
}
Ok(())
}
}
impl AbstractExpr for HirScalarExpr {
type Type = ColumnType;
fn typ(
&self,
outers: &[RelationType],
inner: &RelationType,
params: &BTreeMap<usize, ScalarType>,
) -> Self::Type {
stack::maybe_grow(|| match self {
HirScalarExpr::Column(ColumnRef { level, column }) => {
if *level == 0 {
inner.column_types[*column].clone()
} else {
outers[*level - 1].column_types[*column].clone()
}
}
HirScalarExpr::Parameter(n) => params[n].clone().nullable(true),
HirScalarExpr::Literal(_, typ) => typ.clone(),
HirScalarExpr::CallUnmaterializable(func) => func.output_type(),
HirScalarExpr::CallUnary { expr, func } => {
func.output_type(expr.typ(outers, inner, params))
}
HirScalarExpr::CallBinary { expr1, expr2, func } => func.output_type(
expr1.typ(outers, inner, params),
expr2.typ(outers, inner, params),
),
HirScalarExpr::CallVariadic { exprs, func } => {
func.output_type(exprs.iter().map(|e| e.typ(outers, inner, params)).collect())
}
HirScalarExpr::If { cond: _, then, els } => {
let then_type = then.typ(outers, inner, params);
let else_type = els.typ(outers, inner, params);
then_type.union(&else_type).unwrap()
}
HirScalarExpr::Exists(_) => ScalarType::Bool.nullable(true),
HirScalarExpr::Select(expr) => {
let mut outers = outers.to_vec();
outers.insert(0, inner.clone());
expr.typ(&outers, params)
.column_types
.into_element()
.nullable(true)
}
HirScalarExpr::Windowing(expr) => expr.func.typ(outers, inner, params),
})
}
}
impl AggregateExpr {
pub fn bind_parameters(&mut self, params: &Params) -> Result<(), PlanError> {
self.expr.bind_parameters(params)
}
pub fn typ(
&self,
outers: &[RelationType],
inner: &RelationType,
params: &BTreeMap<usize, ScalarType>,
) -> ColumnType {
self.func.output_type(self.expr.typ(outers, inner, params))
}
pub fn is_count_asterisk(&self) -> bool {
if self.func != AggregateFunc::Count {
return false;
}
match &*self.expr {
HirScalarExpr::Literal(
row,
mz_repr::ColumnType {
scalar_type: mz_repr::ScalarType::Bool,
nullable: false,
},
) => row.unpack_first() == mz_repr::Datum::True,
_ => false,
}
}
}