Skip to main content

cqlite_core/query/
mod.rs

1//! Query execution engine for CQLite
2//!
3//! This module provides the core query execution engine that bridges between
4//! CQL parsing and the storage engine. It includes:
5//!
6//! - CQL query parsing and validation
7//! - Query planning and optimization
8//! - Query execution with storage integration
9//! - Prepared statement support
10//! - Result set management
11//! - REVOLUTIONARY SELECT parser for direct SSTable access
12
13// CQL (Cassandra Query Language) Reference:
14// https://cassandra.apache.org/doc/latest/cassandra/developing/cql/cql_singlefile.html
15//
16// This implements CQL v3.4.3+ for Apache Cassandra 5.0+
17// CQL is NOT SQL - it's a query language specifically designed for Cassandra's distributed architecture.
18
19pub mod access_path;
20pub mod engine;
21pub mod executor;
22pub mod m2_select_validator;
23pub mod parser;
24pub mod planner;
25pub mod prepared;
26pub mod result;
27pub(crate) mod result_budget;
28pub mod writetime_ttl_validator;
29
30// Advanced SELECT query components
31#[cfg(feature = "state_machine")]
32pub mod select_ast;
33#[cfg(feature = "state_machine")]
34pub mod select_executor;
35#[cfg(feature = "state_machine")]
36pub mod select_integration_tests;
37#[cfg(feature = "state_machine")]
38pub mod select_naming;
39#[cfg(feature = "state_machine")]
40pub mod select_optimizer;
41#[cfg(feature = "state_machine")]
42pub mod select_parser;
43
44pub use access_path::{AccessPath, FallbackReason};
45pub use engine::{
46    AnalyzeResult, CacheStats, ExplainResult, QueryCacheEntry, QueryEngine as AdvancedQueryEngine,
47    SchemaStatus,
48};
49pub use executor::{
50    QueryExecutor, QueryResult as ExecutorQueryResult, QueryRow as ExecutorQueryRow,
51};
52pub use m2_select_validator::{M2SelectValidator, SelectValidationResult, UnsupportedFeature};
53pub use parser::QueryParser;
54pub use planner::{ExecutionStep, IndexSelection, PlanType, QueryHints, QueryPlan, QueryPlanner};
55pub use prepared::{
56    ExecutionHints, ParameterMetadata, PreparedContext, PreparedQuery, PreparedQueryBuilder,
57    PreparedQueryStats,
58};
59pub use result::{
60    cql_type_to_data_type, ColumnInfo, PerformanceMetrics, QueryMetadata, QueryResult,
61    QueryResultIterator, QueryRow, RowMetadata, StreamingConfig,
62};
63pub use writetime_ttl_validator::{
64    descriptors_from_table_schema, validate_all_writetime_ttl_calls, validate_writetime_ttl_call,
65    ColumnDescriptor as WriteTimeTtlColumnDescriptor, WriteTimeTtlKind,
66};
67
68// Re-export advanced SELECT components.
69// Only the symbols with known callers are re-exported here. `select_ast` is
70// intentionally not glob-re-exported: a `pub use select_ast::*` would shadow the
71// inline `ComparisonOperator`, `OrderByClause`, and `SortDirection` types below.
72// Other `select_ast` items remain reachable via `cqlite_core::query::select_ast::*`.
73#[cfg(feature = "state_machine")]
74pub use select_ast::SelectStatement;
75#[cfg(feature = "state_machine")]
76pub use select_executor::{
77    build_row_from_scan, evaluate_leaf, evaluate_predicates, LeafOutcome, SelectExecutor,
78};
79#[cfg(feature = "state_machine")]
80pub use select_optimizer::{
81    OptimizedQueryPlan, SSTableFilterOp, SSTablePredicate, SelectOptimizer,
82};
83#[cfg(feature = "state_machine")]
84pub use select_parser::{parse_select, SelectParser};
85
86use std::collections::HashMap;
87use std::sync::Arc;
88
89use crate::{
90    memory::MemoryManager, schema::SchemaManager, storage::StorageEngine, Config, Result, TableId,
91    Value,
92};
93
94/// Query execution statistics
95#[derive(Debug, Clone, Default)]
96pub struct QueryStats {
97    /// Total queries executed
98    pub total_queries: u64,
99    /// Queries that resulted in errors
100    pub error_queries: u64,
101    /// Average execution time in microseconds
102    pub avg_execution_time_us: u64,
103    /// Cache hit ratio
104    pub cache_hit_ratio: f64,
105    /// Total rows affected by write operations
106    pub rows_affected: u64,
107}
108
109/// Legacy query engine wrapper for backward compatibility.
110///
111/// Delegates to [`AdvancedQueryEngine`] (re-exported from [`engine`]); kept as a
112/// stable public surface used by [`crate::Database`] and the CLI's REPL.
113#[derive(Debug)]
114pub struct QueryEngine {
115    advanced_engine: AdvancedQueryEngine,
116}
117
118impl QueryEngine {
119    /// Create a new query engine.
120    pub fn new(
121        storage: Arc<StorageEngine>,
122        schema: Arc<SchemaManager>,
123        memory: Arc<MemoryManager>,
124        config: &Config,
125    ) -> Result<Self> {
126        Ok(Self {
127            advanced_engine: AdvancedQueryEngine::new(storage, schema, memory, config)?,
128        })
129    }
130
131    /// Execute a CQL query
132    pub async fn execute(&self, cql: &str) -> Result<QueryResult> {
133        self.advanced_engine.execute(cql).await
134    }
135
136    /// Execute a SELECT with positional `?` parameters (Issue #961).
137    pub async fn execute_with_params(&self, cql: &str, params: &[Value]) -> Result<QueryResult> {
138        self.advanced_engine.execute_with_params(cql, params).await
139    }
140
141    /// Prepare a query for repeated execution
142    pub async fn prepare(&self, cql: &str) -> Result<Arc<PreparedQuery>> {
143        self.advanced_engine.prepare(cql).await
144    }
145
146    /// Get query statistics
147    pub fn stats(&self) -> QueryStats {
148        self.advanced_engine.stats()
149    }
150
151    /// Clear prepared statement cache
152    pub fn clear_cache(&self) {
153        self.advanced_engine.clear_prepared_cache();
154    }
155
156    /// Explain a query
157    pub async fn explain(&self, cql: &str) -> Result<ExplainResult> {
158        self.advanced_engine.explain(cql).await
159    }
160
161    /// Analyze query performance
162    pub async fn analyze(&self, cql: &str) -> Result<AnalyzeResult> {
163        self.advanced_engine.analyze(cql).await
164    }
165
166    /// Execute a CQL query with streaming results (Issue #280)
167    ///
168    /// Returns a `QueryResultIterator` that yields rows incrementally via a bounded
169    /// channel, enabling memory-efficient processing of large result sets.
170    #[cfg(feature = "state_machine")]
171    pub async fn execute_streaming(
172        &self,
173        cql: &str,
174        config: StreamingConfig,
175    ) -> Result<QueryResultIterator> {
176        self.advanced_engine.execute_streaming(cql, config).await
177    }
178
179    /// Get cache statistics
180    pub fn cache_stats(&self) -> CacheStats {
181        self.advanced_engine.cache_stats()
182    }
183
184    /// Check if schema is available for a table
185    pub async fn has_schema_for_table(&self, table: &str) -> bool {
186        self.advanced_engine.has_schema_for_table(table).await
187    }
188
189    /// Get detailed schema status for debugging
190    pub async fn schema_status(&self, table: &str) -> SchemaStatus {
191        self.advanced_engine.schema_status(table).await
192    }
193}
194
195/// CQL query types
196#[derive(Debug, Clone, PartialEq)]
197pub enum QueryType {
198    /// SELECT statement
199    Select,
200    /// INSERT statement
201    Insert,
202    /// UPDATE statement
203    Update,
204    /// DELETE statement
205    Delete,
206    /// CREATE TABLE statement
207    CreateTable,
208    /// DROP TABLE statement
209    DropTable,
210    /// CREATE INDEX statement
211    CreateIndex,
212    /// DROP INDEX statement
213    DropIndex,
214    /// DESCRIBE statement
215    Describe,
216    /// USE statement (for keyspace)
217    Use,
218}
219
220/// Parsed CQL query representation
221#[derive(Debug, Clone)]
222pub struct ParsedQuery {
223    /// Query type
224    pub query_type: QueryType,
225    /// Target table (if applicable)
226    pub table: Option<TableId>,
227    /// Column selections (for SELECT)
228    pub columns: Vec<String>,
229    /// WHERE clause conditions
230    pub where_clause: Option<WhereClause>,
231    /// VALUES for INSERT
232    pub values: Vec<Value>,
233    /// SET clause for UPDATE
234    pub set_clause: HashMap<String, Value>,
235    /// ORDER BY clause
236    pub order_by: Vec<OrderByClause>,
237    /// LIMIT clause
238    pub limit: Option<usize>,
239    /// Original CQL text
240    pub cql: String,
241}
242
243/// WHERE clause representation
244#[derive(Debug, Clone)]
245pub struct WhereClause {
246    /// Conditions in the WHERE clause
247    pub conditions: Vec<Condition>,
248}
249
250/// Individual condition in WHERE clause
251#[derive(Debug, Clone)]
252pub struct Condition {
253    /// Column name
254    pub column: String,
255    /// Comparison operator
256    pub operator: ComparisonOperator,
257    /// Value to compare against
258    pub value: Value,
259}
260
261/// Comparison operators
262#[derive(Debug, Clone, PartialEq)]
263pub enum ComparisonOperator {
264    /// Equal (=)
265    Equal,
266    /// Not equal (<>)
267    NotEqual,
268    /// Less than (<)
269    LessThan,
270    /// Less than or equal (<=)
271    LessThanOrEqual,
272    /// Greater than (>)
273    GreaterThan,
274    /// Greater than or equal (>=)
275    GreaterThanOrEqual,
276    /// IN operator
277    In,
278    /// NOT IN operator
279    NotIn,
280    /// LIKE operator
281    Like,
282    /// NOT LIKE operator
283    NotLike,
284}
285
286/// ORDER BY clause
287#[derive(Debug, Clone)]
288pub struct OrderByClause {
289    /// Column name
290    pub column: String,
291    /// Sort direction
292    pub direction: SortDirection,
293}
294
295/// Sort direction
296#[derive(Debug, Clone, PartialEq)]
297pub enum SortDirection {
298    /// Ascending
299    Asc,
300    /// Descending
301    Desc,
302}
303
304#[cfg(all(test, feature = "state_machine"))]
305mod tests {
306    use super::*;
307    use crate::platform::Platform;
308    use tempfile::TempDir;
309
310    #[tokio::test]
311    async fn test_query_engine_creation() {
312        let temp_dir = TempDir::new().unwrap();
313        let config = Config::default();
314        let platform = Arc::new(Platform::new(&config).await.unwrap());
315
316        let storage = Arc::new(
317            StorageEngine::open(
318                temp_dir.path(),
319                &config,
320                platform,
321                #[cfg(feature = "state_machine")]
322                None,
323            )
324            .await
325            .unwrap(),
326        );
327        let schema = Arc::new(SchemaManager::new(temp_dir.path()).await.unwrap());
328        let memory = Arc::new(MemoryManager::new(&config).unwrap());
329
330        let query_engine = QueryEngine::new(storage, schema, memory, &config).unwrap();
331
332        assert_eq!(query_engine.stats().total_queries, 0);
333    }
334}