From 14b292a586609706953092e970216980b945153f Mon Sep 17 00:00:00 2001 From: Fedomn Date: Sun, 11 Dec 2022 21:33:45 +0800 Subject: [PATCH] feat(planner): select dummy table to support select only expressions Signed-off-by: Fedomn --- src/execution/physical_plan/mod.rs | 5 +++- .../physical_plan/physical_dummy_scan.rs | 17 +++++++++++ src/execution/physical_plan_generator.rs | 1 + src/execution/volcano_executor/dummy_scan.rs | 30 +++++++++++++++++++ src/execution/volcano_executor/mod.rs | 3 ++ .../expression/bind_constant_expression.rs | 2 +- .../binder/query_node/plan_select_node.rs | 5 +++- .../binder/tableref/bind_dummy_table_ref.rs | 18 +++++++++++ src/planner_v2/binder/tableref/mod.rs | 8 +++++ .../binder/tableref/plan_dummy_table_ref.rs | 13 ++++++++ src/planner_v2/operator/logical_dummy_scan.rs | 11 +++++++ src/planner_v2/operator/mod.rs | 8 +++++ tests/slt/select.slt | 7 +++++ 13 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 src/execution/physical_plan/physical_dummy_scan.rs create mode 100644 src/execution/volcano_executor/dummy_scan.rs create mode 100644 src/planner_v2/binder/tableref/bind_dummy_table_ref.rs create mode 100644 src/planner_v2/binder/tableref/plan_dummy_table_ref.rs create mode 100644 src/planner_v2/operator/logical_dummy_scan.rs diff --git a/src/execution/physical_plan/mod.rs b/src/execution/physical_plan/mod.rs index 226c234..f65940d 100644 --- a/src/execution/physical_plan/mod.rs +++ b/src/execution/physical_plan/mod.rs @@ -1,4 +1,5 @@ mod physical_create_table; +mod physical_dummy_scan; mod physical_expression_scan; mod physical_insert; mod physical_projection; @@ -6,6 +7,7 @@ mod physical_table_scan; use derive_new::new; pub use physical_create_table::*; +pub use physical_dummy_scan::*; pub use physical_expression_scan::*; pub use physical_insert::*; pub use physical_projection::*; @@ -17,12 +19,13 @@ use crate::types_v2::LogicalType; pub struct PhysicalOperatorBase { pub(crate) children: Vec, /// The types returned by this physical operator - pub(crate) _types: Vec, + pub(crate) types: Vec, } #[derive(Clone)] pub enum PhysicalOperator { PhysicalCreateTable(PhysicalCreateTable), + PhysicalDummyScan(PhysicalDummyScan), PhysicalExpressionScan(PhysicalExpressionScan), PhysicalInsert(PhysicalInsert), PhysicalTableScan(PhysicalTableScan), diff --git a/src/execution/physical_plan/physical_dummy_scan.rs b/src/execution/physical_plan/physical_dummy_scan.rs new file mode 100644 index 0000000..91fab77 --- /dev/null +++ b/src/execution/physical_plan/physical_dummy_scan.rs @@ -0,0 +1,17 @@ +use derive_new::new; + +use super::{PhysicalOperator, PhysicalOperatorBase}; +use crate::execution::PhysicalPlanGenerator; +use crate::planner_v2::LogicalDummyScan; + +#[derive(new, Clone)] +pub struct PhysicalDummyScan { + pub(crate) base: PhysicalOperatorBase, +} + +impl PhysicalPlanGenerator { + pub(crate) fn create_physical_dummy_scan(&self, op: LogicalDummyScan) -> PhysicalOperator { + let base = PhysicalOperatorBase::new(vec![], op.base.types); + PhysicalOperator::PhysicalDummyScan(PhysicalDummyScan::new(base)) + } +} diff --git a/src/execution/physical_plan_generator.rs b/src/execution/physical_plan_generator.rs index de102f0..944b7b2 100644 --- a/src/execution/physical_plan_generator.rs +++ b/src/execution/physical_plan_generator.rs @@ -31,6 +31,7 @@ impl PhysicalPlanGenerator { LogicalOperator::LogicalInsert(op) => self.create_physical_insert(op), LogicalOperator::LogicalGet(op) => self.create_physical_table_scan(op), LogicalOperator::LogicalProjection(op) => self.create_physical_projection(op), + LogicalOperator::LogicalDummyScan(op) => self.create_physical_dummy_scan(op), } } } diff --git a/src/execution/volcano_executor/dummy_scan.rs b/src/execution/volcano_executor/dummy_scan.rs new file mode 100644 index 0000000..d6b9b63 --- /dev/null +++ b/src/execution/volcano_executor/dummy_scan.rs @@ -0,0 +1,30 @@ +use std::collections::HashMap; +use std::sync::Arc; + +use arrow::datatypes::{Field, Schema, SchemaRef}; +use arrow::record_batch::RecordBatch; +use derive_new::new; +use futures_async_stream::try_stream; + +use crate::execution::{ExecutionContext, ExecutorError, PhysicalDummyScan}; + +#[derive(new)] +pub struct DummyScan { + pub(crate) plan: PhysicalDummyScan, +} + +impl DummyScan { + #[try_stream(boxed, ok = RecordBatch, error = ExecutorError)] + pub async fn execute(self, _context: Arc) { + let mut fields = vec![]; + for (idx, ty) in self.plan.base.types.iter().enumerate() { + fields.push(Field::new( + format!("col{}", idx).as_str(), + ty.clone().into(), + true, + )); + } + let schema = SchemaRef::new(Schema::new_with_metadata(fields, HashMap::new())); + yield RecordBatch::new_empty(schema.clone()); + } +} diff --git a/src/execution/volcano_executor/mod.rs b/src/execution/volcano_executor/mod.rs index 3b0b2d0..75b5854 100644 --- a/src/execution/volcano_executor/mod.rs +++ b/src/execution/volcano_executor/mod.rs @@ -1,4 +1,5 @@ mod create_table; +mod dummy_scan; mod expression_scan; mod insert; mod projection; @@ -7,6 +8,7 @@ use std::sync::Arc; use arrow::record_batch::RecordBatch; pub use create_table::*; +pub use dummy_scan::*; pub use expression_scan::*; use futures::stream::BoxStream; use futures::TryStreamExt; @@ -43,6 +45,7 @@ impl VolcanoExecutor { let child_executor = self.build(child, context.clone()); Projection::new(op, child_executor).execute(context) } + PhysicalOperator::PhysicalDummyScan(op) => DummyScan::new(op).execute(context), } } diff --git a/src/planner_v2/binder/expression/bind_constant_expression.rs b/src/planner_v2/binder/expression/bind_constant_expression.rs index c0d2d77..e6dcb70 100644 --- a/src/planner_v2/binder/expression/bind_constant_expression.rs +++ b/src/planner_v2/binder/expression/bind_constant_expression.rs @@ -18,7 +18,7 @@ impl ExpressionBinder<'_> { result_types: &mut Vec, ) -> Result { let scalar: ScalarValue = v.into(); - let base = BoundExpressionBase::new("".to_string(), scalar.get_logical_type()); + let base = BoundExpressionBase::new(scalar.to_string(), scalar.get_logical_type()); result_names.push(base.alias.clone()); result_types.push(base.return_type.clone()); let expr = diff --git a/src/planner_v2/binder/query_node/plan_select_node.rs b/src/planner_v2/binder/query_node/plan_select_node.rs index 864d65e..f2f1738 100644 --- a/src/planner_v2/binder/query_node/plan_select_node.rs +++ b/src/planner_v2/binder/query_node/plan_select_node.rs @@ -1,5 +1,7 @@ use super::BoundSelectNode; -use crate::planner_v2::BoundTableRef::{BoundBaseTableRef, BoundExpressionListRef}; +use crate::planner_v2::BoundTableRef::{ + BoundBaseTableRef, BoundDummyTableRef, BoundExpressionListRef, +}; use crate::planner_v2::{ BindError, Binder, BoundCastExpression, BoundStatement, LogicalOperator, LogicalOperatorBase, LogicalProjection, @@ -16,6 +18,7 @@ impl Binder { self.create_plan_for_expression_list_ref(bound_ref)? } BoundBaseTableRef(bound_ref) => self.create_plan_for_base_tabel_ref(*bound_ref)?, + BoundDummyTableRef(bound_ref) => self.create_plan_for_dummy_table_ref(bound_ref)?, }; let root = LogicalOperator::LogicalProjection(LogicalProjection::new( diff --git a/src/planner_v2/binder/tableref/bind_dummy_table_ref.rs b/src/planner_v2/binder/tableref/bind_dummy_table_ref.rs new file mode 100644 index 0000000..1a922d2 --- /dev/null +++ b/src/planner_v2/binder/tableref/bind_dummy_table_ref.rs @@ -0,0 +1,18 @@ +use derive_new::new; + +use super::BoundTableRef; +use crate::planner_v2::{BindError, Binder}; + +#[derive(new, Debug)] +pub struct BoundDummyTableRef { + pub(crate) bind_index: usize, +} + +impl Binder { + pub fn bind_dummy_table_ref(&mut self) -> Result { + let table_index = self.generate_table_index(); + let bound_tabel_ref = + BoundTableRef::BoundDummyTableRef(BoundDummyTableRef::new(table_index)); + Ok(bound_tabel_ref) + } +} diff --git a/src/planner_v2/binder/tableref/mod.rs b/src/planner_v2/binder/tableref/mod.rs index 620acd9..4cd88f4 100644 --- a/src/planner_v2/binder/tableref/mod.rs +++ b/src/planner_v2/binder/tableref/mod.rs @@ -1,10 +1,14 @@ mod bind_base_table_ref; +mod bind_dummy_table_ref; mod bind_expression_list_ref; mod plan_base_table_ref; +mod plan_dummy_table_ref; mod plan_expression_list_ref; pub use bind_base_table_ref::*; +pub use bind_dummy_table_ref::*; pub use bind_expression_list_ref::*; pub use plan_base_table_ref::*; +pub use plan_dummy_table_ref::*; pub use plan_expression_list_ref::*; use super::{BindError, Binder}; @@ -13,6 +17,7 @@ use super::{BindError, Binder}; pub enum BoundTableRef { BoundExpressionListRef(BoundExpressionListRef), BoundBaseTableRef(Box), + BoundDummyTableRef(BoundDummyTableRef), } impl Binder { @@ -20,6 +25,9 @@ impl Binder { &mut self, table_refs: &[sqlparser::ast::TableWithJoins], ) -> Result { + if table_refs.is_empty() { + return self.bind_dummy_table_ref(); + } let first_table = table_refs[0].clone(); match first_table.relation.clone() { sqlparser::ast::TableFactor::Table { .. } => { diff --git a/src/planner_v2/binder/tableref/plan_dummy_table_ref.rs b/src/planner_v2/binder/tableref/plan_dummy_table_ref.rs new file mode 100644 index 0000000..0ac239e --- /dev/null +++ b/src/planner_v2/binder/tableref/plan_dummy_table_ref.rs @@ -0,0 +1,13 @@ +use super::BoundDummyTableRef; +use crate::planner_v2::{BindError, Binder, LogicalDummyScan, LogicalOperator}; + +impl Binder { + pub fn create_plan_for_dummy_table_ref( + &mut self, + bound_ref: BoundDummyTableRef, + ) -> Result { + Ok(LogicalOperator::LogicalDummyScan(LogicalDummyScan::new( + bound_ref.bind_index, + ))) + } +} diff --git a/src/planner_v2/operator/logical_dummy_scan.rs b/src/planner_v2/operator/logical_dummy_scan.rs new file mode 100644 index 0000000..2bc81b0 --- /dev/null +++ b/src/planner_v2/operator/logical_dummy_scan.rs @@ -0,0 +1,11 @@ +use derive_new::new; + +use super::LogicalOperatorBase; + +/// LogicalDummyScan represents a dummy scan returning nothing. +#[derive(new, Debug)] +pub struct LogicalDummyScan { + #[new(default)] + pub(crate) base: LogicalOperatorBase, + pub(crate) table_idx: usize, +} diff --git a/src/planner_v2/operator/mod.rs b/src/planner_v2/operator/mod.rs index f82991f..34c9cec 100644 --- a/src/planner_v2/operator/mod.rs +++ b/src/planner_v2/operator/mod.rs @@ -1,12 +1,14 @@ use crate::types_v2::LogicalType; mod logical_create_table; +mod logical_dummy_scan; mod logical_expression_get; mod logical_get; mod logical_insert; mod logical_projection; use derive_new::new; pub use logical_create_table::*; +pub use logical_dummy_scan::*; pub use logical_expression_get::*; pub use logical_get::*; pub use logical_insert::*; @@ -26,6 +28,7 @@ pub struct LogicalOperatorBase { #[derive(Debug)] pub enum LogicalOperator { LogicalCreateTable(LogicalCreateTable), + LogicalDummyScan(LogicalDummyScan), LogicalExpressionGet(LogicalExpressionGet), LogicalInsert(LogicalInsert), LogicalGet(LogicalGet), @@ -40,6 +43,7 @@ impl LogicalOperator { LogicalOperator::LogicalInsert(op) => &mut op.base.children, LogicalOperator::LogicalGet(op) => &mut op.base.children, LogicalOperator::LogicalProjection(op) => &mut op.base.children, + LogicalOperator::LogicalDummyScan(op) => &mut op.base.children, } } @@ -50,6 +54,7 @@ impl LogicalOperator { LogicalOperator::LogicalInsert(op) => &mut op.base.expressioins, LogicalOperator::LogicalGet(op) => &mut op.base.expressioins, LogicalOperator::LogicalProjection(op) => &mut op.base.expressioins, + LogicalOperator::LogicalDummyScan(op) => &mut op.base.expressioins, } } @@ -60,6 +65,7 @@ impl LogicalOperator { LogicalOperator::LogicalInsert(op) => &op.base.types, LogicalOperator::LogicalGet(op) => &op.base.types, LogicalOperator::LogicalProjection(op) => &op.base.types, + LogicalOperator::LogicalDummyScan(op) => &op.base.types, } } @@ -77,6 +83,7 @@ impl LogicalOperator { LogicalOperator::LogicalProjection(op) => { self.generate_column_bindings(op.table_idx, op.base.expressioins.len()) } + LogicalOperator::LogicalDummyScan(op) => vec![ColumnBinding::new(op.table_idx, 0)], } } @@ -102,6 +109,7 @@ impl LogicalOperator { .collect::>(); op.base.types.extend(types); } + LogicalOperator::LogicalDummyScan(op) => op.base.types.push(LogicalType::Integer), } } diff --git a/tests/slt/select.slt b/tests/slt/select.slt index e7e0c55..0f5f219 100644 --- a/tests/slt/select.slt +++ b/tests/slt/select.slt @@ -37,3 +37,10 @@ select t.v1 as a, v2 as b from t1 as t; ---- 1 4 2 5 + + +onlyif sqlrs_v2 +query III +select 1, 2.3, '😇', true, null; +---- +1 2.3 😇 true null