Skip to main content

icydb_core/db/executor/
mod.rs

1pub(super) mod aggregate;
2mod context;
3mod cursor;
4mod delete;
5mod executable_plan;
6mod execution_plan;
7mod kernel;
8pub(super) mod load;
9mod mutation;
10mod physical_path;
11mod plan_metrics;
12pub(super) mod route;
13mod stream;
14#[cfg(test)]
15mod tests;
16mod window;
17
18pub(in crate::db) use crate::db::lowering::{LoweredIndexPrefixSpec, LoweredIndexRangeSpec};
19pub(super) use context::*;
20pub(in crate::db) use cursor::{
21    PlannedCursor, decode_pk_cursor_boundary, decode_typed_primary_key_cursor_slot, prepare_cursor,
22    revalidate_cursor, validate_index_range_anchor,
23    validate_index_range_boundary_anchor_consistency,
24};
25pub(super) use delete::DeleteExecutor;
26pub(in crate::db) use executable_plan::ExecutablePlan;
27pub(in crate::db::executor) use execution_plan::ExecutionPlan;
28pub(in crate::db::executor) use kernel::{
29    ExecutionKernel, IndexPredicateCompileMode, PlanRow, PostAccessStats,
30};
31pub(super) use load::LoadExecutor;
32pub use load::{ExecutionAccessPathVariant, ExecutionOptimization, ExecutionTrace};
33pub(super) use mutation::save::SaveExecutor;
34pub(super) use stream::access::*;
35pub(super) use stream::key::{
36    BudgetedOrderedKeyStream, KeyOrderComparator, OrderedKeyStream, OrderedKeyStreamBox,
37    VecOrderedKeyStream,
38};
39pub(in crate::db) use window::compute_page_window;
40
41// Design notes:
42// - SchemaInfo is the planner-visible schema (relational attributes). Executors may see
43//   additional tuple payload not represented in SchemaInfo.
44// - Unsupported or opaque values are treated as incomparable; executor validation may
45//   skip type checks for these values.
46// - ORDER BY is stable; incomparable values preserve input order.
47// - Corruption indicates invalid persisted bytes or store mismatches; invariant violations
48//   indicate executor/planner contract breaches.
49
50use crate::{
51    db::{
52        cursor::CursorPlanError,
53        data::DataKey,
54        plan::AccessPlannedQuery,
55        query::{
56            fluent::{delete::FluentDeleteQuery, load::FluentLoadQuery},
57            intent::{PlannedQuery, Query, QueryError},
58            plan::{OrderPlanError, PlanError},
59            predicate::PredicateFieldSlots,
60            predicate::ValidateError,
61        },
62    },
63    error::{ErrorClass, ErrorOrigin, InternalError},
64    traits::EntityKind,
65};
66use thiserror::Error as ThisError;
67
68pub(super) fn compile_predicate_slots<E: EntityKind>(
69    plan: &AccessPlannedQuery<E::Key>,
70) -> Option<PredicateFieldSlots> {
71    plan.predicate
72        .as_ref()
73        .map(PredicateFieldSlots::resolve::<E>)
74}
75
76impl<E: EntityKind> From<PlannedQuery<E>> for ExecutablePlan<E> {
77    fn from(value: PlannedQuery<E>) -> Self {
78        Self::new(value.into_inner())
79    }
80}
81
82impl<E: EntityKind> Query<E> {
83    /// Compile this logical planned query into executor runtime state.
84    pub fn plan(&self) -> Result<ExecutablePlan<E>, QueryError> {
85        self.planned().map(ExecutablePlan::from)
86    }
87}
88
89impl<E: EntityKind> FluentLoadQuery<'_, E> {
90    /// Compile this fluent load intent into executor runtime state.
91    pub fn plan(&self) -> Result<ExecutablePlan<E>, QueryError> {
92        self.planned().map(ExecutablePlan::from)
93    }
94}
95
96impl<E: EntityKind> FluentDeleteQuery<'_, E> {
97    /// Compile this fluent delete intent into executor runtime state.
98    pub fn plan(&self) -> Result<ExecutablePlan<E>, QueryError> {
99        self.planned().map(ExecutablePlan::from)
100    }
101}
102
103///
104/// ExecutorPlanError
105///
106/// Executor-owned plan-surface failures produced during runtime cursor validation.
107/// Mapped to `PlanError` only at query/session boundaries.
108///
109
110#[derive(Debug, ThisError)]
111pub(crate) enum ExecutorPlanError {
112    #[error("{0}")]
113    Predicate(Box<ValidateError>),
114
115    #[error("{0}")]
116    Order(Box<OrderPlanError>),
117
118    #[error("{0}")]
119    Cursor(Box<CursorPlanError>),
120}
121
122impl ExecutorPlanError {
123    /// Convert an executor-owned plan failure to query-owned `PlanError`.
124    #[must_use]
125    pub(crate) fn into_plan_error(self) -> PlanError {
126        match self {
127            Self::Predicate(err) => PlanError::from(*err),
128            Self::Order(err) => PlanError::from(*err),
129            Self::Cursor(err) => PlanError::from(*err),
130        }
131    }
132}
133
134impl From<ValidateError> for ExecutorPlanError {
135    fn from(err: ValidateError) -> Self {
136        Self::Predicate(Box::new(err))
137    }
138}
139
140impl From<OrderPlanError> for ExecutorPlanError {
141    fn from(err: OrderPlanError) -> Self {
142        Self::Order(Box::new(err))
143    }
144}
145
146impl From<CursorPlanError> for ExecutorPlanError {
147    fn from(err: CursorPlanError) -> Self {
148        Self::Cursor(Box::new(err))
149    }
150}
151
152///
153/// ExecutorError
154///
155
156#[derive(Debug, ThisError)]
157pub(crate) enum ExecutorError {
158    #[error("corruption detected ({origin}): {message}")]
159    Corruption {
160        origin: ErrorOrigin,
161        message: String,
162    },
163
164    #[error("data key exists: {0}")]
165    KeyExists(DataKey),
166}
167
168impl ExecutorError {
169    pub(crate) const fn class(&self) -> ErrorClass {
170        match self {
171            Self::KeyExists(_) => ErrorClass::Conflict,
172            Self::Corruption { .. } => ErrorClass::Corruption,
173        }
174    }
175
176    pub(crate) const fn origin(&self) -> ErrorOrigin {
177        match self {
178            Self::KeyExists(_) => ErrorOrigin::Store,
179            Self::Corruption { origin, .. } => *origin,
180        }
181    }
182
183    pub(crate) fn corruption(origin: ErrorOrigin, message: impl Into<String>) -> Self {
184        Self::Corruption {
185            origin,
186            message: message.into(),
187        }
188    }
189
190    // Construct a store-origin corruption error with canonical taxonomy.
191    pub(crate) fn store_corruption(message: impl Into<String>) -> Self {
192        Self::corruption(ErrorOrigin::Store, message)
193    }
194
195    // Construct a serialize-origin corruption error with canonical taxonomy.
196    pub(crate) fn serialize_corruption(message: impl Into<String>) -> Self {
197        Self::corruption(ErrorOrigin::Serialize, message)
198    }
199
200    // Construct a store-origin corruption error from displayable source context.
201    pub(crate) fn store_corruption_from(source: impl std::fmt::Display) -> Self {
202        Self::store_corruption(source.to_string())
203    }
204}
205
206impl From<ExecutorError> for InternalError {
207    fn from(err: ExecutorError) -> Self {
208        Self::classified(err.class(), err.origin(), err.to_string())
209    }
210}