diff --git a/pkg/sql/plan/build_test.go b/pkg/sql/plan/build_test.go index 9364cae3a715d..3286745e13f72 100644 --- a/pkg/sql/plan/build_test.go +++ b/pkg/sql/plan/build_test.go @@ -3275,3 +3275,11 @@ func TestReplaceCaptureDedupJoinDoesNotShuffle(t *testing.T) { t.Fatal("expected REPLACE plan to contain a DEDUP JOIN with OldColCaptureList") } + +func TestCommaJoinWithExplicitJoin(t *testing.T) { + mock := NewMockOptimizer(false) + sqls := []string{ + "select nation.n_name from nation, nation2 join region on nation2.r_regionkey = region.r_regionkey", + } + runTestShouldPass(mock, t, sqls, false, false) +} diff --git a/pkg/sql/plan/query_builder.go b/pkg/sql/plan/query_builder.go index 219aa0ff08710..cc2287d2ba87e 100644 --- a/pkg/sql/plan/query_builder.go +++ b/pkg/sql/plan/query_builder.go @@ -5042,7 +5042,7 @@ func (builder *QueryBuilder) buildTable(stmt tree.TableExpr, ctx *BindContext, p if tbl.Right == nil { return builder.buildTable(tbl.Left, ctx, preNodeId, leftCtx) } - return builder.buildJoinTable(tbl, ctx) + return builder.buildJoinTable(tbl, ctx, leftCtx) case *tree.ApplyTableExpr: _, ok := tbl.Right.(*tree.TableFunction) @@ -5327,7 +5327,7 @@ func (builder *QueryBuilder) addBinding(nodeID int32, alias tree.AliasClause, ct return nil } -func (builder *QueryBuilder) buildJoinTable(tbl *tree.JoinTableExpr, ctx *BindContext) (int32, error) { +func (builder *QueryBuilder) buildJoinTable(tbl *tree.JoinTableExpr, ctx *BindContext, extLeftCtx *BindContext) (int32, error) { joinType := plan.Node_INNER switch tbl.JoinType { @@ -5375,6 +5375,43 @@ func (builder *QueryBuilder) buildJoinTable(tbl *tree.JoinTableExpr, ctx *BindCo return 0, err } + // Comma (CROSS) joins produce nested trees where the outer left context + // is not visible in the inner ON condition + // (e.g. FROM a, b JOIN c ON a.x = c.y). Temporarily add extLeftCtx + // bindings to ctx for the ON condition binding, then remove them so + // the outer mergeContexts doesn't see a duplicate. + var extBindingsRestore func() + if extLeftCtx != nil { + var addedTables []string + for _, binding := range extLeftCtx.bindings { + if _, ok := ctx.bindingByTable[binding.table]; !ok { + ctx.bindings = append(ctx.bindings, binding) + ctx.bindingByTag[binding.tag] = binding + ctx.bindingByTable[binding.table] = binding + addedTables = append(addedTables, binding.table) + } + } + var addedCols []string + for col, binding := range extLeftCtx.bindingByCol { + if _, ok := ctx.bindingByCol[col]; !ok { + ctx.bindingByCol[col] = binding + addedCols = append(addedCols, col) + } + } + extBindingsRestore = func() { + for _, table := range addedTables { + delete(ctx.bindingByTable, table) + } + for _, col := range addedCols { + delete(ctx.bindingByCol, col) + } + for _, binding := range extLeftCtx.bindings { + delete(ctx.bindingByTag, binding.tag) + } + ctx.bindings = ctx.bindings[:len(ctx.bindings)-len(addedTables)] + } + } + node := &plan.Node{ NodeType: plan.Node_JOIN, Children: []int32{leftChildID, rightChildID}, @@ -5444,6 +5481,9 @@ func (builder *QueryBuilder) buildJoinTable(tbl *tree.JoinTableExpr, ctx *BindCo } } + if extBindingsRestore != nil { + extBindingsRestore() + } return nodeID, nil } diff --git a/test/distributed/cases/join/join.result b/test/distributed/cases/join/join.result index cfea8e4b89562..aff66ebd54a94 100644 --- a/test/distributed/cases/join/join.result +++ b/test/distributed/cases/join/join.result @@ -5,8 +5,8 @@ CREATE TABLE t2 (S1 INT); INSERT INTO t1 VALUES (1),(3),(4),(6); INSERT INTO t2 VALUES (2),(4),(5); SELECT * FROM t1 JOIN t2 on t1.S1=t2.S1; -S1 S1 -4 4 +➤ s1[4,32,0] ¦ s1[4,32,0] 𝄀 +4 ¦ 4 drop table if exists t1; drop table if exists t2; create table t1 (id int); @@ -26,16 +26,16 @@ insert into t1 values (106); insert into t1 values (107); insert into t2 values (107),(75),(1000); select t1.id, t2.id from t1, t2 where t2.id = t1.id; -id id -75 75 -107 107 +➤ id[4,32,0] ¦ id[4,32,0] 𝄀 +75 ¦ 75 𝄀 +107 ¦ 107 select t1.id, count(t2.id) from t1,t2 where t2.id = t1.id group by t1.id; -id count(t2.id) -75 1 -107 1 +➤ id[4,32,0] ¦ count(t2.id)[-5,64,0] 𝄀 +75 ¦ 1 𝄀 +107 ¦ 1 select t1.id,t2.id from t2 join t1 on t1.id=t2.id where t2.id=75; -id id -75 75 +➤ id[4,32,0] ¦ id[4,32,0] 𝄀 +75 ¦ 75 drop table if exists t1; drop table if exists t2; CREATE TABLE t1 ( @@ -69,16 +69,16 @@ INSERT INTO t2 VALUES (3,2,11,12,5400,7800); INSERT INTO t2 VALUES (4,2,25,12,6500,11200); INSERT INTO t2 VALUES (5,1,37,6,10000,12000); select t1.id, category as catid, state as stateid, county as countyid from t1 join t2 on count=t2.id where token='a71250b7ed780f6ef3185bfffe027983'; -id catid stateid countyid -28 2 12 11 -27 2 12 11 -29 2 12 25 -26 1 6 37 +➤ id[4,32,0] ¦ catid[4,32,0] ¦ stateid[4,32,0] ¦ countyid[4,32,0] 𝄀 +26 ¦ 1 ¦ 6 ¦ 37 𝄀 +27 ¦ 2 ¦ 12 ¦ 11 𝄀 +28 ¦ 2 ¦ 12 ¦ 11 𝄀 +29 ¦ 2 ¦ 12 ¦ 25 select t1.id, category as catid, state as stateid, county as countyid from t1 join t2 on count=t2.id where token='a71250b7ed780f6ef3185bfffe027983' and t1.id>26 order by t1.id; -id catid stateid countyid -27 2 12 11 -28 2 12 11 -29 2 12 25 +➤ id[4,32,0] ¦ catid[4,32,0] ¦ stateid[4,32,0] ¦ countyid[4,32,0] 𝄀 +27 ¦ 2 ¦ 12 ¦ 11 𝄀 +28 ¦ 2 ¦ 12 ¦ 11 𝄀 +29 ¦ 2 ¦ 12 ¦ 25 drop table if exists t1; drop table if exists t2; drop table if exists t3; @@ -100,23 +100,23 @@ PRIMARY KEY (id) INSERT INTO t1 VALUES (12,5,'Percent','Cost',-1,0,-1,-1),(14,4,'Percent','Cost',-1,0,-1,-1),(18,5,'Percent','Cost',-1,0,-1,-1),(19,4,'Percent','Cost',-1,0,-1,-1),(20,5,'Percent','Cost',100,-1,22,291),(21,5,'Percent','Cost',100,-1,18,291),(22,1,'Percent','Cost',100,-1,6,291),(23,1,'Percent','Cost',100,-1,21,291),(24,1,'Percent','Cost',100,-1,9,291),(25,1,'Percent','Cost',100,-1,4,291),(26,1,'Percent','Cost',100,-1,20,291),(27,4,'Percent','Cost',100,-1,7,202),(28,1,'Percent','Cost',50,-1,-1,137),(29,2,'Percent','Cost',100,-1,4,354),(30,2,'Percent','Cost',100,-1,9,137),(93,2,'Cost','Cost',-1,10000000,-1,-1); INSERT INTO t2 VALUES (1,'s1'),(2,'s2'),(3,'s3'),(4,'s4'),(5,'s5'); select t2_id,name, type from t1 join t2 on t2.id=t1.t2_id order by id; -t2_id name type -1 s1 Percent -1 s1 Percent -1 s1 Percent -1 s1 Percent -1 s1 Percent -1 s1 Percent -2 s2 Percent -2 s2 Percent -2 s2 Cost -4 s4 Percent -4 s4 Percent -4 s4 Percent -5 s5 Percent -5 s5 Percent -5 s5 Percent -5 s5 Percent +➤ t2_id[4,32,0] ¦ name[12,-1,0] ¦ type[12,-1,0] 𝄀 +1 ¦ s1 ¦ Percent 𝄀 +1 ¦ s1 ¦ Percent 𝄀 +1 ¦ s1 ¦ Percent 𝄀 +1 ¦ s1 ¦ Percent 𝄀 +1 ¦ s1 ¦ Percent 𝄀 +1 ¦ s1 ¦ Percent 𝄀 +2 ¦ s2 ¦ Percent 𝄀 +2 ¦ s2 ¦ Percent 𝄀 +2 ¦ s2 ¦ Cost 𝄀 +4 ¦ s4 ¦ Percent 𝄀 +4 ¦ s4 ¦ Percent 𝄀 +4 ¦ s4 ¦ Percent 𝄀 +5 ¦ s5 ¦ Percent 𝄀 +5 ¦ s5 ¦ Percent 𝄀 +5 ¦ s5 ¦ Percent 𝄀 +5 ¦ s5 ¦ Percent drop table t1; drop table t2; CREATE TABLE t1 (ID INTEGER NOT NULL PRIMARY KEY, Value1 VARCHAR(255)); @@ -124,10 +124,10 @@ CREATE TABLE t2 (ID INTEGER NOT NULL PRIMARY KEY, Value2 VARCHAR(255)); INSERT INTO t1 VALUES (1, 'A'); INSERT INTO t2 VALUES (1, 'B'); SELECT t1.ID,Value2 FROM t1 JOIN t2 on t1.ID=t2.ID WHERE Value1 = 'A'; -ID Value2 -1 B +➤ ID[4,32,0] ¦ Value2[12,-1,0] 𝄀 +1 ¦ B SELECT t1.ID,Value2 FROM t1 JOIN t2 on t1.ID=t2.ID WHERE Value1 = 'A' and Value2 <> 'B'; -ID Value2 +➤ ID[4,32,0] ¦ Value2[12,-1,0] drop table if exists t1; drop table if exists t2; drop table if exists t3; @@ -138,8 +138,8 @@ insert into t1 values(1),(2),(3),(4),(5); insert into t2 values(1),(3),(5),(7),(9); insert into t3 values(1),(1),(3),(4),(7); select a,b,c from t1 join t2 on t1.a=t2.b join t3 on t1.a=t3.c where a>1; -a b c -3 3 3 +➤ a[4,32,0] ¦ b[4,32,0] ¦ c[4,32,0] 𝄀 +3 ¦ 3 ¦ 3 drop table if exists t1; drop table if exists t2; drop table if exists t3; @@ -150,7 +150,7 @@ insert into t1 values(1),(2); insert into t2 values(2),(3); insert into t3 values (2),(4); select t3.i from t1 join t2 on t1.i=t2.i join t3 on t2.i=t3.i; -i +➤ i[4,32,0] 𝄀 2 drop table if exists t1; drop table if exists t2; @@ -175,7 +175,7 @@ insert into t4 values (2, 3); insert into t5 values (11,4); insert into t6 values (2, 3); select distinct a,t1.b,t3.c from t1 join t2 on t1.b=t2.b join t3 on t1.b=t3.c; -a b c +➤ a[4,32,0] ¦ b[4,32,0] ¦ c[4,32,0] drop table if exists t1; drop table if exists t2; drop table if exists t3; @@ -189,8 +189,8 @@ insert into t2 values (1,1); insert into t3 values (1,1); insert into t4 values (1); select * from t1 join t2 on t1.a1=t2.a1 join t3 on b=c1 join t4 on t3.c2=t4.c2; -a1 a2 a1 b c1 c2 c2 -1 1 1 1 1 1 1 +➤ a1[4,32,0] ¦ a2[4,32,0] ¦ a1[4,32,0] ¦ b[4,32,0] ¦ c1[4,32,0] ¦ c2[4,32,0] ¦ c2[4,32,0] 𝄀 +1 ¦ 1 ¦ 1 ¦ 1 ¦ 1 ¦ 1 ¦ 1 drop table if exists t1; create table t1 (a int); insert into t1 values(1); @@ -198,8 +198,8 @@ drop table if exists t2; create table t2 (a int); insert into t2 values(1); select * from (t1 join t2 on t1.a = t2.a); -a a -1 1 +➤ a[4,32,0] ¦ a[4,32,0] 𝄀 +1 ¦ 1 drop table if exists tt; drop table if exists tt2; create table tt(a text,b text,c int); @@ -207,7 +207,7 @@ create table tt2(a text,b text,c int); insert into tt values("a","bc",1); insert into tt2 values("ab","c",2); select * from tt as t11 join tt2 as t12 on t11.a = t12.a and t11.b = t12.b; -a b c a b c +➤ a[12,0,0] ¦ b[12,0,0] ¦ c[4,32,0] ¦ a[12,0,0] ¦ b[12,0,0] ¦ c[4,32,0] drop table if exists t1; drop table if exists t2; drop table if exists t3; @@ -215,7 +215,20 @@ create table t1 (q int); create table t2 (a int); create table t3 (b int); select * from t1,t2 join t3 on a=b; -q a b +➤ q[4,32,0] ¦ a[4,32,0] ¦ b[4,32,0] +drop table if exists t_comma_join; +drop table if exists t_comma_dim; +create table t_comma_join (id int, val int); +create table t_comma_dim (id int primary key, typ varchar(16)); +insert into t_comma_join values (1, 100), (2, 200); +insert into t_comma_dim values (1, 'A'), (2, 'B'); +select r.id, s.typ from t_comma_join r, (select max(val) as v from t_comma_join) ld +join t_comma_dim s on r.id = s.id where r.val = ld.v; +➤ id[4,32,0] ¦ typ[12,-1,0] 𝄀 +2 ¦ A 𝄀 +2 ¦ B +drop table t_comma_join; +drop table t_comma_dim; drop table if exists t1; drop table if exists t2; create table t1(a int, b int primary key); @@ -223,17 +236,17 @@ create table t2(a int, b int,primary key(a,b)); insert into t1 select result%50,result from generate_series(1,10000,1) g; insert into t2 select result/100,result%100 from generate_series(1,10000,1) g; select t1.a,t1.b from t1 join t2 on t1.b=t2.a and t1.b=t2.b order by t1.a desc limit 4; -a b -49 99 -49 49 -48 48 -48 98 +➤ a[4,32,0] ¦ b[4,32,0] 𝄀 +49 ¦ 99 𝄀 +49 ¦ 49 𝄀 +48 ¦ 48 𝄀 +48 ¦ 98 select t2.a,t2.b from t2 join t1 on t2.a=t1.b and t2.b=t1.a order by t2.a desc limit 4; -a b -100 0 -99 49 -98 48 -97 47 +➤ a[4,32,0] ¦ b[4,32,0] 𝄀 +100 ¦ 0 𝄀 +99 ¦ 49 𝄀 +98 ¦ 48 𝄀 +97 ¦ 47 drop table t1; drop table t2; create table t1(a int, b int primary key); @@ -241,53 +254,53 @@ create table t2(a int, b int,primary key(a,b)); insert into t1 select 10000-result,result from generate_series(1,10000,1) g; insert into t2 select result%2,result-result%2 from generate_series(1,10000,1) g; select t1.a,t1.b,t2.a,t2.b from t1 left join t2 on t1.b=t2.b order by t1.b desc limit 4; -a b a b -0 10000 0 10000 -1 9999 NULL NULL -2 9998 1 9998 -2 9998 0 9998 +➤ a[4,32,0] ¦ b[4,32,0] ¦ a[4,32,0] ¦ b[4,32,0] 𝄀 +0 ¦ 10000 ¦ 0 ¦ 10000 𝄀 +1 ¦ 9999 ¦ null ¦ null 𝄀 +2 ¦ 9998 ¦ 1 ¦ 9998 𝄀 +2 ¦ 9998 ¦ 0 ¦ 9998 select t1.a,t1.b,t2.a,t2.b from t1 right join t2 on t1.b=t2.b order by t1.b desc limit 4; -a b a b -0 10000 0 10000 -2 9998 0 9998 -2 9998 1 9998 -4 9996 0 9996 +➤ a[4,32,0] ¦ b[4,32,0] ¦ a[4,32,0] ¦ b[4,32,0] 𝄀 +0 ¦ 10000 ¦ 0 ¦ 10000 𝄀 +2 ¦ 9998 ¦ 1 ¦ 9998 𝄀 +2 ¦ 9998 ¦ 0 ¦ 9998 𝄀 +4 ¦ 9996 ¦ 0 ¦ 9996 select * from t1 where t1.b in (select b from t2) order by t1.b desc limit 4; -a b -0 10000 -2 9998 -4 9996 -6 9994 +➤ a[4,32,0] ¦ b[4,32,0] 𝄀 +0 ¦ 10000 𝄀 +2 ¦ 9998 𝄀 +4 ¦ 9996 𝄀 +6 ¦ 9994 select * from t1 where t1.b not in (select b from t2) order by t1.b desc limit 4; -a b -1 9999 -3 9997 -5 9995 -7 9993 +➤ a[4,32,0] ¦ b[4,32,0] 𝄀 +1 ¦ 9999 𝄀 +3 ¦ 9997 𝄀 +5 ¦ 9995 𝄀 +7 ¦ 9993 drop table t1; drop table t2; select * from mo_catalog.mo_indexes where name = 'idx1' and table_id = (select rel_id from mo_catalog.mo_tables where relname = 't1'); -id table_id database_id name type algo algo_table_type algo_params is_visible hidden comment column_name ordinal_position options index_table_name +➤ id[-5,64,0] ¦ table_id[-5,64,0] ¦ database_id[-5,64,0] ¦ name[12,-1,0] ¦ type[12,-1,0] ¦ algo[12,-1,0] ¦ algo_table_type[12,-1,0] ¦ algo_params[12,-1,0] ¦ is_visible[-6,8,0] ¦ hidden[-6,8,0] ¦ comment[12,-1,0] ¦ column_name[12,-1,0] ¦ ordinal_position[4,32,0] ¦ options[12,0,0] ¦ index_table_name[12,-1,0] create table x1 (a int, b int); insert into x1 values (1, 1), (2, 2), (3, 3); insert into x1 select 42, result from generate_series(1,20000,1) g; insert into x1 values (10, 10), (20, 20); create table x2 as select * from x1 limit 10; select count(*) from x2 inner join x1 on x1.a = x2.a; -count(*) +➤ count(*)[-5,64,0] 𝄀 100005 select * from x2 inner join x1 on x1.a = x2.a order by x1.a limit 10; -a b a b -1 1 1 1 -2 2 2 2 -3 3 3 3 -10 10 10 10 -20 20 20 20 -42 2 42 1 -42 1 42 1 -42 5 42 1 -42 4 42 1 -42 3 42 1 +➤ a[4,32,0] ¦ b[4,32,0] ¦ a[4,32,0] ¦ b[4,32,0] 𝄀 +1 ¦ 1 ¦ 1 ¦ 1 𝄀 +2 ¦ 2 ¦ 2 ¦ 2 𝄀 +3 ¦ 3 ¦ 3 ¦ 3 𝄀 +10 ¦ 10 ¦ 10 ¦ 10 𝄀 +20 ¦ 20 ¦ 20 ¦ 20 𝄀 +42 ¦ 2 ¦ 42 ¦ 1 𝄀 +42 ¦ 1 ¦ 42 ¦ 1 𝄀 +42 ¦ 5 ¦ 42 ¦ 1 𝄀 +42 ¦ 4 ¦ 42 ¦ 1 𝄀 +42 ¦ 3 ¦ 42 ¦ 1 drop table x1; drop table x2; drop table if exists t1; @@ -374,7 +387,7 @@ and r_name like 'Europ%' and i_id=m_i_id and s_quantity = m_s_quantity order by n_name, s_name, i_id; -s_suppkey s_name n_name i_id i_name s_address s_phone s_comment +➤ s_suppkey[4,32,0] ¦ s_name[1,25,0] ¦ n_name[1,25,0] ¦ i_id[4,32,0] ¦ i_name[12,-1,0] ¦ s_address[12,-1,0] ¦ s_phone[1,15,0] ¦ s_comment[1,101,0] drop table if exists item; drop table if exists supplier; drop table if exists stock; diff --git a/test/distributed/cases/join/join.sql b/test/distributed/cases/join/join.sql index b5ff57c6aea05..b511aa722bf87 100644 --- a/test/distributed/cases/join/join.sql +++ b/test/distributed/cases/join/join.sql @@ -168,6 +168,18 @@ create table t2 (a int); create table t3 (b int); select * from t1,t2 join t3 on a=b; +-- comma join with CTE/subquery and explicit JOIN (issue #24411) +drop table if exists t_comma_join; +drop table if exists t_comma_dim; +create table t_comma_join (id int, val int); +create table t_comma_dim (id int primary key, typ varchar(16)); +insert into t_comma_join values (1, 100), (2, 200); +insert into t_comma_dim values (1, 'A'), (2, 'B'); +select r.id, s.typ from t_comma_join r, (select max(val) as v from t_comma_join) ld +join t_comma_dim s on r.id = s.id where r.val = ld.v; +drop table t_comma_join; +drop table t_comma_dim; + drop table if exists t1; drop table if exists t2; create table t1(a int, b int primary key);