diff --git a/query/src/sql/planner/binder/bind_context.rs b/query/src/sql/planner/binder/bind_context.rs index e11f8fbfb9a89..deb7b365b06ba 100644 --- a/query/src/sql/planner/binder/bind_context.rs +++ b/query/src/sql/planner/binder/bind_context.rs @@ -81,13 +81,9 @@ impl BindContext { /// Apply table alias like `SELECT * FROM t AS t1(a, b, c)`. /// This method will rename column bindings according to table alias. - pub fn apply_table_alias(&mut self, original_name: &str, alias: &TableAlias) -> Result<()> { + pub fn apply_table_alias(&mut self, alias: &TableAlias) -> Result<()> { for column in self.columns.iter_mut() { - if let Some(table_name) = &column.table_name { - if table_name.as_str() == original_name { - column.table_name = Some(alias.name.to_string()); - } - } + column.table_name = Some(alias.name.to_string()); } if alias.columns.len() > self.columns.len() { diff --git a/query/src/sql/planner/binder/join.rs b/query/src/sql/planner/binder/join.rs index 44baf7ae7af40..2376349d69011 100644 --- a/query/src/sql/planner/binder/join.rs +++ b/query/src/sql/planner/binder/join.rs @@ -50,6 +50,8 @@ impl<'a> Binder { .bind_table_reference(&left_context, &join.right) .await?; + check_duplicate_join_tables(&left_context, &right_context)?; + let mut bind_context = BindContext::new(); for column in left_context.all_column_bindings() { bind_context.add_column_binding(column.clone()); @@ -125,6 +127,37 @@ impl<'a> Binder { } } +pub fn check_duplicate_join_tables( + left_context: &BindContext, + right_context: &BindContext, +) -> Result<()> { + let left_column_bindings = left_context.all_column_bindings(); + let left_table_name = if left_column_bindings.is_empty() { + None + } else { + left_column_bindings[0].table_name.as_ref() + }; + + let right_column_bindings = right_context.all_column_bindings(); + let right_table_name = if right_column_bindings.is_empty() { + None + } else { + right_column_bindings[0].table_name.as_ref() + }; + + if let Some(left) = left_table_name { + if let Some(right) = right_table_name { + if left.eq(right) { + return Err(ErrorCode::SemanticError(format!( + "Duplicated table name {} in the same FROM clause", + left + ))); + } + } + } + Ok(()) +} + struct JoinConditionResolver<'a> { ctx: Arc, diff --git a/query/src/sql/planner/binder/project.rs b/query/src/sql/planner/binder/project.rs index 9c2200f546dab..6addac1784d6f 100644 --- a/query/src/sql/planner/binder/project.rs +++ b/query/src/sql/planner/binder/project.rs @@ -73,8 +73,8 @@ impl<'a> Binder { /// in this function. pub(super) async fn normalize_select_list( &mut self, - select_list: &[SelectTarget<'a>], input_context: &BindContext, + select_list: &[SelectTarget<'a>], ) -> Result { let mut output_context = BindContext::new(); for select_target in select_list { diff --git a/query/src/sql/planner/binder/select.rs b/query/src/sql/planner/binder/select.rs index f4017fe9090c1..f9e1147014e41 100644 --- a/query/src/sql/planner/binder/select.rs +++ b/query/src/sql/planner/binder/select.rs @@ -102,7 +102,7 @@ impl<'a> Binder { // Output of current `SELECT` statement. let mut output_context = self - .normalize_select_list(&stmt.select_list, &from_context) + .normalize_select_list(&from_context, &stmt.select_list) .await?; let agg_info = self.analyze_aggregate(&output_context)?; @@ -206,7 +206,7 @@ impl<'a> Binder { let (s_expr, mut bind_context) = self.bind_base_table(table_index).await?; if let Some(alias) = alias { - bind_context.apply_table_alias(&table, alias)?; + bind_context.apply_table_alias(alias)?; } Ok((s_expr, bind_context)) } @@ -257,12 +257,18 @@ impl<'a> Binder { let (s_expr, mut bind_context) = self.bind_base_table(table_index).await?; if let Some(alias) = alias { - bind_context.apply_table_alias(table.name(), alias)?; + bind_context.apply_table_alias(alias)?; } Ok((s_expr, bind_context)) } TableReference::Join(join) => self.bind_join(bind_context, join).await, - _ => Err(ErrorCode::UnImplement("Unsupported table reference type")), + TableReference::Subquery { subquery, alias } => { + let (s_expr, mut bind_context) = self.bind_query(bind_context, subquery).await?; + if let Some(alias) = alias { + bind_context.apply_table_alias(alias)?; + } + Ok((s_expr, bind_context)) + } } } diff --git a/tests/suites/0_stateless/20+_others/20_0001_planner_v2.result b/tests/suites/0_stateless/20+_others/20_0001_planner_v2.result index 2b89fcdb73c4e..3d8008f50694a 100644 --- a/tests/suites/0_stateless/20+_others/20_0001_planner_v2.result +++ b/tests/suites/0_stateless/20+_others/20_0001_planner_v2.result @@ -88,6 +88,14 @@ NULL 2 3 0 1 1 1 1 2 2 NULL 3 +4950 +100 +1 +99999 +1 +0 +685 +0.685 ====INNER_JOIN==== 1 1 2 2 @@ -226,5 +234,11 @@ new_planner 18 ====Memory Table==== 1 +=== Test Subquery In From === +1 +2 +0 0 5 +0 4 5 +0 8 5 ====Context Function==== default diff --git a/tests/suites/0_stateless/20+_others/20_0001_planner_v2.sql b/tests/suites/0_stateless/20+_others/20_0001_planner_v2.sql index 4b415da49de56..c0be334510d3e 100644 --- a/tests/suites/0_stateless/20+_others/20_0001_planner_v2.sql +++ b/tests/suites/0_stateless/20+_others/20_0001_planner_v2.sql @@ -80,6 +80,21 @@ SELECT a%2 as a1, to_uint64(c % 3) as c1, count(0) as ct FROM t GROUP BY a1, c1 -- u64, nullable(u8) SELECT to_uint64(c % 3) as c1, a%2 as a1, count(0) as ct FROM t GROUP BY a1, c1 ORDER BY a1, c1, ct; +-- aggregator combinator +-- distinct +select sum_distinct(number) from ( select number % 100 as number from numbers(100000)); +select count_distinct(number) from ( select number % 100 as number from numbers(100000)); +select sum_distinct(number) / count_distinct(number) = avg_distinct(number) from ( select number % 100 as number from numbers(100000)); + +-- if +select sum_if(number, number >= 100000 - 1) from numbers(100000); +select sum_if(number, number > 100) / count_if(number, number > 100) = avg_if(number, number > 100) from numbers(100000); +select count_if(number, number>9) from numbers(10); + +-- boolean +select sum(number > 314) from numbers(1000); +select avg(number > 314) from numbers(1000); + drop table t; -- Inner join @@ -147,6 +162,14 @@ insert into temp values (1); select a from temp; drop table temp; +-- subquery in from +select '=== Test Subquery In From ==='; +create table t(a int, b int); +insert into t values(1, 2),(2, 3); +select t1.a from (select * from t) as t1; +SELECT a,b,count() from (SELECT cast((number%4) AS bigint) as a, cast((number%20) AS bigint) as b from numbers(100)) group by a,b order by a,b limit 3 ; +drop table t; + select '====Context Function===='; use default; select database();