From 1f17a974c8f9cc8ad9d0521af61fa5103ba066a3 Mon Sep 17 00:00:00 2001 From: chenxiaobin19 <1025221611@qq.com> Date: Mon, 31 Oct 2022 19:03:12 +0800 Subject: [PATCH] fix inlist2join error --- src/common/backend/utils/adt/selfuncs.cpp | 18 +++++- .../optimizer/prep/prepjointree.cpp | 5 ++ src/include/nodes/parsenodes_common.h | 3 + src/test/regress/expected/query_rewrite.out | 58 ++++++++++++++++++- src/test/regress/sql/query_rewrite.sql | 22 +++++++ 5 files changed, 102 insertions(+), 4 deletions(-) diff --git a/src/common/backend/utils/adt/selfuncs.cpp b/src/common/backend/utils/adt/selfuncs.cpp index e75c104e8..9b43658c2 100755 --- a/src/common/backend/utils/adt/selfuncs.cpp +++ b/src/common/backend/utils/adt/selfuncs.cpp @@ -4796,6 +4796,19 @@ void examine_variable(PlannerInfo* root, Node* node, int varRelid, VariableStatD } } +static void switch_subquery(const PlannerInfo *const root, Query **subquery, const RelOptInfo *const rel) +{ + if (!rel->subroot->parse->is_from_inlist2join_rewrite) { + *subquery = rel->subroot->parse; + return; + } + + if (!root->parse->is_from_sublink_rewrite && !root->parse->is_from_subquery_rewrite) { + *subquery = rel->subroot->parse; + return; + } +} + /* * examine_simple_variable * Handle a simple Var for examine_variable @@ -4904,9 +4917,8 @@ static void examine_simple_variable(PlannerInfo* root, Var* var, VariableStatDat * This is a temporary fix for mislocated varattno after inlist2join * optimization. */ - if (!rel->subroot->parse->is_from_inlist2join_rewrite) { - subquery = rel->subroot->parse; - } + switch_subquery(root, &subquery, rel); + Assert(IsA(subquery, Query)); /* Get the subquery output expression referenced by the upper Var */ diff --git a/src/gausskernel/optimizer/prep/prepjointree.cpp b/src/gausskernel/optimizer/prep/prepjointree.cpp index ef8c37e0f..e7252c5f5 100755 --- a/src/gausskernel/optimizer/prep/prepjointree.cpp +++ b/src/gausskernel/optimizer/prep/prepjointree.cpp @@ -236,6 +236,7 @@ void pull_up_sublinks(PlannerInfo* root) * root->parse->jointree must always be a FromExpr, so insert a dummy one * if we got a bare RangeTblRef or JoinExpr out of the recursion. */ + FromExpr* old_jointree = root->parse->jointree; if (IsA(jtnode, FromExpr)) root->parse->jointree = (FromExpr*)jtnode; else @@ -265,6 +266,9 @@ void pull_up_sublinks(PlannerInfo* root) root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL); } + if (!equal(root->parse->jointree, old_jointree)) { + root->parse->is_from_sublink_rewrite = true; + } } /* @@ -1082,6 +1086,7 @@ static Node* pull_up_simple_subquery(PlannerInfo* root, Node* jtnode, RangeTblEn return jtnode; } + root->parse->is_from_subquery_rewrite = true; /* * Need a modifiable copy of the subquery to hack on. Even if we didn't * sometimes choose not to pull up below, we must do this to avoid diff --git a/src/include/nodes/parsenodes_common.h b/src/include/nodes/parsenodes_common.h index 4e4ee18e6..fa4127b03 100644 --- a/src/include/nodes/parsenodes_common.h +++ b/src/include/nodes/parsenodes_common.h @@ -1979,6 +1979,9 @@ typedef struct Query { * Please refer to subquery_planner. */ bool is_from_inlist2join_rewrite; /* true if the query is created when applying inlist2join optimization */ + bool is_from_sublink_rewrite; /* true if the query is created when applying pull sublink optimization */ + bool is_from_subquery_rewrite; /* true if the query is created when applying pull subquery optimization */ + uint64 uniqueSQLId; /* used by unique sql id */ #ifndef ENABLE_MULTIPLE_NODES char* unique_sql_text; /* used by unique sql plain text */ diff --git a/src/test/regress/expected/query_rewrite.out b/src/test/regress/expected/query_rewrite.out index fb1a941c2..611e9b6a5 100755 --- a/src/test/regress/expected/query_rewrite.out +++ b/src/test/regress/expected/query_rewrite.out @@ -226,9 +226,65 @@ where 5 | 5 | records.storage.state (1 row) +-- fix bug: ERROR: no relation entry for relid 1 +-- Scenario:1 +set enable_hashjoin=on; +set enable_material=off; +set enable_mergejoin=off; +set enable_nestloop=off; +create table k1(id int,id1 int); +create table k2(id int,id1 int); +create table k3(id int,id1 int); +explain (costs off)select m.*,k3.id from (select tz.* from (select k1.id from k1 WHERE exists (select k2.id from k2 where k2.id = k1.id and k2.id1 in (1,2,3,4,5,6,7,8,9,10,11))) tz limit 10) m left join k3 on m.id = k3.id; + QUERY PLAN +---------------------------------------------------------------------------------------------- + Hash Right Join + Hash Cond: (k3.id = k1.id) + -> Seq Scan on k3 + -> Hash + -> Limit + -> Hash Join + Hash Cond: (k1.id = query_rewrite.k2.id) + -> Seq Scan on k1 + -> Hash + -> HashAggregate + Group By Key: query_rewrite.k2.id + -> Hash Join + Hash Cond: (query_rewrite.k2.id1 = "*VALUES*".column1) + -> Seq Scan on k2 + -> Hash + -> HashAggregate + Group By Key: "*VALUES*".column1 + -> Values Scan on "*VALUES*" +(18 rows) + +-- Scenario:2 +create table customer(c_birth_month int); + select + 1 + from + customer t1 , + (with tmp2 as ( select 1 as c_birth_month, 2 as c_birth_day from now()) + select c_birth_month, c_birth_day from ( select 1 as c_birth_month, 2 as c_birth_day from now()) tmp2 ) t2 + where + t1.c_birth_month = t2.c_birth_day and exists (select 1 ) ; + ?column? +---------- +(0 rows) + +-- Scenario:3 +select 1 from customer where c_birth_month not in (with tmp1 as (select 1 from now()) select * from tmp1); + ?column? +---------- +(0 rows) + drop schema query_rewrite cascade; -NOTICE: drop cascades to 3 other objects +NOTICE: drop cascades to 7 other objects DETAIL: drop cascades to table t1 drop cascades to table t2 drop cascades to table t3 +drop cascades to table k1 +drop cascades to table k2 +drop cascades to table k3 +drop cascades to table customer reset current_schema; diff --git a/src/test/regress/sql/query_rewrite.sql b/src/test/regress/sql/query_rewrite.sql index d68fedda6..e8b7a2235 100644 --- a/src/test/regress/sql/query_rewrite.sql +++ b/src/test/regress/sql/query_rewrite.sql @@ -147,6 +147,28 @@ where 50 ) ); +-- fix bug: ERROR: no relation entry for relid 1 +-- Scenario:1 +set enable_hashjoin=on; +set enable_material=off; +set enable_mergejoin=off; +set enable_nestloop=off; +create table k1(id int,id1 int); +create table k2(id int,id1 int); +create table k3(id int,id1 int); +explain (costs off)select m.*,k3.id from (select tz.* from (select k1.id from k1 WHERE exists (select k2.id from k2 where k2.id = k1.id and k2.id1 in (1,2,3,4,5,6,7,8,9,10,11))) tz limit 10) m left join k3 on m.id = k3.id; +-- Scenario:2 +create table customer(c_birth_month int); + select + 1 + from + customer t1 , + (with tmp2 as ( select 1 as c_birth_month, 2 as c_birth_day from now()) + select c_birth_month, c_birth_day from ( select 1 as c_birth_month, 2 as c_birth_day from now()) tmp2 ) t2 + where + t1.c_birth_month = t2.c_birth_day and exists (select 1 ) ; +-- Scenario:3 +select 1 from customer where c_birth_month not in (with tmp1 as (select 1 from now()) select * from tmp1); drop schema query_rewrite cascade; reset current_schema;