quill_sql/execution/
mod.rs

1pub mod physical_plan;
2use crate::catalog::SchemaRef;
3use crate::error::{QuillSQLError, QuillSQLResult};
4use crate::execution::physical_plan::PhysicalPlan;
5use crate::expression::{Expr, ExprTrait};
6use crate::storage::{
7    engine::{StorageEngine, TableBinding},
8    table_heap::TableHeap,
9    tuple::Tuple,
10};
11use crate::transaction::{Transaction, TransactionManager, TxnContext};
12use crate::utils::scalar::ScalarValue;
13use crate::{catalog::Catalog, utils::table_ref::TableReference};
14use std::sync::Arc;
15
16pub trait VolcanoExecutor {
17    fn init(&self, _context: &mut ExecutionContext) -> QuillSQLResult<()> {
18        Ok(())
19    }
20
21    fn next(&self, context: &mut ExecutionContext) -> QuillSQLResult<Option<Tuple>>;
22
23    fn output_schema(&self) -> SchemaRef;
24}
25
26/// Shared state threaded through every physical operator during execution.
27/// Exposes MVCC helpers, storage access, expression evaluation and DDL utilities.
28pub struct ExecutionContext<'a> {
29    /// Mutable reference to the global catalog (schema + metadata).
30    pub catalog: &'a mut Catalog,
31    /// Pluggable storage engine used for heap/index access.
32    storage: Arc<dyn StorageEngine>,
33    /// Transaction runtime wrapper (snapshot, locks, undo tracking).
34    txn: TxnContext<'a>,
35}
36
37impl<'a> ExecutionContext<'a> {
38    pub fn new(
39        catalog: &'a mut Catalog,
40        txn: &'a mut Transaction,
41        txn_mgr: Arc<TransactionManager>,
42        storage: Arc<dyn StorageEngine>,
43    ) -> Self {
44        Self {
45            catalog,
46            storage,
47            txn: TxnContext::new(txn_mgr, txn),
48        }
49    }
50
51    /// Evaluate an expression expected to produce a boolean result.
52    pub fn eval_predicate(&self, expr: &Expr, tuple: &Tuple) -> QuillSQLResult<bool> {
53        match expr.evaluate(tuple)? {
54            ScalarValue::Boolean(Some(v)) => Ok(v),
55            ScalarValue::Boolean(None) => Ok(false),
56            other => Err(QuillSQLError::Execution(format!(
57                "predicate value must be boolean, got {}",
58                other
59            ))),
60        }
61    }
62
63    /// Evaluate an arbitrary scalar expression.
64    pub fn eval_expr(&self, expr: &Expr, tuple: &Tuple) -> QuillSQLResult<ScalarValue> {
65        expr.evaluate(tuple)
66    }
67
68    /// Look up the table heap through the storage engine.
69    pub fn table(&self, table: &TableReference) -> QuillSQLResult<TableBinding> {
70        self.storage.table(self.catalog, table)
71    }
72
73    pub fn table_heap(&self, table: &TableReference) -> QuillSQLResult<Arc<TableHeap>> {
74        Ok(self.table(table)?.table_heap())
75    }
76
77    pub fn txn_ctx(&self) -> &TxnContext<'a> {
78        &self.txn
79    }
80
81    pub fn txn_ctx_mut(&mut self) -> &mut TxnContext<'a> {
82        &mut self.txn
83    }
84}
85
86pub struct ExecutionEngine<'a> {
87    pub context: ExecutionContext<'a>,
88}
89impl<'a> ExecutionEngine<'a> {
90    pub fn execute(&mut self, plan: Arc<PhysicalPlan>) -> QuillSQLResult<Vec<Tuple>> {
91        plan.init(&mut self.context)?;
92        let mut result = Vec::new();
93        loop {
94            let next_tuple = plan.next(&mut self.context)?;
95            if let Some(tuple) = next_tuple {
96                result.push(tuple);
97            } else {
98                break;
99            }
100        }
101        Ok(result)
102    }
103}