pub enum MirScalarExpr {
    Column(usize),
    Literal(Result<Row, EvalError>, ColumnType),
    CallUnmaterializable(UnmaterializableFunc),
    CallUnary {
        func: UnaryFunc,
        expr: Box<MirScalarExpr>,
    },
    CallBinary {
        func: BinaryFunc,
        expr1: Box<MirScalarExpr>,
        expr2: Box<MirScalarExpr>,
    },
    CallVariadic {
        func: VariadicFunc,
        exprs: Vec<MirScalarExpr>,
    },
    If {
        cond: Box<MirScalarExpr>,
        then: Box<MirScalarExpr>,
        els: Box<MirScalarExpr>,
    },
}

Variants

Column(usize)

A column of the input row

Literal(Result<Row, EvalError>, ColumnType)

A literal value. (Stored as a row, because we can’t own a Datum)

CallUnmaterializable(UnmaterializableFunc)

A call to an unmaterializable function.

These functions cannot be evaluated by MirScalarExpr::eval. They must be transformed away by a higher layer.

CallUnary

Fields

func: UnaryFunc

A function call that takes one expression as an argument.

CallBinary

Fields

func: BinaryFunc

A function call that takes two expressions as arguments.

CallVariadic

Fields

A function call that takes an arbitrary number of arguments.

If

Fields

Conditionally evaluated expressions.

It is important that then and els only be evaluated if cond is true or not, respectively. This is the only way users can guard execution (other logical operator do not short-circuit) and we need to preserve that.

Implementations

Match AND or OR on self and get the args. If no match, then interpret self as if it were wrapped in a 1-arg AND/OR.

For a given expr, if self is <expr> = <literal> or <literal> = <expr> then return (<literal>, false). In addition to just trying to match <expr> as it is, it also tries to remove an invertible function call (such as a cast). If the match match succeeds with the inversion, then it returns (<inverted-literal>, true). For more details on the inversion, see invert_casts_on_expr_eq_literal_inner.

If self is <expr> = <literal> or <literal> = <expr> then return <expr>. It also tries to remove a cast (or other invertible function call) from <expr> before returning it, see invert_casts_on_expr_eq_literal_inner.

If the given MirScalarExpr is a literal equality where one side is an invertible function call, then calls the inverse function on both sides of the equality and returns the modified version of the given MirScalarExpr. Otherwise, it returns the original expression. For more details, see invert_casts_on_expr_eq_literal_inner.

Given an <expr> and a <literal> that were taken out from <expr> = <literal> or <literal> = <expr>, it tries to simplify the equality by applying the inverse function of the outermost function call of <expr> (if exists):

= func(<inner_expr>), where f is invertible –> <func^-1(literal)> = <inner_expr> (if func^-1(literal) doesn’t error out)

The return value is the <inner_expr> and the literal value that we get by applying the inverse function.

Tries to remove a cast (or other invertible function) in the same way as invert_casts_on_expr_eq_literal, but if calling the inverse function fails on the literal, then it deems the equality to be impossible. For example if a is a smallint column, then it catches a::integer = 1000000 to be an always false predicate (where the ::integer could have been inserted implicitly).

Determines if self is <expr> < <literal> or <expr> > <literal> or <literal> < <expr> or <literal> > <expr> or <expr> <= <literal> or <expr> >= <literal> or <literal> <= <expr> or <literal> >= <expr>.

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.

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.

If self is a column, return the column index, otherwise None.

Reduces a complex expression where possible.

Also canonicalizes the expression.

use mz_expr::MirScalarExpr;
use mz_repr::{ColumnType, Datum, ScalarType};

let expr_0 = MirScalarExpr::Column(0);
let expr_t = MirScalarExpr::literal_ok(Datum::True, ScalarType::Bool);
let expr_f = MirScalarExpr::literal_ok(Datum::False, ScalarType::Bool);

