Skip to main content

oxigdal_query/executor/
mod.rs

1//! Query execution engine.
2
3pub mod aggregate;
4pub mod filter;
5pub mod join;
6pub(crate) mod like;
7pub mod scan;
8pub mod sort;
9pub mod spatial_funcs;
10
11pub use spatial_funcs::evaluate_spatial_function;
12
13pub mod window;
14
15pub use window::{OrderKey, WindowFunction, WindowSpec, evaluate_window, evaluate_window_batch};
16
17use crate::error::{QueryError, Result};
18use crate::parser::ast::*;
19use aggregate::{Aggregate, AggregateFunc, AggregateFunction};
20use filter::Filter;
21use join::Join;
22use scan::{DataSource, RecordBatch, TableScan};
23use sort::Sort;
24use std::collections::HashMap;
25use std::sync::Arc;
26
27/// Query executor.
28pub struct Executor {
29    /// Data sources registry.
30    data_sources: HashMap<String, Arc<dyn DataSource>>,
31}
32
33impl Executor {
34    /// Create a new executor.
35    pub fn new() -> Self {
36        Self {
37            data_sources: HashMap::new(),
38        }
39    }
40
41    /// Register a data source.
42    pub fn register_data_source(&mut self, name: String, source: Arc<dyn DataSource>) {
43        self.data_sources.insert(name, source);
44    }
45
46    /// Execute a query.
47    pub async fn execute(&self, stmt: &Statement) -> Result<Vec<RecordBatch>> {
48        match stmt {
49            Statement::Select(select) => self.execute_select(select).await,
50        }
51    }
52
53    /// Execute a SELECT statement.
54    async fn execute_select(&self, select: &SelectStatement) -> Result<Vec<RecordBatch>> {
55        // Execute FROM clause
56        let mut batches = if let Some(ref table_ref) = select.from {
57            self.execute_table_reference(table_ref).await?
58        } else {
59            return Err(QueryError::semantic("SELECT without FROM not supported"));
60        };
61
62        // Execute WHERE clause
63        if let Some(ref selection) = select.selection {
64            batches = self.execute_filter(batches, selection)?;
65        }
66
67        // Execute GROUP BY / aggregation
68        if !select.group_by.is_empty() || self.has_aggregates(&select.projection) {
69            batches = self.execute_aggregate(batches, select)?;
70        }
71
72        // Execute ORDER BY
73        if !select.order_by.is_empty() {
74            batches = self.execute_sort(batches, &select.order_by)?;
75        }
76
77        // Execute LIMIT and OFFSET
78        if select.limit.is_some() || select.offset.is_some() {
79            batches = self.execute_limit_offset(batches, select.limit, select.offset)?;
80        }
81
82        Ok(batches)
83    }
84
85    /// Execute a table reference.
86    async fn execute_table_reference(
87        &self,
88        table_ref: &TableReference,
89    ) -> Result<Vec<RecordBatch>> {
90        match table_ref {
91            TableReference::Table { name, .. } => {
92                let source = self
93                    .data_sources
94                    .get(name)
95                    .ok_or_else(|| QueryError::TableNotFound(name.clone()))?;
96
97                let scan = TableScan::new(name.clone(), source.clone());
98                scan.execute().await
99            }
100            TableReference::Join {
101                left,
102                right,
103                join_type,
104                on,
105            } => {
106                // Use Box::pin to avoid infinite size for recursive async fn
107                let left_batches = Box::pin(self.execute_table_reference(left)).await?;
108                let right_batches = Box::pin(self.execute_table_reference(right)).await?;
109
110                let join = Join::new(*join_type, on.clone());
111                let mut result = Vec::new();
112
113                for left_batch in &left_batches {
114                    for right_batch in &right_batches {
115                        result.push(join.execute(left_batch, right_batch)?);
116                    }
117                }
118
119                Ok(result)
120            }
121            TableReference::Subquery { query, .. } => Box::pin(self.execute_select(query)).await,
122        }
123    }
124
125    /// Execute filter operation.
126    fn execute_filter(
127        &self,
128        batches: Vec<RecordBatch>,
129        predicate: &Expr,
130    ) -> Result<Vec<RecordBatch>> {
131        let filter = Filter::new(predicate.clone());
132        let mut result = Vec::new();
133
134        for batch in batches {
135            result.push(filter.execute(&batch)?);
136        }
137
138        Ok(result)
139    }
140
141    /// Execute aggregation.
142    fn execute_aggregate(
143        &self,
144        batches: Vec<RecordBatch>,
145        select: &SelectStatement,
146    ) -> Result<Vec<RecordBatch>> {
147        // Extract aggregate functions from projection
148        let mut agg_funcs = Vec::new();
149
150        for item in &select.projection {
151            if let SelectItem::Expr { expr, alias } = item
152                && let Some(agg_func) = self.extract_aggregate(expr)
153            {
154                let func_alias = alias.clone().or_else(|| Some("agg".to_string()));
155                agg_funcs.push(AggregateFunction {
156                    func: agg_func.0,
157                    column: agg_func.1,
158                    alias: func_alias,
159                });
160            }
161        }
162
163        let aggregate = Aggregate::new(select.group_by.clone(), agg_funcs);
164        let mut result = Vec::new();
165
166        for batch in batches {
167            result.push(aggregate.execute(&batch)?);
168        }
169
170        Ok(result)
171    }
172
173    /// Extract aggregate function from expression.
174    fn extract_aggregate(&self, expr: &Expr) -> Option<(AggregateFunc, String)> {
175        if let Expr::Function { name, args } = expr {
176            let func = match name.to_uppercase().as_str() {
177                "COUNT" => Some(AggregateFunc::Count),
178                "SUM" => Some(AggregateFunc::Sum),
179                "AVG" => Some(AggregateFunc::Avg),
180                "MIN" => Some(AggregateFunc::Min),
181                "MAX" => Some(AggregateFunc::Max),
182                _ => None,
183            }?;
184
185            if let Some(arg) = args.first() {
186                match arg {
187                    Expr::Column { name, .. } => {
188                        return Some((func, name.clone()));
189                    }
190                    Expr::Wildcard => {
191                        // COUNT(*) uses any column
192                        return Some((func, "*".to_string()));
193                    }
194                    _ => {}
195                }
196            } else if matches!(func, AggregateFunc::Count) {
197                // COUNT(*) with no args
198                return Some((func, "*".to_string()));
199            }
200        }
201        None
202    }
203
204    /// Check if projection has aggregates.
205    fn has_aggregates(&self, projection: &[SelectItem]) -> bool {
206        for item in projection {
207            if let SelectItem::Expr { expr, .. } = item
208                && self.extract_aggregate(expr).is_some()
209            {
210                return true;
211            }
212        }
213        false
214    }
215
216    /// Execute sort operation.
217    fn execute_sort(
218        &self,
219        batches: Vec<RecordBatch>,
220        order_by: &[OrderByExpr],
221    ) -> Result<Vec<RecordBatch>> {
222        let sort = Sort::new(order_by.to_vec());
223        let mut result = Vec::new();
224
225        for batch in batches {
226            result.push(sort.execute(&batch)?);
227        }
228
229        Ok(result)
230    }
231
232    /// Execute LIMIT and OFFSET.
233    fn execute_limit_offset(
234        &self,
235        batches: Vec<RecordBatch>,
236        limit: Option<usize>,
237        offset: Option<usize>,
238    ) -> Result<Vec<RecordBatch>> {
239        let offset = offset.unwrap_or(0);
240        let mut current_row = 0;
241        let mut result = Vec::new();
242        let mut remaining = limit;
243
244        for batch in batches {
245            if let Some(rem) = remaining
246                && rem == 0
247            {
248                break;
249            }
250
251            let start = if current_row < offset {
252                let skip = (offset - current_row).min(batch.num_rows);
253                current_row += skip;
254                skip
255            } else {
256                0
257            };
258
259            let end = if let Some(rem) = remaining {
260                (start + rem).min(batch.num_rows)
261            } else {
262                batch.num_rows
263            };
264
265            if start < end {
266                let slice_batch = self.slice_batch(&batch, start, end)?;
267                let slice_rows = slice_batch.num_rows;
268                result.push(slice_batch);
269
270                if let Some(rem) = &mut remaining {
271                    *rem = rem.saturating_sub(slice_rows);
272                }
273            }
274
275            current_row += batch.num_rows;
276        }
277
278        Ok(result)
279    }
280
281    /// Slice a record batch.
282    fn slice_batch(&self, batch: &RecordBatch, start: usize, end: usize) -> Result<RecordBatch> {
283        let mut sliced_columns = Vec::new();
284
285        for column in &batch.columns {
286            sliced_columns.push(self.slice_column(column, start, end));
287        }
288
289        RecordBatch::new(batch.schema.clone(), sliced_columns, end - start)
290    }
291
292    /// Slice a column.
293    fn slice_column(
294        &self,
295        column: &scan::ColumnData,
296        start: usize,
297        end: usize,
298    ) -> scan::ColumnData {
299        use scan::ColumnData;
300
301        match column {
302            ColumnData::Boolean(data) => ColumnData::Boolean(data[start..end].to_vec()),
303            ColumnData::Int32(data) => ColumnData::Int32(data[start..end].to_vec()),
304            ColumnData::Int64(data) => ColumnData::Int64(data[start..end].to_vec()),
305            ColumnData::Float32(data) => ColumnData::Float32(data[start..end].to_vec()),
306            ColumnData::Float64(data) => ColumnData::Float64(data[start..end].to_vec()),
307            ColumnData::String(data) => ColumnData::String(data[start..end].to_vec()),
308            ColumnData::Binary(data) => ColumnData::Binary(data[start..end].to_vec()),
309        }
310    }
311}
312
313impl Default for Executor {
314    fn default() -> Self {
315        Self::new()
316    }
317}
318
319#[cfg(test)]
320mod tests {
321    use super::*;
322    use crate::executor::scan::{DataType, Field, MemoryDataSource, Schema};
323    use crate::parser::sql::parse_sql;
324
325    #[tokio::test]
326    async fn test_executor_simple_query() -> Result<()> {
327        let schema = Arc::new(Schema::new(vec![
328            Field::new("id".to_string(), DataType::Int64, false),
329            Field::new("value".to_string(), DataType::Int64, false),
330        ]));
331
332        let columns = vec![
333            scan::ColumnData::Int64(vec![Some(1), Some(2), Some(3)]),
334            scan::ColumnData::Int64(vec![Some(10), Some(20), Some(30)]),
335        ];
336
337        let batch = RecordBatch::new(schema.clone(), columns, 3)?;
338        let source = Arc::new(MemoryDataSource::new(schema, vec![batch]));
339
340        let mut executor = Executor::new();
341        executor.register_data_source("test_table".to_string(), source);
342
343        let sql = "SELECT * FROM test_table";
344        let stmt = parse_sql(sql)?;
345
346        let result = executor.execute(&stmt).await?;
347        assert!(!result.is_empty());
348
349        Ok(())
350    }
351}