From 1ecdc05bdf5062c24f14541d0d06ec189fc5f847 Mon Sep 17 00:00:00 2001 From: dragonliu Date: Thu, 17 Oct 2024 14:22:43 +0800 Subject: [PATCH 1/3] fix(query): support subquery in pivot --- src/query/ast/src/ast/format/syntax/query.rs | 12 ++ src/query/ast/src/ast/query.rs | 31 +++- .../ast/src/ast/statements/merge_into.rs | 2 + src/query/ast/src/parser/query.rs | 69 +++++---- .../service/src/interpreters/interpreter.rs | 3 +- src/query/service/src/schedulers/scheduler.rs | 15 ++ .../planner/binder/bind_query/bind_select.rs | 133 ++++++++++++++++-- .../sql/src/planner/binder/bind_query/mod.rs | 2 + .../binder/bind_query/subquery_executor.rs | 22 +++ .../binder/bind_table_reference/bind.rs | 2 + src/query/sql/src/planner/binder/binder.rs | 12 ++ .../src/planner/binder/insert_multi_table.rs | 2 + src/query/sql/src/planner/binder/mod.rs | 1 + src/query/sql/src/planner/planner.rs | 10 +- .../planner/semantic/distinct_to_groupby.rs | 2 + src/tests/sqlsmith/src/sql_gen/query.rs | 2 + tests/sqllogictests/suites/query/pivot.test | 33 +++++ 17 files changed, 312 insertions(+), 41 deletions(-) create mode 100644 src/query/sql/src/planner/binder/bind_query/subquery_executor.rs diff --git a/src/query/ast/src/ast/format/syntax/query.rs b/src/query/ast/src/ast/format/syntax/query.rs index 0a4e049b10a7..deb6fafe30da 100644 --- a/src/query/ast/src/ast/format/syntax/query.rs +++ b/src/query/ast/src/ast/format/syntax/query.rs @@ -369,6 +369,8 @@ pub(crate) fn pretty_table(table: TableReference) -> RcDoc<'static> { lateral, subquery, alias, + pivot, + unpivot, } => (if lateral { RcDoc::text("LATERAL") } else { @@ -379,6 +381,16 @@ pub(crate) fn pretty_table(table: TableReference) -> RcDoc<'static> { RcDoc::text(format!(" AS {alias}")) } else { RcDoc::nil() + }) + .append(if let Some(pivot) = pivot { + RcDoc::text(format!(" {pivot}")) + } else { + RcDoc::nil() + }) + .append(if let Some(unpivot) = unpivot { + RcDoc::text(format!(" {unpivot}")) + } else { + RcDoc::nil() }), TableReference::TableFunction { span: _, diff --git a/src/query/ast/src/ast/query.rs b/src/query/ast/src/ast/query.rs index e7448216dfec..76893ba29623 100644 --- a/src/query/ast/src/ast/query.rs +++ b/src/query/ast/src/ast/query.rs @@ -533,17 +533,30 @@ impl Display for TimeTravelPoint { } } +#[derive(Debug, Clone, PartialEq, Drive, DriveMut)] +pub enum PivotValues { + ColumnValues(Vec), + Subquery(Box), +} + #[derive(Debug, Clone, PartialEq, Drive, DriveMut)] pub struct Pivot { pub aggregate: Expr, pub value_column: Identifier, - pub values: Vec, + pub values: PivotValues, } impl Display for Pivot { fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { write!(f, "PIVOT({} FOR {} IN (", self.aggregate, self.value_column)?; - write_comma_separated_list(f, &self.values)?; + match &self.values { + PivotValues::ColumnValues(column_values) => { + write_comma_separated_list(f, column_values)?; + } + PivotValues::Subquery(subquery) => { + write!(f, "{}", subquery)?; + } + } write!(f, "))")?; Ok(()) } @@ -740,6 +753,8 @@ pub enum TableReference { lateral: bool, subquery: Box, alias: Option, + pivot: Option>, + unpivot: Option>, }, Join { span: Span, @@ -757,6 +772,7 @@ impl TableReference { pub fn pivot(&self) -> Option<&Pivot> { match self { TableReference::Table { pivot, .. } => pivot.as_ref().map(|b| b.as_ref()), + TableReference::Subquery { pivot, .. } => pivot.as_ref().map(|b| b.as_ref()), _ => None, } } @@ -764,6 +780,7 @@ impl TableReference { pub fn unpivot(&self) -> Option<&Unpivot> { match self { TableReference::Table { unpivot, .. } => unpivot.as_ref().map(|b| b.as_ref()), + TableReference::Subquery { unpivot, .. } => unpivot.as_ref().map(|b| b.as_ref()), _ => None, } } @@ -862,6 +879,8 @@ impl Display for TableReference { lateral, subquery, alias, + pivot, + unpivot, } => { if *lateral { write!(f, "LATERAL ")?; @@ -870,6 +889,14 @@ impl Display for TableReference { if let Some(alias) = alias { write!(f, " AS {alias}")?; } + + if let Some(pivot) = pivot { + write!(f, " {pivot}")?; + } + + if let Some(unpivot) = unpivot { + write!(f, " {unpivot}")?; + } } TableReference::Join { span: _, join } => { write!(f, "{}", join.left)?; diff --git a/src/query/ast/src/ast/statements/merge_into.rs b/src/query/ast/src/ast/statements/merge_into.rs index 19d3b44ddc8d..e56ffee99f8d 100644 --- a/src/query/ast/src/ast/statements/merge_into.rs +++ b/src/query/ast/src/ast/statements/merge_into.rs @@ -204,6 +204,8 @@ impl MergeSource { lateral: false, subquery: query.clone(), alias: Some(source_alias.clone()), + pivot: None, + unpivot: None, }, Self::Table { catalog, diff --git a/src/query/ast/src/parser/query.rs b/src/query/ast/src/parser/query.rs index 7f2b170edf80..cd9cb44be96b 100644 --- a/src/query/ast/src/parser/query.rs +++ b/src/query/ast/src/parser/query.rs @@ -719,6 +719,8 @@ pub enum TableReferenceElement { lateral: bool, subquery: Box, alias: Option, + pivot: Option>, + unpivot: Option>, }, // [NATURAL] [INNER|OUTER|CROSS|...] JOIN Join { @@ -736,28 +738,6 @@ pub enum TableReferenceElement { } pub fn table_reference_element(i: Input) -> IResult> { - // PIVOT(expr FOR col IN (ident, ...)) - let pivot = map( - rule! { - PIVOT ~ "(" ~ #expr ~ FOR ~ #ident ~ IN ~ "(" ~ #comma_separated_list1(expr) ~ ")" ~ ")" - }, - |(_pivot, _, aggregate, _for, value_column, _in, _, values, _, _)| Pivot { - aggregate, - value_column, - values, - }, - ); - // UNPIVOT(ident for ident IN (ident, ...)) - let unpivot = map( - rule! { - UNPIVOT ~ "(" ~ #ident ~ FOR ~ #ident ~ IN ~ "(" ~ #comma_separated_list1(ident) ~ ")" ~ ")" - }, - |(_unpivot, _, value_column, _for, column_name, _in, _, names, _, _)| Unpivot { - value_column, - column_name, - names, - }, - ); let aliased_table = map( rule! { #dot_separated_idents_1_to_3 ~ #temporal_clause? ~ #with_options? ~ #table_alias? ~ #pivot? ~ #unpivot? ~ SAMPLE? ~ (BLOCK ~ "(" ~ #expr ~ ")")? ~ (ROW ~ "(" ~ #expr ~ ROWS? ~ ")")? @@ -825,12 +805,14 @@ pub fn table_reference_element(i: Input) -> IResult IResult IResult { + map( + rule! { + PIVOT ~ "(" ~ #expr ~ FOR ~ #ident ~ IN ~ "(" ~ #pivot_values ~ ")" ~ ")" + }, + |(_pivot, _, aggregate, _for, value_column, _in, _, values, _, _)| Pivot { + aggregate, + value_column, + values, + }, + )(i) +} + +// UNPIVOT(ident for ident IN (ident, ...)) +fn unpivot(i: Input) -> IResult { + map( + rule! { + UNPIVOT ~ "(" ~ #ident ~ FOR ~ #ident ~ IN ~ "(" ~ #comma_separated_list1(ident) ~ ")" ~ ")" + }, + |(_unpivot, _, value_column, _for, column_name, _in, _, names, _, _)| Unpivot { + value_column, + column_name, + names, + }, + )(i) +} + +fn pivot_values(i: Input) -> IResult { + alt(( + map(comma_separated_list1(expr), PivotValues::ColumnValues), + map(query, |q| PivotValues::Subquery(Box::new(q))), + ))(i) +} + fn get_table_sample( sample: Option<&Token>, block_level_sample: Option<(&Token, &Token, Expr, &Token)>, @@ -966,11 +983,15 @@ impl<'a, I: Iterator>> PrattParser lateral, subquery, alias, + pivot, + unpivot, } => TableReference::Subquery { span: transform_span(input.span.tokens), lateral, subquery, alias, + pivot, + unpivot, }, TableReferenceElement::Stage { location, diff --git a/src/query/service/src/interpreters/interpreter.rs b/src/query/service/src/interpreters/interpreter.rs index 1f220e17edf4..675a7d3b12e0 100644 --- a/src/query/service/src/interpreters/interpreter.rs +++ b/src/query/service/src/interpreters/interpreter.rs @@ -203,9 +203,10 @@ fn log_query_finished(ctx: &QueryContext, error: Option, has_profiles /// /// This function is used to plan the SQL. If an error occurs, we will log the query start and finished. pub async fn interpreter_plan_sql(ctx: Arc, sql: &str) -> Result<(Plan, PlanExtras)> { - let mut planner = Planner::new_with_sample_executor( + let mut planner = Planner::new_with_sample_and_subquery_executors( ctx.clone(), Arc::new(ServiceQueryExecutor::new(ctx.clone())), + Arc::new(ServiceQueryExecutor::new(ctx.clone())), ); let result = planner.plan_sql(sql).await; let short_sql = short_sql( diff --git a/src/query/service/src/schedulers/scheduler.rs b/src/query/service/src/schedulers/scheduler.rs index 0fab2802d0ef..65b8433264c5 100644 --- a/src/query/service/src/schedulers/scheduler.rs +++ b/src/query/service/src/schedulers/scheduler.rs @@ -19,9 +19,12 @@ use databend_common_exception::Result; use databend_common_expression::DataBlock; use databend_common_pipeline_core::processors::ProcessorPtr; use databend_common_pipeline_sinks::EmptySink; +use databend_common_sql::binder::SubqueryExecutor; use databend_common_sql::optimizer::QuerySampleExecutor; +use databend_common_sql::Planner; use futures_util::TryStreamExt; +use crate::interpreters::InterpreterFactory; use crate::pipelines::executor::ExecutorSettings; use crate::pipelines::executor::PipelinePullingExecutor; use crate::pipelines::PipelineBuildResult; @@ -144,3 +147,15 @@ impl QuerySampleExecutor for ServiceQueryExecutor { .await } } + +#[async_trait] +impl SubqueryExecutor for ServiceQueryExecutor { + async fn execute_query(&self, query_sql: &str) -> Result> { + let mut planner = Planner::new(self.ctx.clone()); + let (plan, _) = planner.plan_sql(query_sql).await?; + let interpreter = InterpreterFactory::get(self.ctx.clone(), &plan).await?; + let stream = interpreter.execute(self.ctx.clone()).await?; + let blocks = stream.try_collect::>().await?; + Ok(blocks) + } +} diff --git a/src/query/sql/src/planner/binder/bind_query/bind_select.rs b/src/query/sql/src/planner/binder/bind_query/bind_select.rs index 4fd37192b828..256778a22835 100644 --- a/src/query/sql/src/planner/binder/bind_query/bind_select.rs +++ b/src/query/sql/src/planner/binder/bind_query/bind_select.rs @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::sync::Arc; + use databend_common_ast::ast::BinaryOperator; use databend_common_ast::ast::ColumnID; use databend_common_ast::ast::ColumnPosition; @@ -26,16 +28,22 @@ use databend_common_ast::ast::JoinCondition; use databend_common_ast::ast::JoinOperator; use databend_common_ast::ast::Literal; use databend_common_ast::ast::OrderByExpr; +use databend_common_ast::ast::Pivot; +use databend_common_ast::ast::PivotValues; use databend_common_ast::ast::SelectStmt; use databend_common_ast::ast::SelectTarget; use databend_common_ast::ast::TableReference; +use databend_common_ast::Range; use databend_common_ast::Span; use databend_common_exception::ErrorCode; use databend_common_exception::Result; +use databend_common_expression::DataBlock; +use databend_common_expression::ScalarRef; use derive_visitor::Drive; use derive_visitor::Visitor; use log::warn; +use crate::binder::SubqueryExecutor; use crate::optimizer::SExpr; use crate::planner::binder::BindContext; use crate::planner::binder::Binder; @@ -94,7 +102,8 @@ impl Binder { let mut rewriter = SelectRewriter::new( from_context.all_column_bindings(), self.name_resolution_ctx.unquoted_ident_case_sensitive, - ); + ) + .with_subquery_executor(self.subquery_executor.clone()); let new_stmt = rewriter.rewrite(stmt)?; let stmt = new_stmt.as_ref().unwrap_or(stmt); @@ -253,6 +262,7 @@ struct SelectRewriter<'a> { column_binding: &'a [ColumnBinding], new_stmt: Option, is_unquoted_ident_case_sensitive: bool, + subquery_executor: Option>, } // helper functions to SelectRewriter @@ -360,9 +370,18 @@ impl<'a> SelectRewriter<'a> { column_binding, new_stmt: None, is_unquoted_ident_case_sensitive, + subquery_executor: None, } } + pub fn with_subquery_executor( + mut self, + subquery_executor: Option>, + ) -> Self { + self.subquery_executor = subquery_executor; + self + } + fn rewrite(&mut self, stmt: &SelectStmt) -> Result> { self.rewrite_pivot(stmt)?; self.rewrite_unpivot(stmt)?; @@ -419,7 +438,68 @@ impl<'a> SelectRewriter<'a> { name: format!("{}_if", aggregate_name.name), ..aggregate_name.clone() }; - for value in &pivot.values { + + // The values of pivot are divided into two categories: Column(Vec) and Subquery. + // For Column, it must be literal. For Subquery, it should first be executed, + // and the processing of the result will be consistent with that of Column. + // Therefore, the subquery can only return one column, and only return a string type. + match &pivot.values { + PivotValues::ColumnValues(values) => { + self.process_pivot_column_values( + pivot, + values, + &new_aggregate_name, + aggregate_args, + &mut new_select_list, + stmt, + )?; + } + PivotValues::Subquery(subquery) => { + let query_sql = subquery.to_string(); + if let Some(subquery_executor) = &self.subquery_executor { + let data_blocks = databend_common_base::runtime::block_on(async move { + subquery_executor.execute_query(&query_sql).await + })?; + let values = self.extract_column_values_from_data_blocks(&data_blocks)?; + self.process_pivot_column_values( + pivot, + &values, + &new_aggregate_name, + aggregate_args, + &mut new_select_list, + stmt, + )?; + } else { + return Err(ErrorCode::Internal( + "SelectRewriter's Subquery executor is not set", + )); + }; + } + } + + if let Some(ref mut new_stmt) = self.new_stmt { + new_stmt.select_list = new_select_list; + new_stmt.group_by = Some(new_group_by); + } else { + self.new_stmt = Some(SelectStmt { + select_list: new_select_list, + group_by: Some(new_group_by), + ..stmt.clone() + }); + } + Ok(()) + } + + fn process_pivot_column_values( + &self, + pivot: &Pivot, + values: &[Expr], + new_aggregate_name: &Identifier, + aggregate_args: &[Expr], + new_select_list: &mut Vec, + stmt: &SelectStmt, + ) -> Result<()> { + for value in values { let mut args = aggregate_args.to_vec(); args.push(Self::expr_eq_from_col_and_value( pivot.value_column.clone(), @@ -433,18 +513,47 @@ impl<'a> SelectRewriter<'a> { Some(Identifier::from_name(stmt.span, &alias)), )); } + Ok(()) + } - if let Some(ref mut new_stmt) = self.new_stmt { - new_stmt.select_list = new_select_list; - new_stmt.group_by = Some(new_group_by); - } else { - self.new_stmt = Some(SelectStmt { - select_list: new_select_list, - group_by: Some(new_group_by), - ..stmt.clone() - }); + fn extract_column_values_from_data_blocks( + &self, + data_blocks: &[DataBlock], + ) -> Result> { + let mut values: Vec = vec![]; + let mut current_span_pos = 0; + for block in data_blocks { + let columns = block.columns(); + if columns.len() != 1 { + return Err(ErrorCode::Internal( + "The subquery of `pivot in` must return one column", + )); + } + let value = columns[0].to_column(block.num_rows()); + for row in value.iter() { + match &row { + ScalarRef::String(_) => { + let row_str = row.to_string().trim_matches('\'').to_string(); + let length = row_str.len() as u32; + let literal = Expr::Literal { + span: Some(Range { + start: current_span_pos, + end: current_span_pos + length, + }), + value: Literal::String(row_str), + }; + values.push(literal); + current_span_pos += length; + } + _ => { + return Err(ErrorCode::Internal( + "The subquery of `pivot in` must return a string type", + )); + } + } + } } - Ok(()) + Ok(values) } fn rewrite_unpivot(&mut self, stmt: &SelectStmt) -> Result<()> { diff --git a/src/query/sql/src/planner/binder/bind_query/mod.rs b/src/query/sql/src/planner/binder/bind_query/mod.rs index a100b232fa51..d7962974f4c8 100644 --- a/src/query/sql/src/planner/binder/bind_query/mod.rs +++ b/src/query/sql/src/planner/binder/bind_query/mod.rs @@ -17,7 +17,9 @@ mod bind_limit; mod bind_select; mod bind_set_expr; mod bind_value; +mod subquery_executor; pub use bind_select::MaxColumnPosition; pub use bind_value::bind_values; pub use bind_value::ExpressionScanContext; +pub use subquery_executor::SubqueryExecutor; diff --git a/src/query/sql/src/planner/binder/bind_query/subquery_executor.rs b/src/query/sql/src/planner/binder/bind_query/subquery_executor.rs new file mode 100644 index 000000000000..e2ca0e07693a --- /dev/null +++ b/src/query/sql/src/planner/binder/bind_query/subquery_executor.rs @@ -0,0 +1,22 @@ +// Copyright 2021 Datafuse Labs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use async_trait::async_trait; +use databend_common_exception::Result; +use databend_common_expression::DataBlock; + +#[async_trait] +pub trait SubqueryExecutor: Send + Sync { + async fn execute_query(&self, query_sql: &str) -> Result>; +} diff --git a/src/query/sql/src/planner/binder/bind_table_reference/bind.rs b/src/query/sql/src/planner/binder/bind_table_reference/bind.rs index 0821babf0fd4..92b9bcf18834 100644 --- a/src/query/sql/src/planner/binder/bind_table_reference/bind.rs +++ b/src/query/sql/src/planner/binder/bind_table_reference/bind.rs @@ -70,6 +70,8 @@ impl Binder { lateral, subquery, alias, + pivot: _, + unpivot: _, } => self.bind_subquery(bind_context, *lateral, subquery, alias), TableReference::Location { span: _, diff --git a/src/query/sql/src/planner/binder/binder.rs b/src/query/sql/src/planner/binder/binder.rs index 353207ad7e58..c10590bd94e0 100644 --- a/src/query/sql/src/planner/binder/binder.rs +++ b/src/query/sql/src/planner/binder/binder.rs @@ -51,6 +51,7 @@ use crate::binder::util::illegal_ident_name; use crate::binder::wrap_cast; use crate::binder::ColumnBindingBuilder; use crate::binder::CteInfo; +use crate::binder::SubqueryExecutor; use crate::normalize_identifier; use crate::optimizer::SExpr; use crate::plans::CreateFileFormatPlan; @@ -109,6 +110,8 @@ pub struct Binder { pub bind_recursive_cte: bool, pub enable_result_cache: bool, + + pub subquery_executor: Option>, } impl<'a> Binder { @@ -136,9 +139,18 @@ impl<'a> Binder { expression_scan_context: ExpressionScanContext::new(), bind_recursive_cte: false, enable_result_cache, + subquery_executor: None, } } + pub fn with_subquery_executor( + mut self, + subquery_executor: Option>, + ) -> Self { + self.subquery_executor = subquery_executor; + self + } + #[async_backtrace::framed] #[fastrace::trace] pub async fn bind(mut self, stmt: &Statement) -> Result { diff --git a/src/query/sql/src/planner/binder/insert_multi_table.rs b/src/query/sql/src/planner/binder/insert_multi_table.rs index 48bb96f40b28..c8f0ca98a898 100644 --- a/src/query/sql/src/planner/binder/insert_multi_table.rs +++ b/src/query/sql/src/planner/binder/insert_multi_table.rs @@ -57,6 +57,8 @@ impl Binder { span: None, lateral: false, alias: None, + pivot: None, + unpivot: None, }; let (s_expr, bind_context) = self.bind_table_reference(bind_context, &table_ref)?; diff --git a/src/query/sql/src/planner/binder/mod.rs b/src/query/sql/src/planner/binder/mod.rs index 3a7d53ea9ee7..6015af656862 100644 --- a/src/query/sql/src/planner/binder/mod.rs +++ b/src/query/sql/src/planner/binder/mod.rs @@ -61,6 +61,7 @@ pub use bind_mutation::target_probe; pub use bind_mutation::MutationStrategy; pub use bind_mutation::MutationType; pub use bind_query::bind_values; +pub use bind_query::SubqueryExecutor; pub use bind_table_reference::parse_result_scan_args; pub use binder::Binder; pub use builders::*; diff --git a/src/query/sql/src/planner/planner.rs b/src/query/sql/src/planner/planner.rs index 93bc0722c2ac..a5b6cb45cced 100644 --- a/src/query/sql/src/planner/planner.rs +++ b/src/query/sql/src/planner/planner.rs @@ -37,6 +37,7 @@ use parking_lot::RwLock; use super::semantic::AggregateRewriter; use super::semantic::DistinctToGroupBy; +use crate::binder::SubqueryExecutor; use crate::optimizer::optimize; use crate::optimizer::OptimizerContext; use crate::optimizer::QuerySampleExecutor; @@ -55,6 +56,7 @@ const PROBE_INSERT_MAX_TOKENS: usize = 128 * 8; pub struct Planner { pub(crate) ctx: Arc, pub(crate) sample_executor: Option>, + pub(crate) subquery_executor: Option>, } #[derive(Debug, Clone)] @@ -68,16 +70,19 @@ impl Planner { Planner { ctx, sample_executor: None, + subquery_executor: None, } } - pub fn new_with_sample_executor( + pub fn new_with_sample_and_subquery_executors( ctx: Arc, sample_executor: Arc, + subquery_executor: Arc, ) -> Self { Planner { ctx, sample_executor: Some(sample_executor), + subquery_executor: Some(subquery_executor), } } @@ -197,7 +202,8 @@ impl Planner { CatalogManager::instance(), name_resolution_ctx, metadata.clone(), - ); + ) + .with_subquery_executor(self.subquery_executor.clone()); // Indicate binder there is no need to collect column statistics for the binding table. self.ctx diff --git a/src/query/sql/src/planner/semantic/distinct_to_groupby.rs b/src/query/sql/src/planner/semantic/distinct_to_groupby.rs index cb20b812b55f..bd9f964e5595 100644 --- a/src/query/sql/src/planner/semantic/distinct_to_groupby.rs +++ b/src/query/sql/src/planner/semantic/distinct_to_groupby.rs @@ -132,6 +132,8 @@ impl DistinctToGroupBy { name: Identifier::from_name(None, sub_query_name), columns: vec![Identifier::from_name(None, "_1")], }), + pivot: None, + unpivot: None, }], selection: None, group_by: None, diff --git a/src/tests/sqlsmith/src/sql_gen/query.rs b/src/tests/sqlsmith/src/sql_gen/query.rs index 834a792a7389..9ef1f0b68c66 100644 --- a/src/tests/sqlsmith/src/sql_gen/query.rs +++ b/src/tests/sqlsmith/src/sql_gen/query.rs @@ -692,6 +692,8 @@ impl<'a, R: Rng> SqlGenerator<'a, R> { lateral: false, subquery: Box::new(subquery), alias: Some(alias), + pivot: None, + unpivot: None, } } diff --git a/tests/sqllogictests/suites/query/pivot.test b/tests/sqllogictests/suites/query/pivot.test index c6a1f47f7a97..eb5307c5e43c 100644 --- a/tests/sqllogictests/suites/query/pivot.test +++ b/tests/sqllogictests/suites/query/pivot.test @@ -46,5 +46,38 @@ SELECT EMPID, 1 10400 8000 11000 18000 2 39500 90700 12000 5300 +query IIIII +SELECT empid,jan,feb,mar,apr FROM ( + SELECT * + FROM (SELECT * FROM monthly_sales) + PIVOT(SUM(amount) FOR MONTH IN ('JAN', 'FEB', 'MAR', 'APR')) + ORDER BY EMPID +); +---- +1 10400 8000 11000 18000 +2 39500 90700 12000 5300 + +query IIIII +SELECT empid,jan,feb,mar,apr FROM ( + SELECT * + FROM monthly_sales + PIVOT(SUM(amount) FOR MONTH IN (SELECT DISTINCT month FROM monthly_sales)) + ORDER BY EMPID +); +---- +1 10400 8000 11000 18000 +2 39500 90700 12000 5300 + +query IIIII +SELECT empid,jan,feb,mar,apr FROM ( + SELECT * + FROM (SELECT * FROM monthly_sales) + PIVOT(SUM(amount) FOR MONTH IN (SELECT DISTINCT month FROM monthly_sales)) + ORDER BY EMPID +); +---- +1 10400 8000 11000 18000 +2 39500 90700 12000 5300 + statement ok drop table if exists monthly_sales; From bf25a2fb68e9e2313fce055bb5af7aa647c3bf74 Mon Sep 17 00:00:00 2001 From: dragonliu Date: Fri, 18 Oct 2024 16:35:44 +0800 Subject: [PATCH 2/3] add pivot and unpivot sqllogictests, fix unit-test --- src/query/ast/tests/it/parser.rs | 4 + src/query/ast/tests/it/testdata/query.txt | 1150 +++++++++++++++-- src/query/ast/tests/it/testdata/stmt.txt | 2 + .../planner/binder/bind_query/bind_select.rs | 33 +- tests/sqllogictests/suites/query/pivot.test | 16 + tests/sqllogictests/suites/query/unpivot.test | 20 + 6 files changed, 1093 insertions(+), 132 deletions(-) diff --git a/src/query/ast/tests/it/parser.rs b/src/query/ast/tests/it/parser.rs index 961c322b92e5..a124da116913 100644 --- a/src/query/ast/tests/it/parser.rs +++ b/src/query/ast/tests/it/parser.rs @@ -1092,7 +1092,11 @@ fn test_query() { r#"SELECT * FROM (((SELECT *) EXCEPT (SELECT *))) foo"#, r#"SELECT * FROM (SELECT * FROM xyu ORDER BY x, y) AS xyu"#, r#"select * from monthly_sales pivot(sum(amount) for month in ('JAN', 'FEB', 'MAR', 'APR')) order by empid"#, + r#"select * from (select * from monthly_sales) pivot(sum(amount) for month in ('JAN', 'FEB', 'MAR', 'APR')) order by empid"#, + r#"select * from monthly_sales pivot(sum(amount) for month in (select distinct month from monthly_sales)) order by empid"#, + r#"select * from (select * from monthly_sales) pivot(sum(amount) for month in ((select distinct month from monthly_sales))) order by empid"#, r#"select * from monthly_sales_1 unpivot(sales for month in (jan, feb, mar, april)) order by empid"#, + r#"select * from (select * from monthly_sales_1) unpivot(sales for month in (jan, feb, mar, april)) order by empid"#, r#"select * from range(1, 2)"#, r#"select sum(a) over w from customer window w as (partition by a order by b)"#, r#"select a, sum(a) over w, sum(a) over w1, sum(a) over w2 from t1 window w as (partition by a), w2 as (w1 rows current row), w1 as (w order by a) order by a"#, diff --git a/src/query/ast/tests/it/testdata/query.txt b/src/query/ast/tests/it/testdata/query.txt index 15e35dddaca8..c5bb30f5904b 100644 --- a/src/query/ast/tests/it/testdata/query.txt +++ b/src/query/ast/tests/it/testdata/query.txt @@ -3807,6 +3807,8 @@ Query { columns: [], }, ), + pivot: None, + unpivot: None, }, ], selection: None, @@ -5254,6 +5256,8 @@ Query { columns: [], }, ), + pivot: None, + unpivot: None, }, ], selection: None, @@ -5394,6 +5398,8 @@ Query { columns: [], }, ), + pivot: None, + unpivot: None, }, ], selection: None, @@ -5566,6 +5572,8 @@ Query { columns: [], }, ), + pivot: None, + unpivot: None, }, ], selection: None, @@ -5680,40 +5688,42 @@ Query { quote: None, ident_type: None, }, - values: [ - Literal { - span: Some( - 60..65, - ), - value: String( - "JAN", - ), - }, - Literal { - span: Some( - 67..72, - ), - value: String( - "FEB", - ), - }, - Literal { - span: Some( - 74..79, - ), - value: String( - "MAR", - ), - }, - Literal { - span: Some( - 81..86, - ), - value: String( - "APR", - ), - }, - ], + values: ColumnValues( + [ + Literal { + span: Some( + 60..65, + ), + value: String( + "JAN", + ), + }, + Literal { + span: Some( + 67..72, + ), + value: String( + "FEB", + ), + }, + Literal { + span: Some( + 74..79, + ), + value: String( + "MAR", + ), + }, + Literal { + span: Some( + 81..86, + ), + value: String( + "APR", + ), + }, + ], + ), }, ), unpivot: None, @@ -5759,19 +5769,19 @@ Query { ---------- Input ---------- -select * from monthly_sales_1 unpivot(sales for month in (jan, feb, mar, april)) order by empid +select * from (select * from monthly_sales) pivot(sum(amount) for month in ('JAN', 'FEB', 'MAR', 'APR')) order by empid ---------- Output --------- -SELECT * FROM monthly_sales_1 UNPIVOT(sales FOR month IN (jan, feb, mar, april)) ORDER BY empid +SELECT * FROM (SELECT * FROM monthly_sales) PIVOT(sum(amount) FOR month IN ('JAN', 'FEB', 'MAR', 'APR')) ORDER BY empid ---------- AST ------------ Query { span: Some( - 0..80, + 0..104, ), with: None, body: Select( SelectStmt { span: Some( - 0..80, + 0..104, ), hints: None, distinct: false, @@ -5789,79 +5799,161 @@ Query { }, ], from: [ - Table { + Subquery { span: Some( - 14..80, + 14..104, ), - catalog: None, - database: None, - table: Identifier { + lateral: false, + subquery: Query { span: Some( - 14..29, + 15..42, ), - name: "monthly_sales_1", - quote: None, - ident_type: None, + with: None, + body: Select( + SelectStmt { + span: Some( + 15..42, + ), + hints: None, + distinct: false, + top_n: None, + select_list: [ + StarColumns { + qualified: [ + Star( + Some( + 22..23, + ), + ), + ], + column_filter: None, + }, + ], + from: [ + Table { + span: Some( + 29..42, + ), + catalog: None, + database: None, + table: Identifier { + span: Some( + 29..42, + ), + name: "monthly_sales", + quote: None, + ident_type: None, + }, + alias: None, + temporal: None, + with_options: None, + pivot: None, + unpivot: None, + sample: None, + }, + ], + selection: None, + group_by: None, + having: None, + window_list: None, + qualify: None, + }, + ), + order_by: [], + limit: [], + offset: None, + ignore_result: false, }, alias: None, - temporal: None, - with_options: None, - pivot: None, - unpivot: Some( - Unpivot { - value_column: Identifier { + pivot: Some( + Pivot { + aggregate: FunctionCall { span: Some( - 38..43, + 50..61, ), - name: "sales", - quote: None, - ident_type: None, + func: FunctionCall { + distinct: false, + name: Identifier { + span: Some( + 50..53, + ), + name: "sum", + quote: None, + ident_type: None, + }, + args: [ + ColumnRef { + span: Some( + 54..60, + ), + column: ColumnRef { + database: None, + table: None, + column: Name( + Identifier { + span: Some( + 54..60, + ), + name: "amount", + quote: None, + ident_type: None, + }, + ), + }, + }, + ], + params: [], + window: None, + lambda: None, + }, }, - column_name: Identifier { + value_column: Identifier { span: Some( - 48..53, + 66..71, ), name: "month", quote: None, ident_type: None, }, - names: [ - Identifier { - span: Some( - 58..61, - ), - name: "jan", - quote: None, - ident_type: None, - }, - Identifier { - span: Some( - 63..66, - ), - name: "feb", - quote: None, - ident_type: None, - }, - Identifier { - span: Some( - 68..71, - ), - name: "mar", - quote: None, - ident_type: None, - }, - Identifier { - span: Some( - 73..78, - ), - name: "april", - quote: None, - ident_type: None, - }, - ], + values: ColumnValues( + [ + Literal { + span: Some( + 76..81, + ), + value: String( + "JAN", + ), + }, + Literal { + span: Some( + 83..88, + ), + value: String( + "FEB", + ), + }, + Literal { + span: Some( + 90..95, + ), + value: String( + "MAR", + ), + }, + Literal { + span: Some( + 97..102, + ), + value: String( + "APR", + ), + }, + ], + ), }, ), - sample: None, + unpivot: None, }, ], selection: None, @@ -5875,7 +5967,7 @@ Query { OrderByExpr { expr: ColumnRef { span: Some( - 90..95, + 114..119, ), column: ColumnRef { database: None, @@ -5883,7 +5975,7 @@ Query { column: Name( Identifier { span: Some( - 90..95, + 114..119, ), name: "empid", quote: None, @@ -5903,19 +5995,19 @@ Query { ---------- Input ---------- -select * from range(1, 2) +select * from monthly_sales pivot(sum(amount) for month in (select distinct month from monthly_sales)) order by empid ---------- Output --------- -SELECT * FROM range(1, 2) +SELECT * FROM monthly_sales PIVOT(sum(amount) FOR month IN (SELECT DISTINCT month FROM monthly_sales)) ORDER BY empid ---------- AST ------------ Query { span: Some( - 0..25, + 0..102, ), with: None, body: Select( SelectStmt { span: Some( - 0..25, + 0..102, ), hints: None, distinct: false, @@ -5933,26 +6025,850 @@ Query { }, ], from: [ - TableFunction { + Table { span: Some( - 14..25, + 14..102, ), - lateral: false, - name: Identifier { + catalog: None, + database: None, + table: Identifier { span: Some( - 14..19, + 14..27, ), - name: "range", + name: "monthly_sales", quote: None, ident_type: None, }, - params: [ - Literal { - span: Some( - 20..21, - ), - value: UInt64( - 1, + alias: None, + temporal: None, + with_options: None, + pivot: Some( + Pivot { + aggregate: FunctionCall { + span: Some( + 34..45, + ), + func: FunctionCall { + distinct: false, + name: Identifier { + span: Some( + 34..37, + ), + name: "sum", + quote: None, + ident_type: None, + }, + args: [ + ColumnRef { + span: Some( + 38..44, + ), + column: ColumnRef { + database: None, + table: None, + column: Name( + Identifier { + span: Some( + 38..44, + ), + name: "amount", + quote: None, + ident_type: None, + }, + ), + }, + }, + ], + params: [], + window: None, + lambda: None, + }, + }, + value_column: Identifier { + span: Some( + 50..55, + ), + name: "month", + quote: None, + ident_type: None, + }, + values: Subquery( + Query { + span: Some( + 60..100, + ), + with: None, + body: Select( + SelectStmt { + span: Some( + 60..100, + ), + hints: None, + distinct: true, + top_n: None, + select_list: [ + AliasedExpr { + expr: ColumnRef { + span: Some( + 76..81, + ), + column: ColumnRef { + database: None, + table: None, + column: Name( + Identifier { + span: Some( + 76..81, + ), + name: "month", + quote: None, + ident_type: None, + }, + ), + }, + }, + alias: None, + }, + ], + from: [ + Table { + span: Some( + 87..100, + ), + catalog: None, + database: None, + table: Identifier { + span: Some( + 87..100, + ), + name: "monthly_sales", + quote: None, + ident_type: None, + }, + alias: None, + temporal: None, + with_options: None, + pivot: None, + unpivot: None, + sample: None, + }, + ], + selection: None, + group_by: None, + having: None, + window_list: None, + qualify: None, + }, + ), + order_by: [], + limit: [], + offset: None, + ignore_result: false, + }, + ), + }, + ), + unpivot: None, + sample: None, + }, + ], + selection: None, + group_by: None, + having: None, + window_list: None, + qualify: None, + }, + ), + order_by: [ + OrderByExpr { + expr: ColumnRef { + span: Some( + 112..117, + ), + column: ColumnRef { + database: None, + table: None, + column: Name( + Identifier { + span: Some( + 112..117, + ), + name: "empid", + quote: None, + ident_type: None, + }, + ), + }, + }, + asc: None, + nulls_first: None, + }, + ], + limit: [], + offset: None, + ignore_result: false, +} + + +---------- Input ---------- +select * from (select * from monthly_sales) pivot(sum(amount) for month in ((select distinct month from monthly_sales))) order by empid +---------- Output --------- +SELECT * FROM (SELECT * FROM monthly_sales) PIVOT(sum(amount) FOR month IN ((SELECT DISTINCT month FROM monthly_sales))) ORDER BY empid +---------- AST ------------ +Query { + span: Some( + 0..120, + ), + with: None, + body: Select( + SelectStmt { + span: Some( + 0..120, + ), + hints: None, + distinct: false, + top_n: None, + select_list: [ + StarColumns { + qualified: [ + Star( + Some( + 7..8, + ), + ), + ], + column_filter: None, + }, + ], + from: [ + Subquery { + span: Some( + 14..120, + ), + lateral: false, + subquery: Query { + span: Some( + 15..42, + ), + with: None, + body: Select( + SelectStmt { + span: Some( + 15..42, + ), + hints: None, + distinct: false, + top_n: None, + select_list: [ + StarColumns { + qualified: [ + Star( + Some( + 22..23, + ), + ), + ], + column_filter: None, + }, + ], + from: [ + Table { + span: Some( + 29..42, + ), + catalog: None, + database: None, + table: Identifier { + span: Some( + 29..42, + ), + name: "monthly_sales", + quote: None, + ident_type: None, + }, + alias: None, + temporal: None, + with_options: None, + pivot: None, + unpivot: None, + sample: None, + }, + ], + selection: None, + group_by: None, + having: None, + window_list: None, + qualify: None, + }, + ), + order_by: [], + limit: [], + offset: None, + ignore_result: false, + }, + alias: None, + pivot: Some( + Pivot { + aggregate: FunctionCall { + span: Some( + 50..61, + ), + func: FunctionCall { + distinct: false, + name: Identifier { + span: Some( + 50..53, + ), + name: "sum", + quote: None, + ident_type: None, + }, + args: [ + ColumnRef { + span: Some( + 54..60, + ), + column: ColumnRef { + database: None, + table: None, + column: Name( + Identifier { + span: Some( + 54..60, + ), + name: "amount", + quote: None, + ident_type: None, + }, + ), + }, + }, + ], + params: [], + window: None, + lambda: None, + }, + }, + value_column: Identifier { + span: Some( + 66..71, + ), + name: "month", + quote: None, + ident_type: None, + }, + values: ColumnValues( + [ + Subquery { + span: Some( + 76..118, + ), + modifier: None, + subquery: Query { + span: Some( + 77..117, + ), + with: None, + body: Select( + SelectStmt { + span: Some( + 77..117, + ), + hints: None, + distinct: true, + top_n: None, + select_list: [ + AliasedExpr { + expr: ColumnRef { + span: Some( + 93..98, + ), + column: ColumnRef { + database: None, + table: None, + column: Name( + Identifier { + span: Some( + 93..98, + ), + name: "month", + quote: None, + ident_type: None, + }, + ), + }, + }, + alias: None, + }, + ], + from: [ + Table { + span: Some( + 104..117, + ), + catalog: None, + database: None, + table: Identifier { + span: Some( + 104..117, + ), + name: "monthly_sales", + quote: None, + ident_type: None, + }, + alias: None, + temporal: None, + with_options: None, + pivot: None, + unpivot: None, + sample: None, + }, + ], + selection: None, + group_by: None, + having: None, + window_list: None, + qualify: None, + }, + ), + order_by: [], + limit: [], + offset: None, + ignore_result: false, + }, + }, + ], + ), + }, + ), + unpivot: None, + }, + ], + selection: None, + group_by: None, + having: None, + window_list: None, + qualify: None, + }, + ), + order_by: [ + OrderByExpr { + expr: ColumnRef { + span: Some( + 130..135, + ), + column: ColumnRef { + database: None, + table: None, + column: Name( + Identifier { + span: Some( + 130..135, + ), + name: "empid", + quote: None, + ident_type: None, + }, + ), + }, + }, + asc: None, + nulls_first: None, + }, + ], + limit: [], + offset: None, + ignore_result: false, +} + + +---------- Input ---------- +select * from monthly_sales_1 unpivot(sales for month in (jan, feb, mar, april)) order by empid +---------- Output --------- +SELECT * FROM monthly_sales_1 UNPIVOT(sales FOR month IN (jan, feb, mar, april)) ORDER BY empid +---------- AST ------------ +Query { + span: Some( + 0..80, + ), + with: None, + body: Select( + SelectStmt { + span: Some( + 0..80, + ), + hints: None, + distinct: false, + top_n: None, + select_list: [ + StarColumns { + qualified: [ + Star( + Some( + 7..8, + ), + ), + ], + column_filter: None, + }, + ], + from: [ + Table { + span: Some( + 14..80, + ), + catalog: None, + database: None, + table: Identifier { + span: Some( + 14..29, + ), + name: "monthly_sales_1", + quote: None, + ident_type: None, + }, + alias: None, + temporal: None, + with_options: None, + pivot: None, + unpivot: Some( + Unpivot { + value_column: Identifier { + span: Some( + 38..43, + ), + name: "sales", + quote: None, + ident_type: None, + }, + column_name: Identifier { + span: Some( + 48..53, + ), + name: "month", + quote: None, + ident_type: None, + }, + names: [ + Identifier { + span: Some( + 58..61, + ), + name: "jan", + quote: None, + ident_type: None, + }, + Identifier { + span: Some( + 63..66, + ), + name: "feb", + quote: None, + ident_type: None, + }, + Identifier { + span: Some( + 68..71, + ), + name: "mar", + quote: None, + ident_type: None, + }, + Identifier { + span: Some( + 73..78, + ), + name: "april", + quote: None, + ident_type: None, + }, + ], + }, + ), + sample: None, + }, + ], + selection: None, + group_by: None, + having: None, + window_list: None, + qualify: None, + }, + ), + order_by: [ + OrderByExpr { + expr: ColumnRef { + span: Some( + 90..95, + ), + column: ColumnRef { + database: None, + table: None, + column: Name( + Identifier { + span: Some( + 90..95, + ), + name: "empid", + quote: None, + ident_type: None, + }, + ), + }, + }, + asc: None, + nulls_first: None, + }, + ], + limit: [], + offset: None, + ignore_result: false, +} + + +---------- Input ---------- +select * from (select * from monthly_sales_1) unpivot(sales for month in (jan, feb, mar, april)) order by empid +---------- Output --------- +SELECT * FROM (SELECT * FROM monthly_sales_1) UNPIVOT(sales FOR month IN (jan, feb, mar, april)) ORDER BY empid +---------- AST ------------ +Query { + span: Some( + 0..96, + ), + with: None, + body: Select( + SelectStmt { + span: Some( + 0..96, + ), + hints: None, + distinct: false, + top_n: None, + select_list: [ + StarColumns { + qualified: [ + Star( + Some( + 7..8, + ), + ), + ], + column_filter: None, + }, + ], + from: [ + Subquery { + span: Some( + 14..96, + ), + lateral: false, + subquery: Query { + span: Some( + 15..44, + ), + with: None, + body: Select( + SelectStmt { + span: Some( + 15..44, + ), + hints: None, + distinct: false, + top_n: None, + select_list: [ + StarColumns { + qualified: [ + Star( + Some( + 22..23, + ), + ), + ], + column_filter: None, + }, + ], + from: [ + Table { + span: Some( + 29..44, + ), + catalog: None, + database: None, + table: Identifier { + span: Some( + 29..44, + ), + name: "monthly_sales_1", + quote: None, + ident_type: None, + }, + alias: None, + temporal: None, + with_options: None, + pivot: None, + unpivot: None, + sample: None, + }, + ], + selection: None, + group_by: None, + having: None, + window_list: None, + qualify: None, + }, + ), + order_by: [], + limit: [], + offset: None, + ignore_result: false, + }, + alias: None, + pivot: None, + unpivot: Some( + Unpivot { + value_column: Identifier { + span: Some( + 54..59, + ), + name: "sales", + quote: None, + ident_type: None, + }, + column_name: Identifier { + span: Some( + 64..69, + ), + name: "month", + quote: None, + ident_type: None, + }, + names: [ + Identifier { + span: Some( + 74..77, + ), + name: "jan", + quote: None, + ident_type: None, + }, + Identifier { + span: Some( + 79..82, + ), + name: "feb", + quote: None, + ident_type: None, + }, + Identifier { + span: Some( + 84..87, + ), + name: "mar", + quote: None, + ident_type: None, + }, + Identifier { + span: Some( + 89..94, + ), + name: "april", + quote: None, + ident_type: None, + }, + ], + }, + ), + }, + ], + selection: None, + group_by: None, + having: None, + window_list: None, + qualify: None, + }, + ), + order_by: [ + OrderByExpr { + expr: ColumnRef { + span: Some( + 106..111, + ), + column: ColumnRef { + database: None, + table: None, + column: Name( + Identifier { + span: Some( + 106..111, + ), + name: "empid", + quote: None, + ident_type: None, + }, + ), + }, + }, + asc: None, + nulls_first: None, + }, + ], + limit: [], + offset: None, + ignore_result: false, +} + + +---------- Input ---------- +select * from range(1, 2) +---------- Output --------- +SELECT * FROM range(1, 2) +---------- AST ------------ +Query { + span: Some( + 0..25, + ), + with: None, + body: Select( + SelectStmt { + span: Some( + 0..25, + ), + hints: None, + distinct: false, + top_n: None, + select_list: [ + StarColumns { + qualified: [ + Star( + Some( + 7..8, + ), + ), + ], + column_filter: None, + }, + ], + from: [ + TableFunction { + span: Some( + 14..25, + ), + lateral: false, + name: Identifier { + span: Some( + 14..19, + ), + name: "range", + quote: None, + ident_type: None, + }, + params: [ + Literal { + span: Some( + 20..21, + ), + value: UInt64( + 1, ), }, Literal { @@ -6717,6 +7633,8 @@ Query { columns: [], }, ), + pivot: None, + unpivot: None, }, ], selection: None, @@ -6866,6 +7784,8 @@ Query { ], }, ), + pivot: None, + unpivot: None, }, ], selection: None, @@ -7104,6 +8024,8 @@ Query { ignore_result: false, }, alias: None, + pivot: None, + unpivot: None, }, }, }, @@ -7152,6 +8074,8 @@ Query { ignore_result: false, }, alias: None, + pivot: None, + unpivot: None, }, ], selection: None, diff --git a/src/query/ast/tests/it/testdata/stmt.txt b/src/query/ast/tests/it/testdata/stmt.txt index 9cfaea5263be..527c892bfac5 100644 --- a/src/query/ast/tests/it/testdata/stmt.txt +++ b/src/query/ast/tests/it/testdata/stmt.txt @@ -22852,6 +22852,8 @@ Query( ignore_result: false, }, alias: None, + pivot: None, + unpivot: None, }, ], selection: None, diff --git a/src/query/sql/src/planner/binder/bind_query/bind_select.rs b/src/query/sql/src/planner/binder/bind_query/bind_select.rs index 256778a22835..d570c8d34e9c 100644 --- a/src/query/sql/src/planner/binder/bind_query/bind_select.rs +++ b/src/query/sql/src/planner/binder/bind_query/bind_select.rs @@ -33,7 +33,6 @@ use databend_common_ast::ast::PivotValues; use databend_common_ast::ast::SelectStmt; use databend_common_ast::ast::SelectTarget; use databend_common_ast::ast::TableReference; -use databend_common_ast::Range; use databend_common_ast::Span; use databend_common_exception::ErrorCode; use databend_common_exception::Result; @@ -460,7 +459,8 @@ impl<'a> SelectRewriter<'a> { let data_blocks = databend_common_base::runtime::block_on(async move { subquery_executor.execute_query(&query_sql).await })?; - let values = self.extract_column_values_from_data_blocks(&data_blocks)?; + let values = + self.extract_column_values_from_data_blocks(&data_blocks, subquery.span)?; self.process_pivot_column_values( pivot, &values, @@ -519,36 +519,31 @@ impl<'a> SelectRewriter<'a> { fn extract_column_values_from_data_blocks( &self, data_blocks: &[DataBlock], + span: Span, ) -> Result> { let mut values: Vec = vec![]; - let mut current_span_pos = 0; for block in data_blocks { let columns = block.columns(); if columns.len() != 1 { - return Err(ErrorCode::Internal( + return Err(ErrorCode::SemanticError( "The subquery of `pivot in` must return one column", - )); + ) + .set_span(span)); } - let value = columns[0].to_column(block.num_rows()); - for row in value.iter() { - match &row { - ScalarRef::String(_) => { - let row_str = row.to_string().trim_matches('\'').to_string(); - let length = row_str.len() as u32; + for row in 0..block.num_rows() { + match columns[0].value.index(row).unwrap() { + ScalarRef::String(s) => { let literal = Expr::Literal { - span: Some(Range { - start: current_span_pos, - end: current_span_pos + length, - }), - value: Literal::String(row_str), + span, + value: Literal::String(s.to_string()), }; values.push(literal); - current_span_pos += length; } _ => { - return Err(ErrorCode::Internal( + return Err(ErrorCode::SemanticError( "The subquery of `pivot in` must return a string type", - )); + ) + .set_span(span)); } } } diff --git a/tests/sqllogictests/suites/query/pivot.test b/tests/sqllogictests/suites/query/pivot.test index eb5307c5e43c..d9d4b805f64d 100644 --- a/tests/sqllogictests/suites/query/pivot.test +++ b/tests/sqllogictests/suites/query/pivot.test @@ -79,5 +79,21 @@ SELECT empid,jan,feb,mar,apr FROM ( 1 10400 8000 11000 18000 2 39500 90700 12000 5300 +statement error 1065 +SELECT empid,jan,feb,mar,apr FROM ( + SELECT * + FROM monthly_sales + PIVOT(SUM(amount) FOR MONTH IN (SELECT DISTINCT month, month FROM monthly_sales)) + ORDER BY EMPID +); + +statement error 1065 +SELECT empid,jan,feb,mar,apr FROM ( + SELECT * + FROM monthly_sales + PIVOT(SUM(amount) FOR MONTH IN (SELECT DISTINCT empid FROM monthly_sales)) + ORDER BY EMPID +); + statement ok drop table if exists monthly_sales; diff --git a/tests/sqllogictests/suites/query/unpivot.test b/tests/sqllogictests/suites/query/unpivot.test index a9686cf2d9a5..03baa8ea9233 100644 --- a/tests/sqllogictests/suites/query/unpivot.test +++ b/tests/sqllogictests/suites/query/unpivot.test @@ -45,6 +45,26 @@ SELECT empid,dept,month,sales FROM ( 3 cars mar 100 3 cars april 50 +query IIII +SELECT empid,dept,month,sales FROM ( + SELECT * FROM (SELECT * FROM monthly_sales_1) + UNPIVOT(sales FOR month IN (jan, feb, mar, april)) + ORDER BY empid +); +---- +1 electronics jan 100 +1 electronics feb 200 +1 electronics mar 300 +1 electronics april 100 +2 clothes jan 100 +2 clothes feb 300 +2 clothes mar 150 +2 clothes april 200 +3 cars jan 200 +3 cars feb 400 +3 cars mar 100 +3 cars april 50 + statement ok drop table monthly_sales_1; From c3a8ab0ce6ca6347900cc09b20bb9c010793b6ba Mon Sep 17 00:00:00 2001 From: dragonliu Date: Sat, 19 Oct 2024 16:15:08 +0800 Subject: [PATCH 3/3] code format --- .../service/src/interpreters/interpreter.rs | 3 +-- src/query/service/src/schedulers/scheduler.rs | 15 ++++++------- .../planner/binder/bind_query/bind_select.rs | 14 +++++++----- .../sql/src/planner/binder/bind_query/mod.rs | 2 -- .../binder/bind_query/subquery_executor.rs | 22 ------------------- src/query/sql/src/planner/binder/binder.rs | 6 ++--- src/query/sql/src/planner/binder/mod.rs | 1 - src/query/sql/src/planner/mod.rs | 1 + .../dynamic_sample/dynamic_sample.rs | 4 ++-- .../filter_selectivity_sample.rs | 8 ++++--- .../dynamic_sample/join_selectivity_sample.rs | 4 ++-- .../planner/optimizer/dynamic_sample/mod.rs | 2 -- .../src/planner/optimizer/hyper_dp/dphyp.rs | 6 ++--- .../optimizer/hyper_dp/join_relation.rs | 6 ++--- src/query/sql/src/planner/optimizer/mod.rs | 1 - .../sql/src/planner/optimizer/optimizer.rs | 9 +++----- src/query/sql/src/planner/planner.rs | 21 +++++++----------- ...y_sample_executor.rs => query_executor.rs} | 7 ++++-- 18 files changed, 51 insertions(+), 81 deletions(-) delete mode 100644 src/query/sql/src/planner/binder/bind_query/subquery_executor.rs rename src/query/sql/src/planner/{optimizer/dynamic_sample/query_sample_executor.rs => query_executor.rs} (76%) diff --git a/src/query/service/src/interpreters/interpreter.rs b/src/query/service/src/interpreters/interpreter.rs index 675a7d3b12e0..0a07c08a65df 100644 --- a/src/query/service/src/interpreters/interpreter.rs +++ b/src/query/service/src/interpreters/interpreter.rs @@ -203,10 +203,9 @@ fn log_query_finished(ctx: &QueryContext, error: Option, has_profiles /// /// This function is used to plan the SQL. If an error occurs, we will log the query start and finished. pub async fn interpreter_plan_sql(ctx: Arc, sql: &str) -> Result<(Plan, PlanExtras)> { - let mut planner = Planner::new_with_sample_and_subquery_executors( + let mut planner = Planner::new_with_query_executor( ctx.clone(), Arc::new(ServiceQueryExecutor::new(ctx.clone())), - Arc::new(ServiceQueryExecutor::new(ctx.clone())), ); let result = planner.plan_sql(sql).await; let short_sql = short_sql( diff --git a/src/query/service/src/schedulers/scheduler.rs b/src/query/service/src/schedulers/scheduler.rs index 65b8433264c5..e60a5f88736c 100644 --- a/src/query/service/src/schedulers/scheduler.rs +++ b/src/query/service/src/schedulers/scheduler.rs @@ -19,8 +19,7 @@ use databend_common_exception::Result; use databend_common_expression::DataBlock; use databend_common_pipeline_core::processors::ProcessorPtr; use databend_common_pipeline_sinks::EmptySink; -use databend_common_sql::binder::SubqueryExecutor; -use databend_common_sql::optimizer::QuerySampleExecutor; +use databend_common_sql::planner::query_executor::QueryExecutor; use databend_common_sql::Planner; use futures_util::TryStreamExt; @@ -135,8 +134,11 @@ impl ServiceQueryExecutor { } #[async_trait] -impl QuerySampleExecutor for ServiceQueryExecutor { - async fn execute_query(&self, plan: &PhysicalPlan) -> Result> { +impl QueryExecutor for ServiceQueryExecutor { + async fn execute_query_with_physical_plan( + &self, + plan: &PhysicalPlan, + ) -> Result> { let build_res = build_query_pipeline_without_render_result_set(&self.ctx, plan).await?; let settings = ExecutorSettings::try_create(self.ctx.clone())?; let pulling_executor = PipelinePullingExecutor::from_pipelines(build_res, settings)?; @@ -146,11 +148,8 @@ impl QuerySampleExecutor for ServiceQueryExecutor { .try_collect::>() .await } -} -#[async_trait] -impl SubqueryExecutor for ServiceQueryExecutor { - async fn execute_query(&self, query_sql: &str) -> Result> { + async fn execute_query_with_sql_string(&self, query_sql: &str) -> Result> { let mut planner = Planner::new(self.ctx.clone()); let (plan, _) = planner.plan_sql(query_sql).await?; let interpreter = InterpreterFactory::get(self.ctx.clone(), &plan).await?; diff --git a/src/query/sql/src/planner/binder/bind_query/bind_select.rs b/src/query/sql/src/planner/binder/bind_query/bind_select.rs index d570c8d34e9c..9a5ae8851d6e 100644 --- a/src/query/sql/src/planner/binder/bind_query/bind_select.rs +++ b/src/query/sql/src/planner/binder/bind_query/bind_select.rs @@ -42,10 +42,10 @@ use derive_visitor::Drive; use derive_visitor::Visitor; use log::warn; -use crate::binder::SubqueryExecutor; use crate::optimizer::SExpr; use crate::planner::binder::BindContext; use crate::planner::binder::Binder; +use crate::planner::query_executor::QueryExecutor; use crate::AsyncFunctionRewriter; use crate::ColumnBinding; use crate::VirtualColumnRewriter; @@ -261,7 +261,7 @@ struct SelectRewriter<'a> { column_binding: &'a [ColumnBinding], new_stmt: Option, is_unquoted_ident_case_sensitive: bool, - subquery_executor: Option>, + subquery_executor: Option>, } // helper functions to SelectRewriter @@ -375,7 +375,7 @@ impl<'a> SelectRewriter<'a> { pub fn with_subquery_executor( mut self, - subquery_executor: Option>, + subquery_executor: Option>, ) -> Self { self.subquery_executor = subquery_executor; self @@ -457,7 +457,9 @@ impl<'a> SelectRewriter<'a> { let query_sql = subquery.to_string(); if let Some(subquery_executor) = &self.subquery_executor { let data_blocks = databend_common_base::runtime::block_on(async move { - subquery_executor.execute_query(&query_sql).await + subquery_executor + .execute_query_with_sql_string(&query_sql) + .await })?; let values = self.extract_column_values_from_data_blocks(&data_blocks, subquery.span)?; @@ -523,13 +525,13 @@ impl<'a> SelectRewriter<'a> { ) -> Result> { let mut values: Vec = vec![]; for block in data_blocks { - let columns = block.columns(); - if columns.len() != 1 { + if block.num_columns() != 1 { return Err(ErrorCode::SemanticError( "The subquery of `pivot in` must return one column", ) .set_span(span)); } + let columns = block.columns(); for row in 0..block.num_rows() { match columns[0].value.index(row).unwrap() { ScalarRef::String(s) => { diff --git a/src/query/sql/src/planner/binder/bind_query/mod.rs b/src/query/sql/src/planner/binder/bind_query/mod.rs index d7962974f4c8..a100b232fa51 100644 --- a/src/query/sql/src/planner/binder/bind_query/mod.rs +++ b/src/query/sql/src/planner/binder/bind_query/mod.rs @@ -17,9 +17,7 @@ mod bind_limit; mod bind_select; mod bind_set_expr; mod bind_value; -mod subquery_executor; pub use bind_select::MaxColumnPosition; pub use bind_value::bind_values; pub use bind_value::ExpressionScanContext; -pub use subquery_executor::SubqueryExecutor; diff --git a/src/query/sql/src/planner/binder/bind_query/subquery_executor.rs b/src/query/sql/src/planner/binder/bind_query/subquery_executor.rs deleted file mode 100644 index e2ca0e07693a..000000000000 --- a/src/query/sql/src/planner/binder/bind_query/subquery_executor.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2021 Datafuse Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use async_trait::async_trait; -use databend_common_exception::Result; -use databend_common_expression::DataBlock; - -#[async_trait] -pub trait SubqueryExecutor: Send + Sync { - async fn execute_query(&self, query_sql: &str) -> Result>; -} diff --git a/src/query/sql/src/planner/binder/binder.rs b/src/query/sql/src/planner/binder/binder.rs index c10590bd94e0..575c4bcdab63 100644 --- a/src/query/sql/src/planner/binder/binder.rs +++ b/src/query/sql/src/planner/binder/binder.rs @@ -51,9 +51,9 @@ use crate::binder::util::illegal_ident_name; use crate::binder::wrap_cast; use crate::binder::ColumnBindingBuilder; use crate::binder::CteInfo; -use crate::binder::SubqueryExecutor; use crate::normalize_identifier; use crate::optimizer::SExpr; +use crate::planner::query_executor::QueryExecutor; use crate::plans::CreateFileFormatPlan; use crate::plans::CreateRolePlan; use crate::plans::DescConnectionPlan; @@ -111,7 +111,7 @@ pub struct Binder { pub enable_result_cache: bool, - pub subquery_executor: Option>, + pub subquery_executor: Option>, } impl<'a> Binder { @@ -145,7 +145,7 @@ impl<'a> Binder { pub fn with_subquery_executor( mut self, - subquery_executor: Option>, + subquery_executor: Option>, ) -> Self { self.subquery_executor = subquery_executor; self diff --git a/src/query/sql/src/planner/binder/mod.rs b/src/query/sql/src/planner/binder/mod.rs index 6015af656862..3a7d53ea9ee7 100644 --- a/src/query/sql/src/planner/binder/mod.rs +++ b/src/query/sql/src/planner/binder/mod.rs @@ -61,7 +61,6 @@ pub use bind_mutation::target_probe; pub use bind_mutation::MutationStrategy; pub use bind_mutation::MutationType; pub use bind_query::bind_values; -pub use bind_query::SubqueryExecutor; pub use bind_table_reference::parse_result_scan_args; pub use binder::Binder; pub use builders::*; diff --git a/src/query/sql/src/planner/mod.rs b/src/query/sql/src/planner/mod.rs index d1b63c97d16e..1bf403ca2f88 100644 --- a/src/query/sql/src/planner/mod.rs +++ b/src/query/sql/src/planner/mod.rs @@ -17,6 +17,7 @@ mod format; mod metadata; #[allow(clippy::module_inception)] mod planner; +pub mod query_executor; mod semantic; pub mod binder; diff --git a/src/query/sql/src/planner/optimizer/dynamic_sample/dynamic_sample.rs b/src/query/sql/src/planner/optimizer/dynamic_sample/dynamic_sample.rs index 07e8abf91402..5f5249299bc6 100644 --- a/src/query/sql/src/planner/optimizer/dynamic_sample/dynamic_sample.rs +++ b/src/query/sql/src/planner/optimizer/dynamic_sample/dynamic_sample.rs @@ -21,10 +21,10 @@ use databend_common_exception::Result; use crate::optimizer::dynamic_sample::filter_selectivity_sample::filter_selectivity_sample; use crate::optimizer::dynamic_sample::join_selectivity_sample::join_selectivity_sample; -use crate::optimizer::QuerySampleExecutor; use crate::optimizer::RelExpr; use crate::optimizer::SExpr; use crate::optimizer::StatInfo; +use crate::planner::query_executor::QueryExecutor; use crate::plans::Operator; use crate::plans::RelOperator; use crate::MetadataRef; @@ -34,7 +34,7 @@ pub async fn dynamic_sample( ctx: Arc, metadata: MetadataRef, s_expr: &SExpr, - sample_executor: Arc, + sample_executor: Arc, ) -> Result> { let time_budget = Duration::from_millis(ctx.get_settings().get_dynamic_sample_time_budget_ms()?); diff --git a/src/query/sql/src/planner/optimizer/dynamic_sample/filter_selectivity_sample.rs b/src/query/sql/src/planner/optimizer/dynamic_sample/filter_selectivity_sample.rs index fdb181cda595..53f1e994613f 100644 --- a/src/query/sql/src/planner/optimizer/dynamic_sample/filter_selectivity_sample.rs +++ b/src/query/sql/src/planner/optimizer/dynamic_sample/filter_selectivity_sample.rs @@ -26,11 +26,11 @@ use num_traits::ToPrimitive; use crate::executor::PhysicalPlanBuilder; use crate::optimizer::statistics::CollectStatisticsOptimizer; -use crate::optimizer::QuerySampleExecutor; use crate::optimizer::RelExpr; use crate::optimizer::SExpr; use crate::optimizer::SelectivityEstimator; use crate::optimizer::StatInfo; +use crate::planner::query_executor::QueryExecutor; use crate::plans::Aggregate; use crate::plans::AggregateFunction; use crate::plans::AggregateMode; @@ -43,7 +43,7 @@ pub async fn filter_selectivity_sample( ctx: Arc, metadata: MetadataRef, s_expr: &SExpr, - sample_executor: Arc, + sample_executor: Arc, ) -> Result> { // filter cardinality by sample will be called in `dphyp`, so we can ensure the filter is in complex query(contains not only one table) // Because it's meaningless for filter cardinality by sample in single table query. @@ -87,7 +87,9 @@ pub async fn filter_selectivity_sample( required.insert(0); let plan = builder.build(&new_s_expr, required).await?; - let result = sample_executor.execute_query(&plan).await?; + let result = sample_executor + .execute_query_with_physical_plan(&plan) + .await?; if let Some(block) = result.first() { if let Some(count) = block.get_last_column().as_number() { if let Some(number_scalar) = count.index(0) { diff --git a/src/query/sql/src/planner/optimizer/dynamic_sample/join_selectivity_sample.rs b/src/query/sql/src/planner/optimizer/dynamic_sample/join_selectivity_sample.rs index b7fa2affc0e2..9d0d96c2af5e 100644 --- a/src/query/sql/src/planner/optimizer/dynamic_sample/join_selectivity_sample.rs +++ b/src/query/sql/src/planner/optimizer/dynamic_sample/join_selectivity_sample.rs @@ -18,9 +18,9 @@ use databend_common_catalog::table_context::TableContext; use databend_common_exception::Result; use crate::optimizer::dynamic_sample::dynamic_sample; -use crate::optimizer::QuerySampleExecutor; use crate::optimizer::SExpr; use crate::optimizer::StatInfo; +use crate::planner::query_executor::QueryExecutor; use crate::plans::Join; use crate::MetadataRef; @@ -28,7 +28,7 @@ pub async fn join_selectivity_sample( ctx: Arc, metadata: MetadataRef, s_expr: &SExpr, - sample_executor: Arc, + sample_executor: Arc, ) -> Result> { let left_stat_info = dynamic_sample( ctx.clone(), diff --git a/src/query/sql/src/planner/optimizer/dynamic_sample/mod.rs b/src/query/sql/src/planner/optimizer/dynamic_sample/mod.rs index 0998554242d5..848e631a00a9 100644 --- a/src/query/sql/src/planner/optimizer/dynamic_sample/mod.rs +++ b/src/query/sql/src/planner/optimizer/dynamic_sample/mod.rs @@ -16,7 +16,5 @@ mod dynamic_sample; mod filter_selectivity_sample; mod join_selectivity_sample; -mod query_sample_executor; pub use dynamic_sample::dynamic_sample; -pub use query_sample_executor::QuerySampleExecutor; diff --git a/src/query/sql/src/planner/optimizer/hyper_dp/dphyp.rs b/src/query/sql/src/planner/optimizer/hyper_dp/dphyp.rs index 1cb9762f61c5..db2e0d8699b4 100644 --- a/src/query/sql/src/planner/optimizer/hyper_dp/dphyp.rs +++ b/src/query/sql/src/planner/optimizer/hyper_dp/dphyp.rs @@ -28,10 +28,10 @@ use crate::optimizer::hyper_dp::query_graph::QueryGraph; use crate::optimizer::hyper_dp::util::intersect; use crate::optimizer::hyper_dp::util::union; use crate::optimizer::rule::TransformResult; -use crate::optimizer::QuerySampleExecutor; use crate::optimizer::RuleFactory; use crate::optimizer::RuleID; use crate::optimizer::SExpr; +use crate::planner::query_executor::QueryExecutor; use crate::plans::Filter; use crate::plans::JoinType; use crate::plans::RelOperator; @@ -46,7 +46,7 @@ const RELATION_THRESHOLD: usize = 10; // See the paper for more details. pub struct DPhpy { ctx: Arc, - sample_executor: Option>, + sample_executor: Option>, metadata: MetadataRef, join_relations: Vec, // base table index -> index of join_relations @@ -64,7 +64,7 @@ impl DPhpy { pub fn new( ctx: Arc, metadata: MetadataRef, - sample_executor: Option>, + sample_executor: Option>, ) -> Self { Self { ctx, diff --git a/src/query/sql/src/planner/optimizer/hyper_dp/join_relation.rs b/src/query/sql/src/planner/optimizer/hyper_dp/join_relation.rs index b3e7cc6dbfb7..ec2f4f2fcba9 100644 --- a/src/query/sql/src/planner/optimizer/hyper_dp/join_relation.rs +++ b/src/query/sql/src/planner/optimizer/hyper_dp/join_relation.rs @@ -20,19 +20,19 @@ use databend_common_catalog::table_context::TableContext; use databend_common_exception::Result; use crate::optimizer::dynamic_sample::dynamic_sample; -use crate::optimizer::QuerySampleExecutor; use crate::optimizer::RelExpr; use crate::optimizer::SExpr; +use crate::planner::query_executor::QueryExecutor; use crate::IndexType; use crate::MetadataRef; pub struct JoinRelation { s_expr: SExpr, - sample_executor: Option>, + sample_executor: Option>, } impl JoinRelation { - pub fn new(s_expr: &SExpr, sample_executor: Option>) -> Self { + pub fn new(s_expr: &SExpr, sample_executor: Option>) -> Self { Self { s_expr: s_expr.clone(), sample_executor, diff --git a/src/query/sql/src/planner/optimizer/mod.rs b/src/query/sql/src/planner/optimizer/mod.rs index 82582c63fa3d..d60fc7801671 100644 --- a/src/query/sql/src/planner/optimizer/mod.rs +++ b/src/query/sql/src/planner/optimizer/mod.rs @@ -38,7 +38,6 @@ mod dynamic_sample; pub use cascades::CascadesOptimizer; pub use decorrelate::FlattenInfo; pub use decorrelate::SubqueryRewriter; -pub use dynamic_sample::QuerySampleExecutor; pub use extract::PatternExtractor; pub use hyper_dp::DPhpy; pub use m_expr::MExpr; diff --git a/src/query/sql/src/planner/optimizer/optimizer.rs b/src/query/sql/src/planner/optimizer/optimizer.rs index 0f21b277fb4c..26d85bcebfb2 100644 --- a/src/query/sql/src/planner/optimizer/optimizer.rs +++ b/src/query/sql/src/planner/optimizer/optimizer.rs @@ -41,11 +41,11 @@ use crate::optimizer::join::SingleToInnerOptimizer; use crate::optimizer::rule::TransformResult; use crate::optimizer::statistics::CollectStatisticsOptimizer; use crate::optimizer::util::contains_local_table_scan; -use crate::optimizer::QuerySampleExecutor; use crate::optimizer::RuleFactory; use crate::optimizer::RuleID; use crate::optimizer::SExpr; use crate::optimizer::DEFAULT_REWRITE_RULES; +use crate::planner::query_executor::QueryExecutor; use crate::plans::CopyIntoLocationPlan; use crate::plans::Join; use crate::plans::JoinType; @@ -72,7 +72,7 @@ pub struct OptimizerContext { enable_dphyp: bool, planning_agg_index: bool, #[educe(Debug(ignore))] - sample_executor: Option>, + sample_executor: Option>, } impl OptimizerContext { @@ -104,10 +104,7 @@ impl OptimizerContext { self } - pub fn with_sample_executor( - mut self, - sample_executor: Option>, - ) -> Self { + pub fn with_sample_executor(mut self, sample_executor: Option>) -> Self { self.sample_executor = sample_executor; self } diff --git a/src/query/sql/src/planner/planner.rs b/src/query/sql/src/planner/planner.rs index a5b6cb45cced..7bacfc1aef84 100644 --- a/src/query/sql/src/planner/planner.rs +++ b/src/query/sql/src/planner/planner.rs @@ -37,10 +37,9 @@ use parking_lot::RwLock; use super::semantic::AggregateRewriter; use super::semantic::DistinctToGroupBy; -use crate::binder::SubqueryExecutor; use crate::optimizer::optimize; use crate::optimizer::OptimizerContext; -use crate::optimizer::QuerySampleExecutor; +use crate::planner::query_executor::QueryExecutor; use crate::plans::Insert; use crate::plans::InsertInputSource; use crate::plans::Plan; @@ -55,8 +54,7 @@ const PROBE_INSERT_MAX_TOKENS: usize = 128 * 8; pub struct Planner { pub(crate) ctx: Arc, - pub(crate) sample_executor: Option>, - pub(crate) subquery_executor: Option>, + pub(crate) query_executor: Option>, } #[derive(Debug, Clone)] @@ -69,20 +67,17 @@ impl Planner { pub fn new(ctx: Arc) -> Self { Planner { ctx, - sample_executor: None, - subquery_executor: None, + query_executor: None, } } - pub fn new_with_sample_and_subquery_executors( + pub fn new_with_query_executor( ctx: Arc, - sample_executor: Arc, - subquery_executor: Arc, + query_executor: Arc, ) -> Self { Planner { ctx, - sample_executor: Some(sample_executor), - subquery_executor: Some(subquery_executor), + query_executor: Some(query_executor), } } @@ -203,7 +198,7 @@ impl Planner { name_resolution_ctx, metadata.clone(), ) - .with_subquery_executor(self.subquery_executor.clone()); + .with_subquery_executor(self.query_executor.clone()); // Indicate binder there is no need to collect column statistics for the binding table. self.ctx @@ -218,7 +213,7 @@ impl Planner { .with_enable_distributed_optimization(!self.ctx.get_cluster().is_empty()) .with_enable_join_reorder(unsafe { !settings.get_disable_join_reorder()? }) .with_enable_dphyp(settings.get_enable_dphyp()?) - .with_sample_executor(self.sample_executor.clone()); + .with_sample_executor(self.query_executor.clone()); let optimized_plan = optimize(opt_ctx, plan).await?; let result = (optimized_plan, PlanExtras { diff --git a/src/query/sql/src/planner/optimizer/dynamic_sample/query_sample_executor.rs b/src/query/sql/src/planner/query_executor.rs similarity index 76% rename from src/query/sql/src/planner/optimizer/dynamic_sample/query_sample_executor.rs rename to src/query/sql/src/planner/query_executor.rs index ca376b2fc651..cfc3890bfc56 100644 --- a/src/query/sql/src/planner/optimizer/dynamic_sample/query_sample_executor.rs +++ b/src/query/sql/src/planner/query_executor.rs @@ -19,6 +19,9 @@ use databend_common_expression::DataBlock; use crate::executor::PhysicalPlan; #[async_trait] -pub trait QuerySampleExecutor: Send + Sync { - async fn execute_query(&self, plan: &PhysicalPlan) -> Result>; +pub trait QueryExecutor: Send + Sync { + async fn execute_query_with_physical_plan(&self, plan: &PhysicalPlan) + -> Result>; + + async fn execute_query_with_sql_string(&self, sql: &str) -> Result>; }