use parquet::arrow::arrow_reader::RowSelection;
pub(in crate::prune) use super::context::RowGroupContext;
use super::{between, bloom, cmp, in_list, is_null, page, page::PagePruning, starts_with};
use crate::ir::{IrExpr, TriState};
pub(super) fn eval_conjunction(predicates: &[IrExpr], ctx: &RowGroupContext<'_>) -> TriState {
let mut result = TriState::True;
for predicate in predicates {
result = result.and(eval_expr(predicate, ctx));
if result == TriState::False {
break;
}
}
result
}
pub(super) fn eval_expr(expr: &IrExpr, ctx: &RowGroupContext<'_>) -> TriState {
match expr {
IrExpr::True => TriState::True,
IrExpr::False => TriState::False,
IrExpr::Cmp { column, op, value } => cmp::eval_cmp(column, *op, value, ctx),
IrExpr::Between {
column,
low,
high,
inclusive,
} => between::eval_between(column, low, high, *inclusive, ctx),
IrExpr::InList { column, values } => in_list::eval_in_list(column, values, ctx),
IrExpr::BloomFilterEq { column, value } => bloom::eval_bloom_eq(column, value, ctx),
IrExpr::BloomFilterInList { column, values } => {
bloom::eval_bloom_in_list(column, values, ctx)
}
IrExpr::StartsWith { column, prefix } => starts_with::eval_starts_with(column, prefix, ctx),
IrExpr::IsNull { column, negated } => is_null::eval_is_null(column, *negated, ctx),
IrExpr::And(parts) => parts
.iter()
.fold(TriState::True, |acc, expr| acc.and(eval_expr(expr, ctx))),
IrExpr::Or(parts) => parts
.iter()
.fold(TriState::False, |acc, expr| acc.or(eval_expr(expr, ctx))),
IrExpr::Not(inner) => eval_expr(inner, ctx).not(),
}
}
pub(super) fn page_selection_for_predicates(
predicates: &[IrExpr],
ctx: &RowGroupContext<'_>,
) -> Option<RowSelection> {
let mut selection: Option<PagePruning> = None;
for predicate in predicates {
if let Some(predicate_selection) = page_selection_for_expr(predicate, ctx) {
selection = match selection {
None => Some(predicate_selection),
Some(existing) => Some(existing.intersection(predicate_selection)),
};
}
}
selection.map(|selection| selection.selection)
}
pub(super) fn page_selection_for_expr(
expr: &IrExpr,
ctx: &RowGroupContext<'_>,
) -> Option<PagePruning> {
match expr {
IrExpr::Cmp { column, op, value } => cmp::page_selection_for_cmp(column, *op, value, ctx),
IrExpr::Between {
column,
low,
high,
inclusive,
} => between::page_selection_for_between(column, low, high, *inclusive, ctx),
IrExpr::InList { column, values } => {
in_list::page_selection_for_in_list(column, values, ctx)
}
IrExpr::BloomFilterEq { .. } | IrExpr::BloomFilterInList { .. } => None,
IrExpr::StartsWith { column, prefix } => {
starts_with::page_selection_for_starts_with(column, prefix, ctx)
}
IrExpr::IsNull { column, negated } => {
is_null::page_selection_for_is_null(column, *negated, ctx)
}
IrExpr::And(parts) => {
let mut selection: Option<PagePruning> = None;
let mut all_supported = true;
for part in parts {
if let Some(part_sel) = page_selection_for_expr(part, ctx) {
selection = match selection {
None => Some(part_sel),
Some(existing) => Some(existing.intersection(part_sel)),
};
} else {
all_supported = false;
}
}
selection.map(|mut selection| {
if !all_supported {
selection.exact = false;
}
selection
})
}
IrExpr::Or(parts) => {
let mut selection: Option<PagePruning> = None;
for part in parts {
let part_sel = page_selection_for_expr(part, ctx)?; selection = match selection {
None => Some(part_sel),
Some(existing) => Some(existing.union(part_sel)),
};
}
selection
}
IrExpr::Not(inner) => {
let inner = page_selection_for_expr(inner, ctx)?;
if !inner.exact {
return None; }
let total_rows = ctx.metadata.row_group(ctx.row_group_idx).num_rows() as usize;
let selection = page::invert_selection(&inner.selection, total_rows)?;
Some(PagePruning::new(selection, true))
}
IrExpr::True | IrExpr::False => None, }
}