1use alopex_core::kv::KVStore;
2
3use crate::ast::LITERAL_TABLE;
4use crate::catalog::{Catalog, StorageType};
5use crate::executor::evaluator::EvalContext;
6use crate::executor::memory::MemoryPolicy;
7use crate::executor::{ExecutionResult, ExecutorError, QueryResult, QueryRowIterator, Result};
8use crate::planner::logical_plan::LogicalPlan;
9use crate::planner::typed_expr::{Projection, SortExpr};
10use crate::storage::{SqlTxn, SqlValue};
11
12use super::{ColumnInfo, Row};
13
14pub mod aggregate;
15pub mod columnar_scan;
16pub mod iterator;
17pub mod join;
18mod knn;
19mod project;
20mod scan;
21pub mod subquery;
22
23pub use columnar_scan::{ColumnarScanIterator, create_columnar_scan_iterator};
24pub use iterator::{FilterIterator, LimitIterator, RowIterator, ScanIterator, SortIterator};
25pub use scan::create_scan_iterator;
26
27pub fn execute_query<'txn, S: KVStore + 'txn, C: Catalog + ?Sized, T: SqlTxn<'txn, S>>(
39 txn: &mut T,
40 catalog: &C,
41 plan: LogicalPlan,
42) -> Result<ExecutionResult> {
43 execute_query_with_policy(txn, catalog, plan, None)
44}
45
46pub fn execute_query_with_policy<
47 'txn,
48 S: KVStore + 'txn,
49 C: Catalog + ?Sized,
50 T: SqlTxn<'txn, S>,
51>(
52 txn: &mut T,
53 catalog: &C,
54 plan: LogicalPlan,
55 memory: Option<&MemoryPolicy>,
56) -> Result<ExecutionResult> {
57 if let Some((pattern, projection, filter)) = knn::extract_knn_context(&plan) {
58 return knn::execute_knn_query(txn, catalog, &pattern, &projection, filter.as_ref());
59 }
60
61 let result = execute_query_result_with_outer_and_policy(txn, catalog, plan, None, memory)?;
62 Ok(ExecutionResult::Query(result))
63}
64
65pub(crate) fn execute_query_result_with_outer<
66 'txn,
67 S: KVStore + 'txn,
68 C: Catalog + ?Sized,
69 T: SqlTxn<'txn, S>,
70>(
71 txn: &mut T,
72 catalog: &C,
73 plan: LogicalPlan,
74 outer: Option<&Row>,
75) -> Result<QueryResult> {
76 execute_query_result_with_outer_and_policy(txn, catalog, plan, outer, None)
77}
78
79fn execute_query_result_with_outer_and_policy<
80 'txn,
81 S: KVStore + 'txn,
82 C: Catalog + ?Sized,
83 T: SqlTxn<'txn, S>,
84>(
85 txn: &mut T,
86 catalog: &C,
87 plan: LogicalPlan,
88 outer: Option<&Row>,
89 memory: Option<&MemoryPolicy>,
90) -> Result<QueryResult> {
91 let (mut iter, projection, schema) =
92 build_iterator_pipeline_with_outer(txn, catalog, plan, memory, outer)?;
93 let mut rows = Vec::new();
94 while let Some(result) = iter.next_row() {
95 rows.push(result?);
96 }
97 execute_project_with_subqueries(txn, catalog, rows, &projection, &schema, outer)
98}
99
100pub fn execute_query_streaming<'txn, S: KVStore + 'txn, C: Catalog + ?Sized, T: SqlTxn<'txn, S>>(
116 txn: &mut T,
117 catalog: &C,
118 plan: LogicalPlan,
119) -> Result<QueryRowIterator<'static>> {
120 execute_query_streaming_with_policy(txn, catalog, plan, None)
121}
122
123pub fn execute_query_streaming_with_policy<
124 'txn,
125 S: KVStore + 'txn,
126 C: Catalog + ?Sized,
127 T: SqlTxn<'txn, S>,
128>(
129 txn: &mut T,
130 catalog: &C,
131 plan: LogicalPlan,
132 memory: Option<&MemoryPolicy>,
133) -> Result<QueryRowIterator<'static>> {
134 if knn::extract_knn_context(&plan).is_some() {
136 let result = execute_query_with_policy(txn, catalog, plan, memory)?;
138 if let ExecutionResult::Query(qr) = result {
139 let (iter, projection, schema) = materialize_query_result(qr);
140 return Ok(QueryRowIterator::new(iter, projection, schema));
141 }
142 return Err(ExecutorError::InvalidOperation {
143 operation: "execute_query_streaming".into(),
144 reason: "KNN query did not return Query result".into(),
145 });
146 }
147
148 if subquery::plan_contains_subquery(&plan) {
153 let result = execute_query_result_with_outer_and_policy(txn, catalog, plan, None, memory)?;
154 let (iter, projection, schema) = materialize_query_result(result);
155 return Ok(QueryRowIterator::new(iter, projection, schema));
156 }
157
158 let (iter, projection, schema) = build_iterator_pipeline(txn, catalog, plan, memory)?;
159
160 Ok(QueryRowIterator::new(iter, projection, schema))
161}
162
163fn materialize_query_result(
168 result: QueryResult,
169) -> (
170 Box<dyn RowIterator>,
171 Projection,
172 Vec<crate::catalog::ColumnMetadata>,
173) {
174 let column_names: Vec<String> = result.columns.iter().map(|c| c.name.clone()).collect();
175 let schema: Vec<crate::catalog::ColumnMetadata> = result
176 .columns
177 .iter()
178 .map(|c| crate::catalog::ColumnMetadata::new(&c.name, c.data_type.clone()))
179 .collect();
180 let rows: Vec<Row> = result
181 .rows
182 .into_iter()
183 .enumerate()
184 .map(|(i, values)| Row::new(i as u64, values))
185 .collect();
186 let iter = iterator::VecIterator::new(rows, schema.clone());
187 (Box::new(iter), Projection::All(column_names), schema)
188}
189
190fn build_iterator_pipeline<'txn, S: KVStore + 'txn, C: Catalog + ?Sized, T: SqlTxn<'txn, S>>(
197 txn: &mut T,
198 catalog: &C,
199 plan: LogicalPlan,
200 memory: Option<&MemoryPolicy>,
201) -> Result<(
202 Box<dyn RowIterator>,
203 Projection,
204 Vec<crate::catalog::ColumnMetadata>,
205)> {
206 build_iterator_pipeline_with_outer(txn, catalog, plan, memory, None)
207}
208
209fn build_iterator_pipeline_with_outer<
210 'txn,
211 S: KVStore + 'txn,
212 C: Catalog + ?Sized,
213 T: SqlTxn<'txn, S>,
214>(
215 txn: &mut T,
216 catalog: &C,
217 plan: LogicalPlan,
218 memory: Option<&MemoryPolicy>,
219 outer: Option<&Row>,
220) -> Result<(
221 Box<dyn RowIterator>,
222 Projection,
223 Vec<crate::catalog::ColumnMetadata>,
224)> {
225 match plan {
226 LogicalPlan::Scan { table, projection } => {
227 if table == LITERAL_TABLE {
228 let schema = Vec::new();
229 let rows = vec![Row::new(0, Vec::new())];
230 let iter = iterator::VecIterator::new(rows, schema.clone());
231 return Ok((Box::new(iter), projection, schema));
232 }
233 let table_meta = catalog
234 .get_table(&table)
235 .cloned()
236 .ok_or_else(|| ExecutorError::TableNotFound(table.clone()))?;
237
238 if table_meta.storage_options.storage_type == StorageType::Columnar {
239 let columnar_scan = columnar_scan::build_columnar_scan(&table_meta, &projection);
240 let rows = columnar_scan::execute_columnar_scan(txn, &table_meta, &columnar_scan)?;
241 let schema = table_meta.columns.clone();
242 let iter = iterator::VecIterator::new(rows, schema.clone());
243 return Ok((Box::new(iter), projection, schema));
244 }
245
246 let rows = scan::execute_scan(txn, &table_meta)?;
250 let schema = table_meta.columns.clone();
251
252 let iter = iterator::VecIterator::new(rows, schema.clone());
254 Ok((Box::new(iter), projection, schema))
255 }
256 LogicalPlan::Filter { input, predicate } => {
257 if let LogicalPlan::Scan { table, projection } = input.as_ref()
258 && let Some(table_meta) = catalog.get_table(table)
259 && table_meta.storage_options.storage_type == StorageType::Columnar
260 {
261 let columnar_scan = columnar_scan::build_columnar_scan_for_filter(
262 table_meta,
263 projection.clone(),
264 &predicate,
265 );
266 let rows = columnar_scan::execute_columnar_scan(txn, table_meta, &columnar_scan)?;
267 let schema = table_meta.columns.clone();
268 let iter = iterator::VecIterator::new(rows, schema.clone());
269 return Ok((Box::new(iter), projection.clone(), schema));
270 }
271 let (mut input_iter, projection, schema) =
272 build_iterator_pipeline_with_outer(txn, catalog, *input, memory, outer)?;
273 if outer.is_some() || subquery::contains_subquery(&predicate) {
274 let mut rows = Vec::new();
275 while let Some(result) = input_iter.next_row() {
276 let row = result?;
277 let eval_row = combine_outer_for_eval(&row, outer);
278 if let SqlValue::Boolean(true) = subquery::evaluate_expr_with_subqueries(
279 txn, catalog, &predicate, &eval_row,
280 )? {
281 rows.push(row);
282 }
283 }
284 let iter = iterator::VecIterator::new(rows, schema.clone());
285 return Ok((Box::new(iter), projection, schema));
286 }
287 let filter_iter = FilterIterator::new(input_iter, predicate);
288 Ok((Box::new(filter_iter), projection, schema))
289 }
290 LogicalPlan::Project { input, projection } => {
291 let (mut input_iter, _input_projection, schema) =
292 build_iterator_pipeline_with_outer(txn, catalog, *input, memory, outer)?;
293 let mut rows = Vec::new();
294 while let Some(result) = input_iter.next_row() {
295 rows.push(result?);
296 }
297 let projected =
298 execute_project_with_subqueries(txn, catalog, rows, &projection, &schema, outer)?;
299 let output_schema = projected
300 .columns
301 .iter()
302 .map(|col| crate::catalog::ColumnMetadata::new(&col.name, col.data_type.clone()))
303 .collect::<Vec<_>>();
304 let rows = projected
305 .rows
306 .into_iter()
307 .enumerate()
308 .map(|(idx, values)| Row::new(idx as u64, values))
309 .collect::<Vec<_>>();
310 let output_projection =
311 Projection::All(output_schema.iter().map(|col| col.name.clone()).collect());
312 let iter = iterator::VecIterator::new(rows, output_schema.clone());
313 Ok((Box::new(iter), output_projection, output_schema))
314 }
315 LogicalPlan::Join {
316 left,
317 right,
318 join_type,
319 condition,
320 using: _,
321 } => {
322 let (mut left_iter, _left_projection, left_schema) =
323 build_iterator_pipeline_with_outer(txn, catalog, *left, memory, outer)?;
324 let (mut right_iter, _right_projection, right_schema) =
325 build_iterator_pipeline_with_outer(txn, catalog, *right, memory, outer)?;
326 let mut left_rows = Vec::new();
327 while let Some(result) = left_iter.next_row() {
328 left_rows.push(result?);
329 }
330 let mut right_rows = Vec::new();
331 while let Some(result) = right_iter.next_row() {
332 right_rows.push(result?);
333 }
334 let left_width = left_schema.len();
335 let right_width = right_schema.len();
336 let rows = join::execute_join_with_widths(
337 left_rows,
338 right_rows,
339 join_type,
340 condition.as_ref(),
341 left_width,
342 right_width,
343 )?;
344 let mut schema = left_schema;
345 schema.extend(right_schema);
346 let projection = Projection::All(schema.iter().map(|col| col.name.clone()).collect());
347 let iter = iterator::VecIterator::new(rows, schema.clone());
348 Ok((Box::new(iter), projection, schema))
349 }
350 LogicalPlan::Aggregate {
351 input,
352 group_keys,
353 aggregates,
354 having,
355 projection,
356 } => {
357 let (input_iter, _projection, _schema) =
358 build_iterator_pipeline_with_outer(txn, catalog, *input, memory, outer)?;
359 let schema = aggregate::build_aggregate_schema(&group_keys, &aggregates);
360 if let Some(policy) = memory
361 && policy.spill_directory().is_some()
362 {
363 if group_keys.is_empty() {
364 let iter = aggregate::StreamingAggregateIterator::new(
365 input_iter,
366 group_keys,
367 aggregates,
368 having,
369 schema.clone(),
370 );
371 return Ok((Box::new(iter), projection, schema));
372 }
373 let order_by = group_keys
374 .iter()
375 .cloned()
376 .map(|expr| SortExpr {
377 expr,
378 asc: true,
379 nulls_first: false,
380 })
381 .collect::<Vec<_>>();
382 let sort_iter =
383 SortIterator::new_with_policy(input_iter, &order_by, Some(policy.clone()))?;
384 let iter = aggregate::StreamingAggregateIterator::new(
385 Box::new(sort_iter),
386 group_keys,
387 aggregates,
388 having,
389 schema.clone(),
390 );
391 return Ok((Box::new(iter), projection, schema));
392 }
393
394 let parallelism = std::thread::available_parallelism()
395 .map(usize::from)
396 .unwrap_or(1);
397 if !aggregate::should_use_single_for_parallel(parallelism, &aggregates) {
398 let rows = aggregate::execute_parallel_aggregate_rows_with_policy(
399 input_iter,
400 group_keys,
401 aggregates,
402 having,
403 schema.clone(),
404 parallelism,
405 memory.cloned(),
406 1_000_000,
407 )?;
408 let iter = iterator::VecIterator::new(rows, schema.clone());
409 return Ok((Box::new(iter), projection, schema));
410 }
411
412 let mut iter = aggregate::AggregateIterator::new(
413 input_iter,
414 group_keys,
415 aggregates,
416 having,
417 schema.clone(),
418 );
419 if let Some(policy) = memory {
420 iter = iter.with_memory_policy(Some(policy.clone()));
421 }
422 Ok((Box::new(iter), projection, schema))
423 }
424 LogicalPlan::Sort { input, order_by } => {
425 let (input_iter, projection, schema) =
426 build_iterator_pipeline_with_outer(txn, catalog, *input, memory, outer)?;
427 let sort_iter = if let Some(policy) = memory {
428 SortIterator::new_with_policy(input_iter, &order_by, Some(policy.clone()))?
429 } else {
430 SortIterator::new(input_iter, &order_by)?
431 };
432 Ok((Box::new(sort_iter), projection, schema))
433 }
434 LogicalPlan::Limit {
435 input,
436 limit,
437 offset,
438 } => {
439 let (input_iter, projection, schema) =
440 build_iterator_pipeline_with_outer(txn, catalog, *input, memory, outer)?;
441 let limit_iter = LimitIterator::new(input_iter, limit, offset);
442 Ok((Box::new(limit_iter), projection, schema))
443 }
444 other => Err(ExecutorError::UnsupportedOperation(format!(
445 "unsupported query plan: {other:?}"
446 ))),
447 }
448}
449
450pub fn build_streaming_pipeline<
462 'a,
463 'txn: 'a,
464 S: KVStore + 'txn,
465 C: Catalog + ?Sized,
466 T: SqlTxn<'txn, S>,
467>(
468 txn: &'a mut T,
469 catalog: &C,
470 plan: LogicalPlan,
471) -> Result<(
472 Box<dyn RowIterator + 'a>,
473 Projection,
474 Vec<crate::catalog::ColumnMetadata>,
475)> {
476 build_streaming_pipeline_with_policy(txn, catalog, plan, None)
477}
478
479pub fn build_streaming_pipeline_with_policy<
480 'a,
481 'txn: 'a,
482 S: KVStore + 'txn,
483 C: Catalog + ?Sized,
484 T: SqlTxn<'txn, S>,
485>(
486 txn: &'a mut T,
487 catalog: &C,
488 plan: LogicalPlan,
489 memory: Option<&MemoryPolicy>,
490) -> Result<(
491 Box<dyn RowIterator + 'a>,
492 Projection,
493 Vec<crate::catalog::ColumnMetadata>,
494)> {
495 if subquery::plan_contains_subquery(&plan) {
501 let result = execute_query_result_with_outer_and_policy(txn, catalog, plan, None, memory)?;
502 return Ok(materialize_query_result(result));
503 }
504
505 build_streaming_pipeline_inner(txn, catalog, plan, memory)
506}
507
508fn build_streaming_pipeline_inner<
510 'a,
511 'txn: 'a,
512 S: KVStore + 'txn,
513 C: Catalog + ?Sized,
514 T: SqlTxn<'txn, S>,
515>(
516 txn: &'a mut T,
517 catalog: &C,
518 plan: LogicalPlan,
519 memory: Option<&MemoryPolicy>,
520) -> Result<(
521 Box<dyn RowIterator + 'a>,
522 Projection,
523 Vec<crate::catalog::ColumnMetadata>,
524)> {
525 match plan {
526 LogicalPlan::Scan { table, projection } => {
527 if table == LITERAL_TABLE {
528 let schema = Vec::new();
529 let rows = vec![Row::new(0, Vec::new())];
530 let iter = iterator::VecIterator::new(rows, schema.clone());
531 return Ok((Box::new(iter), projection, schema));
532 }
533 let table_meta = catalog
534 .get_table(&table)
535 .cloned()
536 .ok_or_else(|| ExecutorError::TableNotFound(table.clone()))?;
537
538 if table_meta.storage_options.storage_type == StorageType::Columnar {
539 let columnar_scan = columnar_scan::build_columnar_scan(&table_meta, &projection);
541 let schema = table_meta.columns.clone();
542 let iter =
543 columnar_scan::create_columnar_scan_iterator(txn, &table_meta, &columnar_scan)?;
544 return Ok((Box::new(iter), projection, schema));
545 }
546
547 let schema = table_meta.columns.clone();
549 let scan_iter = scan::create_scan_iterator(txn, &table_meta)?;
550 Ok((Box::new(scan_iter), projection, schema))
551 }
552 LogicalPlan::Filter { input, predicate } => {
553 if let LogicalPlan::Scan { table, projection } = input.as_ref()
554 && let Some(table_meta) = catalog.get_table(table)
555 && table_meta.storage_options.storage_type == StorageType::Columnar
556 {
557 let columnar_scan = columnar_scan::build_columnar_scan_for_filter(
559 table_meta,
560 projection.clone(),
561 &predicate,
562 );
563 let schema = table_meta.columns.clone();
564 let iter =
565 columnar_scan::create_columnar_scan_iterator(txn, table_meta, &columnar_scan)?;
566 return Ok((Box::new(iter), projection.clone(), schema));
567 }
568 let (input_iter, projection, schema) =
569 build_streaming_pipeline_inner(txn, catalog, *input, memory)?;
570 let filter_iter = FilterIterator::new(input_iter, predicate);
571 Ok((Box::new(filter_iter), projection, schema))
572 }
573 LogicalPlan::Project { input, projection } => {
574 let (mut input_iter, _input_projection, schema) =
575 build_streaming_pipeline_inner(txn, catalog, *input, memory)?;
576 let mut rows = Vec::new();
577 while let Some(result) = input_iter.next_row() {
578 rows.push(result?);
579 }
580 let projected = project::execute_project(rows, &projection, &schema)?;
581 let output_schema = projected
582 .columns
583 .iter()
584 .map(|col| crate::catalog::ColumnMetadata::new(&col.name, col.data_type.clone()))
585 .collect::<Vec<_>>();
586 let rows = projected
587 .rows
588 .into_iter()
589 .enumerate()
590 .map(|(idx, values)| Row::new(idx as u64, values))
591 .collect::<Vec<_>>();
592 let output_projection =
593 Projection::All(output_schema.iter().map(|col| col.name.clone()).collect());
594 let iter = iterator::VecIterator::new(rows, output_schema.clone());
595 Ok((Box::new(iter), output_projection, output_schema))
596 }
597 LogicalPlan::Join {
598 left,
599 right,
600 join_type,
601 condition,
602 using: _,
603 } => {
604 let (mut left_iter, _left_projection, left_schema) =
605 build_streaming_pipeline_inner(txn, catalog, *left, memory)?;
606 let mut left_rows = Vec::new();
607 while let Some(result) = left_iter.next_row() {
608 left_rows.push(result?);
609 }
610 drop(left_iter);
611 let (mut right_iter, _right_projection, right_schema) =
612 build_streaming_pipeline_inner(txn, catalog, *right, memory)?;
613 let mut right_rows = Vec::new();
614 while let Some(result) = right_iter.next_row() {
615 right_rows.push(result?);
616 }
617 let rows = join::execute_join_with_widths(
618 left_rows,
619 right_rows,
620 join_type,
621 condition.as_ref(),
622 left_schema.len(),
623 right_schema.len(),
624 )?;
625 let mut schema = left_schema;
626 schema.extend(right_schema);
627 let projection = Projection::All(schema.iter().map(|col| col.name.clone()).collect());
628 let iter = iterator::VecIterator::new(rows, schema.clone());
629 Ok((Box::new(iter), projection, schema))
630 }
631 LogicalPlan::Aggregate {
632 input,
633 group_keys,
634 aggregates,
635 having,
636 projection,
637 } => {
638 let (input_iter, _projection, _schema) =
639 build_streaming_pipeline_inner(txn, catalog, *input, memory)?;
640 let schema = aggregate::build_aggregate_schema(&group_keys, &aggregates);
641 if let Some(policy) = memory
642 && policy.spill_directory().is_some()
643 {
644 if group_keys.is_empty() {
645 let iter = aggregate::StreamingAggregateIterator::new(
646 input_iter,
647 group_keys,
648 aggregates,
649 having,
650 schema.clone(),
651 );
652 return Ok((Box::new(iter), projection, schema));
653 }
654 let order_by = group_keys
655 .iter()
656 .cloned()
657 .map(|expr| SortExpr {
658 expr,
659 asc: true,
660 nulls_first: false,
661 })
662 .collect::<Vec<_>>();
663 let sort_iter =
664 SortIterator::new_with_policy(input_iter, &order_by, Some(policy.clone()))?;
665 let iter = aggregate::StreamingAggregateIterator::new(
666 Box::new(sort_iter),
667 group_keys,
668 aggregates,
669 having,
670 schema.clone(),
671 );
672 return Ok((Box::new(iter), projection, schema));
673 }
674
675 let parallelism = std::thread::available_parallelism()
676 .map(usize::from)
677 .unwrap_or(1);
678 if !aggregate::should_use_single_for_parallel(parallelism, &aggregates) {
679 let rows = aggregate::execute_parallel_aggregate_rows_with_policy(
680 input_iter,
681 group_keys,
682 aggregates,
683 having,
684 schema.clone(),
685 parallelism,
686 memory.cloned(),
687 1_000_000,
688 )?;
689 let iter = iterator::VecIterator::new(rows, schema.clone());
690 return Ok((Box::new(iter), projection, schema));
691 }
692
693 let mut iter = aggregate::AggregateIterator::new(
694 input_iter,
695 group_keys,
696 aggregates,
697 having,
698 schema.clone(),
699 );
700 if let Some(policy) = memory {
701 iter = iter.with_memory_policy(Some(policy.clone()));
702 }
703 Ok((Box::new(iter), projection, schema))
704 }
705 LogicalPlan::Sort { input, order_by } => {
706 let (input_iter, projection, schema) =
707 build_streaming_pipeline_inner(txn, catalog, *input, memory)?;
708 let sort_iter = if let Some(policy) = memory {
709 SortIterator::new_with_policy(input_iter, &order_by, Some(policy.clone()))?
710 } else {
711 SortIterator::new(input_iter, &order_by)?
712 };
713 Ok((Box::new(sort_iter), projection, schema))
714 }
715 LogicalPlan::Limit {
716 input,
717 limit,
718 offset,
719 } => {
720 let (input_iter, projection, schema) =
721 build_streaming_pipeline_inner(txn, catalog, *input, memory)?;
722 let limit_iter = LimitIterator::new(input_iter, limit, offset);
723 Ok((Box::new(limit_iter), projection, schema))
724 }
725 other => Err(ExecutorError::UnsupportedOperation(format!(
726 "unsupported query plan: {other:?}"
727 ))),
728 }
729}
730
731fn eval_expr(expr: &crate::planner::typed_expr::TypedExpr, row: &Row) -> Result<SqlValue> {
733 let ctx = EvalContext::new(&row.values);
734 crate::executor::evaluator::evaluate(expr, &ctx)
735}
736
737fn combine_outer_for_eval(row: &Row, outer: Option<&Row>) -> Row {
738 let Some(outer) = outer else {
739 return row.clone();
740 };
741 let mut values = Vec::with_capacity(row.len() + outer.len());
742 values.extend(row.values.clone());
743 values.extend(outer.values.clone());
744 Row::new(row.row_id, values)
745}
746
747fn execute_project_with_subqueries<
748 'txn,
749 S: KVStore + 'txn,
750 C: Catalog + ?Sized,
751 T: SqlTxn<'txn, S>,
752>(
753 txn: &mut T,
754 catalog: &C,
755 rows: Vec<Row>,
756 projection: &Projection,
757 schema: &[crate::catalog::ColumnMetadata],
758 outer: Option<&Row>,
759) -> Result<QueryResult> {
760 match projection {
761 Projection::All(_) => project::execute_project(rows, projection, schema),
762 Projection::Columns(cols)
763 if outer.is_some() || cols.iter().any(|c| subquery::contains_subquery(&c.expr)) =>
764 {
765 let columns: Vec<_> = cols
766 .iter()
767 .enumerate()
768 .map(|(i, c)| column_info_from_projection(c, i))
769 .collect();
770 let mut projected_rows = Vec::with_capacity(rows.len());
771 for row in rows {
772 let eval_row = combine_outer_for_eval(&row, outer);
773 let mut values = Vec::with_capacity(cols.len());
774 for col in cols {
775 values.push(subquery::evaluate_expr_with_subqueries(
776 txn, catalog, &col.expr, &eval_row,
777 )?);
778 }
779 projected_rows.push(values);
780 }
781 Ok(QueryResult::new(columns, projected_rows))
782 }
783 Projection::Columns(_) => project::execute_project(rows, projection, schema),
784 }
785}
786
787fn column_name_from_projection(
789 projected: &crate::planner::typed_expr::ProjectedColumn,
790 idx: usize,
791) -> String {
792 projected
793 .alias
794 .clone()
795 .or_else(|| match &projected.expr.kind {
796 crate::planner::typed_expr::TypedExprKind::ColumnRef { column, .. } => {
797 Some(column.clone())
798 }
799 _ => None,
800 })
801 .unwrap_or_else(|| format!("col_{idx}"))
802}
803
804fn column_info_from_projection(
806 projected: &crate::planner::typed_expr::ProjectedColumn,
807 idx: usize,
808) -> ColumnInfo {
809 ColumnInfo::new(
810 column_name_from_projection(projected, idx),
811 projected.expr.resolved_type.clone(),
812 )
813}
814
815fn column_infos_from_all(
817 schema: &[crate::catalog::ColumnMetadata],
818 names: &[String],
819) -> Result<Vec<ColumnInfo>> {
820 names
821 .iter()
822 .map(|name| {
823 let col = schema
824 .iter()
825 .find(|c| &c.name == name)
826 .ok_or_else(|| ExecutorError::ColumnNotFound(name.clone()))?;
827 Ok(ColumnInfo::new(name.clone(), col.data_type.clone()))
828 })
829 .collect()
830}
831
832#[cfg(test)]
833mod tests {
834 use super::*;
835 use crate::catalog::{ColumnMetadata, MemoryCatalog, TableMetadata};
836 use crate::executor::ddl::create_table::execute_create_table;
837 use crate::planner::typed_expr::TypedExpr;
838 use crate::planner::types::ResolvedType;
839 use crate::storage::TxnBridge;
840 use alopex_core::kv::memory::MemoryKV;
841 use std::sync::Arc;
842
843 #[test]
844 fn execute_query_scan_only_returns_rows() {
845 let bridge = TxnBridge::new(Arc::new(MemoryKV::new()));
846 let mut catalog = MemoryCatalog::new();
847 let table = TableMetadata::new(
848 "users",
849 vec![
850 ColumnMetadata::new("id", ResolvedType::Integer),
851 ColumnMetadata::new("name", ResolvedType::Text),
852 ],
853 );
854 let mut ddl_txn = bridge.begin_write().unwrap();
855 execute_create_table(&mut ddl_txn, &mut catalog, table.clone(), vec![], false).unwrap();
856 ddl_txn.commit().unwrap();
857
858 let mut txn = bridge.begin_write().unwrap();
859 crate::executor::dml::execute_insert(
860 &mut txn,
861 &catalog,
862 "users",
863 vec!["id".into(), "name".into()],
864 vec![vec![
865 TypedExpr::literal(
866 crate::ast::expr::Literal::Number("1".into()),
867 ResolvedType::Integer,
868 crate::Span::default(),
869 ),
870 TypedExpr::literal(
871 crate::ast::expr::Literal::String("alice".into()),
872 ResolvedType::Text,
873 crate::Span::default(),
874 ),
875 ]],
876 )
877 .unwrap();
878
879 let result = execute_query(
880 &mut txn,
881 &catalog,
882 LogicalPlan::scan(
883 "users".into(),
884 Projection::All(vec!["id".into(), "name".into()]),
885 ),
886 )
887 .unwrap();
888
889 match result {
890 ExecutionResult::Query(q) => {
891 assert_eq!(q.rows.len(), 1);
892 assert_eq!(q.columns.len(), 2);
893 assert_eq!(
894 q.rows[0],
895 vec![SqlValue::Integer(1), SqlValue::Text("alice".into())]
896 );
897 }
898 other => panic!("unexpected result {other:?}"),
899 }
900 }
901}