let mut test =
expr_t
    .clone()
    .and(expr_f.clone())
    .if_then_else(expr_0, expr_t.clone());

let input_type = vec![ScalarType::Int32.nullable(false)];
test.reduce(&input_type);
assert_eq!(test, expr_t);

Decompose an IsNull expression into a disjunction of simpler expressions.

Assumes that self is the expression inside of an IsNull. Returns Some(expressions) if the outer IsNull is to be replaced by some other expression. Note: if it returns None, it might still have mutated *self.

Flattens a chain of calls to associative variadic functions (For example: ORs or ANDs)

Canonicalizes AND/OR, and does some straightforward simplifications

Transforms !(a && b) into !a || !b, and !(a || b) into !a && !b

AND/OR undistribution (factoring out) to apply at each MirScalarExpr.

This method attempts to apply one of the distribution laws (in a direction opposite to the their name):

(a && b) || (a && c) --> a && (b || c)  // Undistribute-OR
(a || b) && (a || c) --> a || (b && c)  // Undistribute-AND

or one of their corresponding two absorption law special cases:

a || (a && c)  -->  a  // Absorb-OR
a && (a || c)  -->  a  // Absorb-AND

The method also works with more than 2 arguments at the top, e.g.

(a && b) || (a && c) || (a && d)  -->  a && (b || c || d)

It can also factor out only a subset of the top arguments, e.g.

(a && b) || (a && c) || (d && e)  -->  (a && (b || c)) || (d && e)

Note that sometimes there are two overlapping possibilities to factor out from, e.g.

(a && b) || (a && c) || (d && c)

Here we can factor out a from from the 1. and 2. terms, or we can factor out c from the 2. and 3. terms. One of these might lead to more/better undistribution opportunities later, but we just pick one locally, because recursively trying out all of them would lead to exponential run time.

The local heuristic is that we prefer a candidate that leads to an absorption, or if there is no such one then we simply pick the first. In case of multiple absorption candidates, it doesn’t matter which one we pick, because applying an absorption cannot adversely effect the possibility of applying other absorptions.

Assumption

Assumes that nested chains of AND/OR applications are flattened (this can be enforced with Self::flatten_associative).

Examples

Absorb-OR:

a || (a && c) || (a && d)
-->
a && (true || c || d)
-->
a && true
-->
a

Here only the first step is performed by this method. The rest is done by Self::reduce_and_canonicalize_and_or called after us in reduce().

Adds any columns that must be non-Null for self to be non-Null.

True iff the expression contains UnmaterializableFunc::MzNow.

True iff the expression contains an UnmaterializableFunc.

True iff evaluation could possibly error on non-error input Datum.

Trait Implementations

