Skip to content

Commit 2260c7f

Browse files
committed
Fixes for ChangeVarNodes_walker()
This commit fixes two bug in ChangeVarNodes_walker() function. * When considering RestrictInfo, walk down to its clauses based on the presense of relid to be deleted not just in clause_relids but also in required_relids. * Incrementally adjust num_base_rels based on the change of clause_relids instead of recalculating it using clause_relids, which could contain outer-join relids. Reported-by: Richard Guo <guofenglinux@gmail.com> Discussion: https://postgr.es/m/CAMbWs49PE3CvnV8vrQ0Dr%3DHqgZZmX0tdNbzVNJxqc8yg-8kDQQ%40mail.gmail.com Author: Andrei Lepikhov <lepihov@gmail.com> Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
1 parent 15b1b4d commit 2260c7f

File tree

3 files changed

+46
-6
lines changed

3 files changed

+46
-6
lines changed

src/backend/rewrite/rewriteManip.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -644,14 +644,34 @@ ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
644644
bool clause_relids_is_multiple =
645645
(bms_membership(rinfo->clause_relids) == BMS_MULTIPLE);
646646

647-
if (bms_is_member(context->rt_index, rinfo->clause_relids))
647+
/*
648+
* Recurse down into clauses if the target relation is present in
649+
* clause_relids or required_relids. We must check required_relids
650+
* because the relation not present in clause_relids might still be
651+
* present somewhere in orclause.
652+
*/
653+
if (bms_is_member(context->rt_index, rinfo->clause_relids) ||
654+
bms_is_member(context->rt_index, rinfo->required_relids))
648655
{
656+
Relids new_clause_relids;
657+
649658
expression_tree_walker((Node *) rinfo->clause, ChangeVarNodes_walker, (void *) context);
650659
expression_tree_walker((Node *) rinfo->orclause, ChangeVarNodes_walker, (void *) context);
651660

652-
rinfo->clause_relids =
653-
adjust_relid_set(rinfo->clause_relids, context->rt_index, context->new_index);
654-
rinfo->num_base_rels = bms_num_members(rinfo->clause_relids);
661+
new_clause_relids = adjust_relid_set(rinfo->clause_relids,
662+
context->rt_index,
663+
context->new_index);
664+
665+
/*
666+
* Incrementally adjust num_base_rels based on the change of
667+
* clause_relids, which could contain both base relids and
668+
* outer-join relids. This operation is legal until we remove
669+
* only baserels.
670+
*/
671+
rinfo->num_base_rels -= bms_num_members(rinfo->clause_relids) -
672+
bms_num_members(new_clause_relids);
673+
674+
rinfo->clause_relids = new_clause_relids;
655675
rinfo->left_relids =
656676
adjust_relid_set(rinfo->left_relids, context->rt_index, context->new_index);
657677
rinfo->right_relids =

src/test/regress/expected/join.out

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7260,7 +7260,21 @@ WHERE t1.id = emp1.id RETURNING emp1.id, emp1.code, t1.code;
72607260
Index Cond: (id = emp1.id)
72617261
(5 rows)
72627262

7263-
INSERT INTO emp1 VALUES (1, 1), (2, 1);
7263+
-- Check that SJE correctly replaces relations in OR-clauses
7264+
EXPLAIN (COSTS OFF)
7265+
SELECT * FROM emp1 t1
7266+
INNER JOIN emp1 t2 ON t1.id = t2.id
7267+
LEFT JOIN emp1 t3 ON t1.code = 1 AND (t2.code = t3.code OR t2.code = 1);
7268+
QUERY PLAN
7269+
---------------------------------------------------------------------------
7270+
Nested Loop Left Join
7271+
Join Filter: ((t2.code = 1) AND ((t2.code = t3.code) OR (t2.code = 1)))
7272+
-> Seq Scan on emp1 t2
7273+
-> Materialize
7274+
-> Seq Scan on emp1 t3
7275+
(5 rows)
7276+
7277+
INSERT INTO emp1 VALUES (1, 1), (2, 1);
72647278
WITH t1 AS (SELECT * FROM emp1)
72657279
UPDATE emp1 SET code = t1.code + 1 FROM t1
72667280
WHERE t1.id = emp1.id RETURNING emp1.id, emp1.code, t1.code;

src/test/regress/sql/join.sql

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2807,7 +2807,13 @@ WITH t1 AS (SELECT * FROM emp1)
28072807
UPDATE emp1 SET code = t1.code + 1 FROM t1
28082808
WHERE t1.id = emp1.id RETURNING emp1.id, emp1.code, t1.code;
28092809

2810-
INSERT INTO emp1 VALUES (1, 1), (2, 1);
2810+
-- Check that SJE correctly replaces relations in OR-clauses
2811+
EXPLAIN (COSTS OFF)
2812+
SELECT * FROM emp1 t1
2813+
INNER JOIN emp1 t2 ON t1.id = t2.id
2814+
LEFT JOIN emp1 t3 ON t1.code = 1 AND (t2.code = t3.code OR t2.code = 1);
2815+
2816+
INSERT INTO emp1 VALUES (1, 1), (2, 1);
28112817

28122818
WITH t1 AS (SELECT * FROM emp1)
28132819
UPDATE emp1 SET code = t1.code + 1 FROM t1

0 commit comments

Comments
 (0)