use crate::{
db::{
executor::ExecutableAccessPlan,
index::{IndexCompilePolicy, IndexPredicateProgram, compile_index_program},
predicate::{
PredicateCapabilityContext, PredicateCapabilityProfile, PredicateProgram,
classify_predicate_capabilities,
},
query::plan::AccessPlannedQuery,
},
model::entity::{EntityModel, resolve_field_slot},
};
#[derive(Clone)]
pub(in crate::db::executor) struct ExecutionPreparation {
compiled_predicate: Option<PredicateProgram>,
conservative_mode: Option<IndexPredicateProgram>,
predicate_capability_profile: Option<PredicateCapabilityProfile>,
slot_map: Option<Vec<usize>>,
strict_mode: Option<IndexPredicateProgram>,
}
impl ExecutionPreparation {
#[must_use]
pub(in crate::db::executor) fn from_plan(
model: &'static EntityModel,
plan: &AccessPlannedQuery,
slot_map: Option<Vec<usize>>,
) -> Self {
let compiled_predicate = plan
.scalar_plan()
.predicate
.as_ref()
.map(|predicate| PredicateProgram::compile_with_model(model, predicate));
let predicate_capability_profile = match (compiled_predicate.as_ref(), slot_map.as_deref())
{
(Some(compiled_predicate), Some(slot_map)) => Some(classify_predicate_capabilities(
compiled_predicate.executable(),
PredicateCapabilityContext::index_compile(slot_map),
)),
(Some(_) | None, None) | (None, Some(_)) => None,
};
let strict_mode = match (compiled_predicate.as_ref(), slot_map.as_deref()) {
(Some(compiled_predicate), Some(slot_map)) => compile_index_program(
compiled_predicate.executable(),
slot_map,
IndexCompilePolicy::StrictAllOrNone,
),
(Some(_) | None, None) | (None, Some(_)) => None,
};
Self {
compiled_predicate,
conservative_mode: None,
predicate_capability_profile,
slot_map,
strict_mode,
}
}
#[must_use]
pub(in crate::db::executor) fn from_runtime_plan(
model: &'static EntityModel,
plan: &AccessPlannedQuery,
slot_map: Option<Vec<usize>>,
) -> Self {
let compiled_predicate = plan
.scalar_plan()
.predicate
.as_ref()
.map(|predicate| PredicateProgram::compile_with_model(model, predicate));
let conservative_mode = match (compiled_predicate.as_ref(), slot_map.as_deref()) {
(Some(compiled_predicate), Some(slot_map)) => compile_index_program(
compiled_predicate.executable(),
slot_map,
IndexCompilePolicy::ConservativeSubset,
),
(Some(_) | None, None) | (None, Some(_)) => None,
};
Self {
compiled_predicate,
conservative_mode,
predicate_capability_profile: None,
slot_map,
strict_mode: None,
}
}
#[must_use]
pub(in crate::db::executor) fn from_strict_runtime_plan(
model: &'static EntityModel,
plan: &AccessPlannedQuery,
slot_map: Option<Vec<usize>>,
) -> Self {
let compiled_predicate = plan
.scalar_plan()
.predicate
.as_ref()
.map(|predicate| PredicateProgram::compile_with_model(model, predicate));
let strict_mode = match (compiled_predicate.as_ref(), slot_map.as_deref()) {
(Some(compiled_predicate), Some(slot_map)) => compile_index_program(
compiled_predicate.executable(),
slot_map,
IndexCompilePolicy::StrictAllOrNone,
),
(Some(_) | None, None) | (None, Some(_)) => None,
};
Self {
compiled_predicate,
conservative_mode: None,
predicate_capability_profile: None,
slot_map,
strict_mode,
}
}
#[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 conservative_mode(
&self,
) -> Option<&IndexPredicateProgram> {
self.conservative_mode.as_ref()
}
#[must_use]
pub(in crate::db::executor) fn slot_map(&self) -> Option<&[usize]> {
self.slot_map.as_deref()
}
#[must_use]
pub(in crate::db::executor) const fn predicate_capability_profile(
&self,
) -> Option<PredicateCapabilityProfile> {
self.predicate_capability_profile
}
#[must_use]
pub(in crate::db::executor) const fn strict_mode(&self) -> Option<&IndexPredicateProgram> {
self.strict_mode.as_ref()
}
}
pub(in crate::db::executor) fn resolved_index_slots_for_access_path<K>(
model: &'static EntityModel,
access: &ExecutableAccessPlan<'_, K>,
) -> Option<Vec<usize>> {
let path = access.as_path()?;
let path_capabilities = path.capabilities();
let index_fields = path_capabilities.index_fields_for_slot_map()?;
let mut slots = Vec::with_capacity(index_fields.len());
for field_name in index_fields {
let slot = resolve_field_slot(model, field_name)?;
slots.push(slot);
}
Some(slots)
}
pub(in crate::db::executor) fn slot_map_for_model_plan(
model: &'static EntityModel,
plan: &AccessPlannedQuery,
) -> Option<Vec<usize>> {
resolved_index_slots_for_access_path(model, plan.access.resolve_strategy().executable())
}