pub struct LiteralConstraints;
Expand description
Convert literal constraints into IndexedFilter
joins.
Implementations§
source§impl LiteralConstraints
impl LiteralConstraints
fn action( &self, relation: &mut MirRelationExpr, transform_ctx: &mut TransformCtx<'_>, ) -> Result<(), TransformError>
sourcefn detect_literal_constraints(
mfp: &MapFilterProject,
get_id: GlobalId,
transform_ctx: &mut TransformCtx<'_>,
) -> Option<(GlobalId, Vec<MirScalarExpr>, Vec<Row>)>
fn detect_literal_constraints( mfp: &MapFilterProject, get_id: GlobalId, transform_ctx: &mut TransformCtx<'_>, ) -> Option<(GlobalId, Vec<MirScalarExpr>, Vec<Row>)>
Detects literal constraints in an MFP on top of a Get of id
, and a matching index that can
be used to speed up the Filter of the MFP.
For example, if there is an index on (f1, f2)
, and the Filter is
(f1 = 3 AND f2 = 5) OR (f1 = 7 AND f2 = 9)
, it returns Some([f1, f2], [[3,5], [7,9]])
.
We can use an index if each argument of the OR includes a literal constraint on each of the key fields of the index. Extra predicates inside the OR arguments are ok.
Returns (idx_id, idx_key, values to lookup in the index).
sourcefn remove_literal_constraints(
mfp: &mut MapFilterProject,
key: &Vec<MirScalarExpr>,
) -> bool
fn remove_literal_constraints( mfp: &mut MapFilterProject, key: &Vec<MirScalarExpr>, ) -> bool
Removes the expressions that LiteralConstraints::detect_literal_constraints found, if
possible. Returns whether it removed anything.
For example, if the key of the detected literal constraint is just f1
, and we have the
expression
(f1 = 3 AND f2 = 5) OR (f1 = 7 AND f2 = 5)
, then this modifies it to f2 = 5
.
However, if OR branches differ in their non-key parts, then we cannot remove the literal
constraint. For example,
(f1 = 3 AND f2 = 5) OR (f1 = 7 AND f2 = 555)
, then we cannot remove the f1
parts,
because then the filter wouldn’t know whether to check f2 = 5
or f2 = 555
.
sourcefn remove_impossible_or_args(
mfp: &mut MapFilterProject,
) -> Result<bool, RecursionLimitError>
fn remove_impossible_or_args( mfp: &mut MapFilterProject, ) -> Result<bool, RecursionLimitError>
- Removes such OR args in which there are contradicting literal constraints.
- Also, if an OR arg doesn’t have any contradiction, this fn just deduplicates the AND arg list of that OR arg. (Might additionally sort all AND arg lists.)
Returns whether it performed any removal or deduplication.
Example for 1:
<arg1> OR (a = 5 AND a = 5 AND a = 8) OR <arg3>
–>
<arg1> OR <arg3>
Example for 2:
<arg1> OR (a = 5 AND a = 5 AND b = 8) OR <arg3>
–>
<arg1> OR (a = 5 AND b = 8) OR <arg3>
sourcefn get_or_args(mfp: &MapFilterProject) -> Vec<MirScalarExpr>
fn get_or_args(mfp: &MapFilterProject) -> Vec<MirScalarExpr>
Returns the arguments of the predicate’s top-level OR as a Vec. If there is no top-level OR, then interpret the predicate as a 1-arg OR, i.e., return a 1-element Vec.
Assumes that LiteralConstraints::list_of_predicates_to_and_of_predicates has already run.
sourcefn inline_literal_constraints(mfp: &mut MapFilterProject)
fn inline_literal_constraints(mfp: &mut MapFilterProject)
Makes the job of LiteralConstraints::detect_literal_constraints easier by undoing some CSE to reconstruct literal constraints.
sourcefn list_of_predicates_to_and_of_predicates(mfp: &mut MapFilterProject)
fn list_of_predicates_to_and_of_predicates(mfp: &mut MapFilterProject)
MFPs have a Vec of predicates [p1, p2, ...]
, which logically represents p1 AND p2 AND ...
.
This function performs this conversion. Note that it might create a variadic AND with
0 or 1 args, so the resulting predicate Vec always has exactly 1 element.
sourcefn canonicalize_predicates(
mfp: &mut MapFilterProject,
relation: &MirRelationExpr,
)
fn canonicalize_predicates( mfp: &mut MapFilterProject, relation: &MirRelationExpr, )
Call mz_expr::canonicalize::canonicalize_predicates on each of the predicates in the MFP.
sourcefn distribute_and_over_or(
mfp: &mut MapFilterProject,
) -> Result<(), RecursionLimitError>
fn distribute_and_over_or( mfp: &mut MapFilterProject, ) -> Result<(), RecursionLimitError>
Distribute AND over OR + do flatten_and_or until fixed point. This effectively converts to disjunctive normal form (DNF) (i.e., an OR of ANDs), because MirScalarExpr::reduce did Demorgans and double-negation-elimination. So after MirScalarExpr::reduce, we get here a tree of AND/OR nodes. A distribution step lifts an OR up the tree by 1 level, and a MirScalarExpr::flatten_associative merges two ORs that are at adjacent levels, so eventually we’ll end up with just one OR that is at the top of the tree, with ANDs below it. For example: (a || b) && (c || d) -> ((a || b) && c) || ((a || b) && d) -> (a && c) || (b && c) || (a && d) || (b && d) (This is a variadic OR with 4 arguments.)
Example:
User wrote WHERE (a,b) IN ((1,2), (1,4), (8,5))
,
from which MirScalarExpr::undistribute_and_or made this before us:
(#0 = 1 AND (#1 = 2 OR #1 = 4)) OR (#0 = 8 AND #1 = 5)
And now we distribute the first AND over the first OR in 2 steps: First to
((#0 = 1 AND #1 = 2) OR (#0 = 1 AND #1 = 4)) OR (#0 = 8 AND #1 = 5)
then MirScalarExpr::flatten_associative:
(#0 = 1 AND #1 = 2) OR (#0 = 1 AND #1 = 4) OR (#0 = 8 AND #1 = 5)
Note that MirScalarExpr::undistribute_and_or is not exactly an inverse to this because
- it can undistribute both AND over OR and OR over AND.
- it cannot always undo the distribution, because an expression might have multiple overlapping undistribution opportunities, see comment there.
sourcefn unary_and(mfp: &mut MapFilterProject)
fn unary_and(mfp: &mut MapFilterProject)
For each of the arguments of the top-level OR (if no top-level OR, then interpret the whole expression as a 1-arg OR, see LiteralConstraints::get_or_args), check if it’s an AND, and if not, then wrap it in a 1-arg AND.
fn predicates_size(mfp: &MapFilterProject) -> usize
Trait Implementations§
source§impl Debug for LiteralConstraints
impl Debug for LiteralConstraints
source§impl Transform for LiteralConstraints
impl Transform for LiteralConstraints
source§fn name(&self) -> &'static str
fn name(&self) -> &'static str
source§fn actually_perform_transform(
&self,
relation: &mut MirRelationExpr,
ctx: &mut TransformCtx<'_>,
) -> Result<(), TransformError>
fn actually_perform_transform( &self, relation: &mut MirRelationExpr, ctx: &mut TransformCtx<'_>, ) -> Result<(), TransformError>
source§fn transform(
&self,
relation: &mut MirRelationExpr,
args: &mut TransformCtx<'_>,
) -> Result<(), TransformError>
fn transform( &self, relation: &mut MirRelationExpr, args: &mut TransformCtx<'_>, ) -> Result<(), TransformError>
Auto Trait Implementations§
impl Freeze for LiteralConstraints
impl RefUnwindSafe for LiteralConstraints
impl Send for LiteralConstraints
impl Sync for LiteralConstraints
impl Unpin for LiteralConstraints
impl UnwindSafe for LiteralConstraints
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> FmtForward for T
impl<T> FmtForward for T
source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self
to use its Binary
implementation when Debug
-formatted.source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self
to use its Display
implementation when
Debug
-formatted.source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self
to use its LowerExp
implementation when
Debug
-formatted.source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self
to use its LowerHex
implementation when
Debug
-formatted.source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self
to use its Octal
implementation when Debug
-formatted.source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self
to use its Pointer
implementation when
Debug
-formatted.source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self
to use its UpperExp
implementation when
Debug
-formatted.source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self
to use its UpperHex
implementation when
Debug
-formatted.source§impl<T> FutureExt for T
impl<T> FutureExt for T
source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T
in a tonic::Request
source§impl<T, U> OverrideFrom<Option<&T>> for Uwhere
U: OverrideFrom<T>,
impl<T, U> OverrideFrom<Option<&T>> for Uwhere
U: OverrideFrom<T>,
source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moresource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moresource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self
, then passes self.as_ref()
into the pipe function.source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self
, then passes self.as_mut()
into the pipe
function.source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self
, then passes self.deref()
into the pipe function.source§impl<T> Pointable for T
impl<T> Pointable for T
source§impl<P, R> ProtoType<R> for Pwhere
R: RustType<P>,
impl<P, R> ProtoType<R> for Pwhere
R: RustType<P>,
source§fn into_rust(self) -> Result<R, TryFromProtoError>
fn into_rust(self) -> Result<R, TryFromProtoError>
RustType::from_proto
.source§fn from_rust(rust: &R) -> P
fn from_rust(rust: &R) -> P
RustType::into_proto
.source§impl<'a, S, T> Semigroup<&'a S> for Twhere
T: Semigroup<S>,
impl<'a, S, T> Semigroup<&'a S> for Twhere
T: Semigroup<S>,
source§fn plus_equals(&mut self, rhs: &&'a S)
fn plus_equals(&mut self, rhs: &&'a S)
std::ops::AddAssign
, for types that do not implement AddAssign
.source§impl<T> Tap for T
impl<T> Tap for T
source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B>
of a value. Read moresource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B>
of a value. Read moresource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R>
view of a value. Read moresource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R>
view of a value. Read moresource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target
of a value. Read moresource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target
of a value. Read moresource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap()
only in debug builds, and is erased in release builds.source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut()
only in debug builds, and is erased in release
builds.source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow()
only in debug builds, and is erased in release
builds.source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut()
only in debug builds, and is erased in release
builds.source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref()
only in debug builds, and is erased in release
builds.source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut()
only in debug builds, and is erased in release
builds.source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref()
only in debug builds, and is erased in release
builds.