The type of parameters that arbitrary_with accepts for configuration of the generated Strategy. Parameters must implement Default. Read more
The type of Strategy used to generate values of type Self. Read more
Generates a Strategy for producing arbitrary values of type the implementing type (Self). The strategy is passed the arguments given in args. Read more
Generates a Strategy for producing arbitrary values of type the implementing type (Self). Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Deserialize this value from the given Serde deserializer. Read more
Formats the value using the given formatter. Read more
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
Adds names and types of the fields of the struct or enum to rti. Read more
This method returns an Ordering between self and other. Read more
Compares and returns the maximum of two values. Read more
Compares and returns the minimum of two values. Read more
Restrict a value to a certain interval. Read more
This method tests for self and other values to be equal, and is used by ==. Read more
This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason. Read more
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Convert a Self into a Proto value.
Consume and convert a Proto back into a Self value. Read more
Serialize this value into the given Serde serializer. Read more
Apply an infallible immutable function f to each direct child.
Apply an infallible mutable function f to each direct child.
Apply a fallible immutable function f to each direct child. Read more
Apply a fallible mutable function f to each direct child. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Formats an object with the “alternative” format ({:#}) and returns it.
Compare self to key and return true if they are equal.

Returns the argument unchanged.

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
Attaches the current Context to this type, returning a WithContext wrapper. Read more
The type of the output value.
A well-distributed integer derived from the data.
Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Instruments this type with the current Span, returning an Instrumented wrapper. Read more

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Wrap the input message T in a tonic::Request
Upcasts this ProgressEventTimestamp to Any. Read more
Returns the name of the concrete type of this object. Read more
Should always be Self
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Converts the given value to a String. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
source

fn visit_post<F>(&self, f: &mut F) -> Result<(), RecursionLimitError>where
    F: FnMut(&T),

Post-order immutable infallible visitor for self.
source

fn visit_post_nolimit<F>(&self, f: &mut F)where
    F: FnMut(&T),

👎Deprecated: Use visit_post instead.
Post-order immutable infallible visitor for self. Does not enforce a recursion limit. Read more
source

fn visit_mut_post<F>(&mut self, f: &mut F) -> Result<(), RecursionLimitError>where
    F: FnMut(&mut T),

Post-order mutable infallible visitor for self.
source

fn visit_mut_post_nolimit<F>(&mut self, f: &mut F)where
    F: FnMut(&mut T),

👎Deprecated: Use visit_mut_post instead.
Post-order mutable infallible visitor for self. Does not enforce a recursion limit. Read more
source

fn try_visit_post<F, E>(&self, f: &mut F) -> Result<(), E>where
    F: FnMut(&T) -> Result<(), E>,
    E: From<RecursionLimitError>,

Post-order immutable fallible visitor for self.
source

fn try_visit_mut_post<F, E>(&mut self, f: &mut F) -> Result<(), E>where
    F: FnMut(&mut T) -> Result<(), E>,
    E: From<RecursionLimitError>,

Post-order mutable fallible visitor for self.
Pre-order immutable infallible visitor for self.
Pre-order immutable infallible visitor for self, which also accumulates context information along the path from the root to the current node’s parent. acc_fun is a similar closure as in fold. The accumulated context is passed to the visitor, along with the current node. Read more
👎Deprecated: Use visit_pre instead.
Pre-order immutable infallible visitor for self. Does not enforce a recursion limit. Read more
Pre-order mutable infallible visitor for self.
👎Deprecated: Use visit_mut_pre instead.
Pre-order mutable infallible visitor for self. Does not enforce a recursion limit. Read more
Pre-order immutable fallible visitor for self.
Pre-order mutable fallible visitor for self.
source

fn visit_pre_post<F1, F2>(
    &self,
    pre: &mut F1,
    post: &mut F2
) -> Result<(), RecursionLimitError>where
    F1: FnMut(&T) -> Option<Vec<&T, Global>>,
    F2: FnMut(&T),

source

fn visit_pre_post_nolimit<F1, F2>(&self, pre: &mut F1, post: &mut F2)where
    F1: FnMut(&T) -> Option<Vec<&T, Global>>,
    F2: FnMut(&T),

👎Deprecated: Use visit instead.
A generalization of Visit::visit_pre and Visit::visit_post. Does not enforce a recursion limit. Read more
source

fn visit_mut_pre_post<F1, F2>(
    &mut self,
    pre: &mut F1,
    post: &mut F2
) -> Result<(), RecursionLimitError>where
    F1: FnMut(&mut T) -> Option<Vec<&mut T, Global>>,
    F2: FnMut(&mut T),

👎Deprecated: Use visit_mut instead.
source

fn visit_mut_pre_post_nolimit<F1, F2>(&mut self, pre: &mut F1, post: &mut F2)where
    F1: FnMut(&mut T) -> Option<Vec<&mut T, Global>>,
    F2: FnMut(&mut T),

👎Deprecated: Use visit_mut_pre_post instead.
A generalization of Visit::visit_mut_pre and Visit::visit_mut_post. Does not enforce a recursion limit. Read more
Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more