Skip to main content

citadel_sql/executor/
compile.rs

1use std::sync::Arc;
2
3use citadel::Database;
4use citadel_txn::read_txn::ReadTxn;
5use citadel_txn::write_txn::WriteTxn;
6
7use crate::error::Result;
8use crate::parser::Statement;
9use crate::schema::SchemaManager;
10use crate::types::{ExecutionResult, QueryResult, Value};
11
12pub enum ActiveTxnRef<'a, 'db: 'a> {
13    None,
14    Read(&'a mut ReadTxn<'db>),
15    Write(&'a mut WriteTxn<'db>),
16}
17
18pub trait CompiledPlan: Send + Sync {
19    fn execute(
20        &self,
21        db: &Database,
22        schema: &SchemaManager,
23        stmt: &Statement,
24        params: &[Value],
25        txn: ActiveTxnRef<'_, '_>,
26    ) -> Result<ExecutionResult>;
27
28    /// Attempt to produce a streaming row source. Returns `None` if this plan
29    /// cannot stream the given statement — caller falls back to `execute`.
30    fn try_stream<'db>(
31        &self,
32        _db: &'db Database,
33        _schema: &SchemaManager,
34        _stmt: &Statement,
35        _params: &[Value],
36    ) -> Option<Box<dyn RowSourceIter + 'db>> {
37        None
38    }
39
40    /// Zero-copy materialized collect; `None` if the plan cannot fast-collect.
41    fn try_collect(
42        &self,
43        _db: &Database,
44        _schema: &SchemaManager,
45        _stmt: &Statement,
46        _params: &[Value],
47    ) -> Option<Result<QueryResult>> {
48        None
49    }
50
51    /// `false` when `execute` reads `params` directly without `resolve_scoped_param`,
52    /// letting the caller skip `with_scoped_params`.
53    fn uses_scoped_params(&self) -> bool {
54        true
55    }
56
57    /// `false` when the plan never reads the txn clock (no NOW(),
58    /// CURRENT_TIMESTAMP, etc.). Lets the caller skip the
59    /// `with_txn_clock` thread-local wrapper.
60    fn needs_txn_clock(&self) -> bool {
61        true
62    }
63}
64
65/// Internal trait: object-safe streaming source over decoded rows.
66pub trait RowSourceIter {
67    fn next_row(&mut self) -> Result<Option<Vec<Value>>>;
68    fn columns(&self) -> &[String];
69    /// Upper bound on remaining rows, for output pre-sizing. 0 = unknown.
70    fn size_hint(&self) -> usize {
71        0
72    }
73}
74
75pub fn compile(schema: &SchemaManager, stmt: &Statement) -> Option<Arc<dyn CompiledPlan>> {
76    match stmt {
77        Statement::Select(sq) => super::select::CompiledSelect::try_compile(schema, sq)
78            .map(|c| Arc::new(c) as Arc<dyn CompiledPlan>),
79        Statement::Insert(ins) => super::dml::CompiledInsert::try_compile(schema, ins)
80            .map(|c| Arc::new(c) as Arc<dyn CompiledPlan>),
81        Statement::Update(upd) => super::write::CompiledUpdate::try_compile(schema, upd)
82            .ok()
83            .flatten()
84            .map(|c| Arc::new(c) as Arc<dyn CompiledPlan>),
85        Statement::Delete(del) => super::dml::CompiledDelete::try_compile(schema, del)
86            .map(|c| Arc::new(c) as Arc<dyn CompiledPlan>),
87        _ => None,
88    }
89}
90
91#[cfg(test)]
92#[path = "compile_tests.rs"]
93mod tests;