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