#[cfg(test)]
mod tests;
use crate::db::{
index::{
IndexCompilePolicy, IndexPredicateProgram, compile_index_program,
compile_index_program_for_targets,
},
predicate::{
IndexCompileTarget, PredicateCapabilityContext, PredicateCapabilityProfile,
PredicateProgram, classify_predicate_capabilities,
classify_predicate_capabilities_for_targets,
},
query::plan::{
AccessPlannedQuery, EffectiveRuntimeFilterProgram, covering_strict_predicate_compatible,
},
};
use std::borrow::Cow;
#[derive(Clone)]
pub(in crate::db::executor) struct ExecutionPreparation {
compiled_predicate: Option<PredicateProgram>,
effective_runtime_filter_program: Option<EffectiveRuntimeFilterProgram>,
compile_targets: Option<Vec<IndexCompileTarget>>,
index_program: Option<PreparedIndexProgram>,
predicate_capability_profile: Option<PredicateCapabilityProfile>,
slot_map: Option<Vec<usize>>,
}
#[derive(Clone)]
struct PreparedIndexProgram {
policy: IndexCompilePolicy,
program: Option<IndexPredicateProgram>,
}
impl PreparedIndexProgram {
fn resolve(
prepared: Option<&Self>,
policy: IndexCompilePolicy,
compile: impl FnOnce() -> Option<IndexPredicateProgram>,
) -> Option<Cow<'_, IndexPredicateProgram>> {
match prepared {
Some(prepared) if prepared.policy == policy => {
prepared.program.as_ref().map(Cow::Borrowed)
}
Some(_) | None => compile().map(Cow::Owned),
}
}
}
#[derive(Clone, Copy)]
enum PreparationPredicateSource {
ExecutionPreparation,
EffectiveRuntime,
}
#[derive(Clone, Copy)]
struct PreparationBuildConfig {
predicate_source: PreparationPredicateSource,
include_predicate_capability_profile: bool,
index_policy: Option<IndexCompilePolicy>,
}
impl ExecutionPreparation {
#[must_use]
pub(in crate::db::executor) fn from_plan(
plan: &AccessPlannedQuery,
slot_map: Option<Vec<usize>>,
) -> Self {
Self::build(
plan,
slot_map,
PreparationBuildConfig {
predicate_source: PreparationPredicateSource::ExecutionPreparation,
include_predicate_capability_profile: true,
index_policy: Some(IndexCompilePolicy::StrictAllOrNone),
},
)
}
#[must_use]
pub(in crate::db::executor) fn from_covering_route_plan(
plan: &AccessPlannedQuery,
slot_map: Option<Vec<usize>>,
) -> Self {
Self::build(
plan,
slot_map,
PreparationBuildConfig {
predicate_source: PreparationPredicateSource::ExecutionPreparation,
include_predicate_capability_profile: true,
index_policy: None,
},
)
}
#[must_use]
pub(in crate::db::executor) fn from_runtime_plan(
plan: &AccessPlannedQuery,
slot_map: Option<Vec<usize>>,
) -> Self {
Self::build(
plan,
slot_map,
PreparationBuildConfig {
predicate_source: PreparationPredicateSource::EffectiveRuntime,
include_predicate_capability_profile: false,
index_policy: Some(IndexCompilePolicy::ConservativeSubset),
},
)
}
#[must_use]
pub(in crate::db::executor) const fn compiled_predicate(&self) -> Option<&PredicateProgram> {
self.compiled_predicate.as_ref()
}
#[must_use]
pub(in crate::db::executor) const fn effective_runtime_filter_program(
&self,
) -> Option<&EffectiveRuntimeFilterProgram> {
self.effective_runtime_filter_program.as_ref()
}
#[must_use]
pub(in crate::db::executor) fn prepared_index_program(
&self,
policy: IndexCompilePolicy,
) -> Option<&IndexPredicateProgram> {
self.index_program
.as_ref()
.filter(|prepared| prepared.policy == policy)
.and_then(|prepared| prepared.program.as_ref())
}
#[must_use]
pub(in crate::db::executor) fn resolve_index_program(
&self,
policy: IndexCompilePolicy,
) -> Option<Cow<'_, IndexPredicateProgram>> {
PreparedIndexProgram::resolve(self.index_program.as_ref(), policy, || {
compile_index_program_for_preparation(
self.compiled_predicate.as_ref(),
self.compile_targets.as_deref(),
self.slot_map.as_deref(),
policy,
)
})
}
#[must_use]
pub(in crate::db::executor) const fn predicate_capability_profile(
&self,
) -> Option<PredicateCapabilityProfile> {
self.predicate_capability_profile
}
fn build(
plan: &AccessPlannedQuery,
slot_map: Option<Vec<usize>>,
config: PreparationBuildConfig,
) -> Self {
let compiled_predicate = match config.predicate_source {
PreparationPredicateSource::ExecutionPreparation => {
plan.execution_preparation_compiled_predicate().cloned()
}
PreparationPredicateSource::EffectiveRuntime => {
plan.effective_runtime_compiled_predicate().cloned()
}
};
let effective_runtime_filter_program = matches!(
config.predicate_source,
PreparationPredicateSource::EffectiveRuntime
)
.then(|| plan.effective_runtime_filter_program().cloned())
.flatten();
let compile_targets = index_compile_targets_for_model_plan(plan);
let predicate_capability_profile = if config.include_predicate_capability_profile {
predicate_capability_profile_for_preparation(
compiled_predicate.as_ref(),
compile_targets.as_deref(),
slot_map.as_deref(),
)
} else {
None
};
let index_program = config.index_policy.map(|policy| PreparedIndexProgram {
policy,
program: compile_index_program_for_preparation(
compiled_predicate.as_ref(),
compile_targets.as_deref(),
slot_map.as_deref(),
policy,
),
});
Self {
compiled_predicate,
effective_runtime_filter_program,
compile_targets,
index_program,
predicate_capability_profile,
slot_map,
}
}
}
impl std::fmt::Debug for ExecutionPreparation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("ExecutionPreparation(..)")
}
}
#[must_use]
pub(in crate::db::executor) fn covering_strict_predicate_compatible_for_plan(
plan: &AccessPlannedQuery,
) -> bool {
if !plan.has_residual_filter_predicate() {
return covering_strict_predicate_compatible(plan, None);
}
let execution_preparation =
ExecutionPreparation::from_covering_route_plan(plan, slot_map_for_model_plan(plan));
covering_strict_predicate_compatible(
plan,
execution_preparation
.predicate_capability_profile()
.map(PredicateCapabilityProfile::index),
)
}
fn predicate_capability_profile_for_preparation(
compiled_predicate: Option<&PredicateProgram>,
compile_targets: Option<&[IndexCompileTarget]>,
slot_map: Option<&[usize]>,
) -> Option<PredicateCapabilityProfile> {
match (compiled_predicate, compile_targets, slot_map) {
(Some(compiled_predicate), Some(compile_targets), _) => {
Some(classify_predicate_capabilities_for_targets(
compiled_predicate.executable(),
compile_targets,
))
}
(Some(compiled_predicate), None, Some(slot_map)) => Some(classify_predicate_capabilities(
compiled_predicate.executable(),
PredicateCapabilityContext::index_compile(slot_map),
)),
(Some(_) | None, None, None) | (None, Some(_), _) | (None, None, Some(_)) => None,
}
}
fn compile_index_program_for_preparation(
compiled_predicate: Option<&PredicateProgram>,
compile_targets: Option<&[IndexCompileTarget]>,
slot_map: Option<&[usize]>,
policy: IndexCompilePolicy,
) -> Option<IndexPredicateProgram> {
match (compiled_predicate, compile_targets, slot_map) {
(Some(compiled_predicate), Some(compile_targets), _) => compile_index_program_for_targets(
compiled_predicate.executable(),
compile_targets,
policy,
),
(Some(compiled_predicate), None, Some(slot_map)) => {
compile_index_program(compiled_predicate.executable(), slot_map, policy)
}
(Some(_) | None, None, None) | (None, Some(_), _) | (None, None, Some(_)) => None,
}
}
pub(in crate::db::executor) fn slot_map_for_model_plan(
plan: &AccessPlannedQuery,
) -> Option<Vec<usize>> {
plan.slot_map().map(<[usize]>::to_vec)
}
fn index_compile_targets_for_model_plan(
plan: &AccessPlannedQuery,
) -> Option<Vec<IndexCompileTarget>> {
plan.index_compile_targets()
.map(<[IndexCompileTarget]>::to_vec)
}
crate::retained::retained_fields!(ExecutionPreparation {
Self{compiled_predicate,effective_runtime_filter_program,compile_targets,index_program,predicate_capability_profile,slot_map} => [compiled_predicate,effective_runtime_filter_program,compile_targets,index_program,predicate_capability_profile,slot_map],
});
crate::retained::retained_fields!(PreparedIndexProgram {
Self{policy: _,program} => [program],
});