use crate::{
db::{
executor::{
ExecutableAccessPlan, LoweredIndexPrefixSpec, LoweredIndexRangeSpec,
pipeline::contracts::AccessStreamBindings, traversal::IndexRangeTraversalContract,
},
index::predicate::IndexPredicateExecution,
},
error::InternalError,
};
#[allow(clippy::struct_field_names)]
pub(in crate::db::executor) struct AccessSpecCursor<'a> {
index_prefix_specs: &'a [LoweredIndexPrefixSpec],
index_range_specs: &'a [LoweredIndexRangeSpec],
index_prefix_offset: usize,
index_range_offset: usize,
}
impl<'a> AccessSpecCursor<'a> {
#[must_use]
pub(in crate::db::executor) const fn new(
index_prefix_specs: &'a [LoweredIndexPrefixSpec],
index_range_specs: &'a [LoweredIndexRangeSpec],
) -> Self {
Self {
index_prefix_specs,
index_range_specs,
index_prefix_offset: 0,
index_range_offset: 0,
}
}
pub(in crate::db::executor) fn next_index_prefix_specs(
&mut self,
count: usize,
) -> Option<&'a [LoweredIndexPrefixSpec]> {
let start = self.index_prefix_offset;
let end = start.saturating_add(count);
let slice = self.index_prefix_specs.get(start..end)?;
self.index_prefix_offset = end;
Some(slice)
}
pub(in crate::db::executor) fn require_next_index_prefix_specs(
&mut self,
count: usize,
) -> Result<&'a [LoweredIndexPrefixSpec], InternalError> {
self.next_index_prefix_specs(count).ok_or_else(|| {
InternalError::query_executor_invariant(
"index-prefix execution requires pre-lowered specs",
)
})
}
pub(in crate::db::executor) fn next_index_range_spec(
&mut self,
) -> Option<&'a LoweredIndexRangeSpec> {
let spec = self.index_range_specs.get(self.index_range_offset);
if spec.is_some() {
self.index_range_offset = self.index_range_offset.saturating_add(1);
}
spec
}
pub(in crate::db::executor) fn require_next_index_range_spec(
&mut self,
) -> Result<&'a LoweredIndexRangeSpec, InternalError> {
IndexRangeTraversalContract::require_spec(self.next_index_range_spec())
}
pub(in crate::db::executor) fn validate_consumed(&self) -> Result<(), InternalError> {
if self.index_prefix_offset < self.index_prefix_specs.len() {
return Err(InternalError::query_executor_invariant(
"unused index-prefix executable specs after access-plan traversal",
));
}
validate_index_range_specs_consumed(self.index_range_offset, self.index_range_specs.len())?;
Ok(())
}
}
fn validate_index_range_specs_consumed(
consumed: usize,
available: usize,
) -> Result<(), InternalError> {
IndexRangeTraversalContract::validate_specs_consumed(consumed, available)
}
pub(in crate::db::executor) struct ExecutableAccess<'a, K> {
pub(in crate::db::executor) plan: ExecutableAccessPlan<'a, K>,
pub(in crate::db::executor) bindings: AccessStreamBindings<'a>,
pub(in crate::db::executor) physical_fetch_hint: Option<usize>,
pub(in crate::db::executor) index_predicate_execution: Option<IndexPredicateExecution<'a>>,
pub(in crate::db::executor) preserve_leaf_index_order: bool,
}
impl<'a, K> ExecutableAccess<'a, K> {
#[must_use]
pub(in crate::db::executor) const fn from_executable_plan(
plan: ExecutableAccessPlan<'a, K>,
bindings: AccessStreamBindings<'a>,
physical_fetch_hint: Option<usize>,
index_predicate_execution: Option<IndexPredicateExecution<'a>>,
) -> Self {
Self {
plan,
bindings,
physical_fetch_hint,
index_predicate_execution,
preserve_leaf_index_order: false,
}
}
#[must_use]
pub(in crate::db::executor) const fn with_preserved_leaf_index_order(mut self) -> Self {
self.preserve_leaf_index_order = true;
self
}
}
pub(in crate::db::executor) struct IndexStreamConstraints<'a> {
pub(in crate::db::executor) prefixes: &'a [LoweredIndexPrefixSpec],
pub(in crate::db::executor) range: Option<&'a LoweredIndexRangeSpec>,
}
pub(in crate::db::executor) struct StreamExecutionHints<'a> {
pub(in crate::db::executor) physical_fetch_hint: Option<usize>,
pub(in crate::db::executor) predicate_execution: Option<IndexPredicateExecution<'a>>,
}