use super::*;
pub(super) struct TermPath {
pub path: AccessPath,
pub on_enforced: bool,
pub remaining_on: Option<Option<BoundExpr>>,
}
pub(super) fn choose_term_path(
level: usize,
ids: &[usize],
source: &BoundSource,
select: &BoundSelect,
terms: &[BoundExpr],
consumed: &mut [bool],
levers: Levers,
) -> TermPath {
let mut on_enforced = false;
let mut remaining_on: Option<Option<BoundExpr>> = None;
let path = if is_outer(source.join) && matches!(source.rows, SourceRows::Table) {
let on_terms = if source.join == JoinKind::Left {
outer_terms(source)
} else {
Vec::new()
};
let mut on_consumed = vec![false; on_terms.len()];
let chosen = choose_path(
level,
ids,
source,
select,
&on_terms,
&mut on_consumed,
levers,
);
on_enforced = !on_terms.is_empty() && on_consumed.iter().all(|held| *held);
if source.table.module.is_some() {
remaining_on = Some(
on_terms
.iter()
.zip(&on_consumed)
.filter(|(_, held)| !**held)
.map(|(term, _)| term.clone())
.reduce(|left, right| BoundExpr::And(Box::new(left), Box::new(right))),
);
}
chosen
} else {
choose_path(level, ids, source, select, terms, consumed, levers)
};
TermPath {
path,
on_enforced,
remaining_on,
}
}
pub(super) fn hold_terms_before_right_joins(
select: &BoundSelect,
terms: &[BoundExpr],
held_before: &[Option<usize>],
consumed: &mut [bool],
sources: &mut [PlannedSource],
) {
for (index, term) in terms.iter().enumerate() {
let Some(Some(position)) = held_before.get(index) else {
continue;
};
if consumed.get(index).copied().unwrap_or(false) {
continue;
}
let Some(id) = select.sources.get(*position).map(|source| source.id) else {
continue;
};
let Some(planned) = sources.iter_mut().find(|planned| planned.id == id) else {
continue;
};
planned.before = Some(match planned.before.take() {
Some(existing) => BoundExpr::And(Box::new(existing), Box::new(term.clone())),
None => term.clone(),
});
if let Some(mark) = consumed.get_mut(index) {
*mark = true;
}
}
}
pub(super) fn derived_affinities(block: &BoundSelect) -> Vec<inillucent_value::Affinity> {
block
.columns
.iter()
.enumerate()
.map(|(at, column)| match &column.expr {
BoundExpr::Column { affinity, .. }
if *affinity != inillucent_value::Affinity::Real
|| block.column_affinity(at).is_numeric() =>
{
*affinity
}
_ => inillucent_value::Affinity::Blob,
})
.collect()
}