aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlexander Korotkov <akorotkov@postgresql.org>2025-04-29 14:34:44 +0300
committerAlexander Korotkov <akorotkov@postgresql.org>2025-04-29 14:34:44 +0300
commit2260c7f6d90ecf76d3806d32890a0890688b41e8 (patch)
treeca339e2ad4f5db7da9c05b8b9f7e7ff6d83c9cdb /src
parent15b1b4dd3fccfd2576f44841863153c312de011b (diff)
downloadpostgresql-2260c7f6d90ecf76d3806d32890a0890688b41e8.tar.gz
postgresql-2260c7f6d90ecf76d3806d32890a0890688b41e8.zip
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>
Diffstat (limited to 'src')
-rw-r--r--src/backend/rewrite/rewriteManip.c28
-rw-r--r--src/test/regress/expected/join.out16
-rw-r--r--src/test/regress/sql/join.sql8
3 files changed, 46 insertions, 6 deletions
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index e190f169fb3..3f8b8b6eed9 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -644,14 +644,34 @@ ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
bool clause_relids_is_multiple =
(bms_membership(rinfo->clause_relids) == BMS_MULTIPLE);
- if (bms_is_member(context->rt_index, rinfo->clause_relids))
+ /*
+ * Recurse down into clauses if the target relation is present in
+ * clause_relids or required_relids. We must check required_relids
+ * because the relation not present in clause_relids might still be
+ * present somewhere in orclause.
+ */
+ if (bms_is_member(context->rt_index, rinfo->clause_relids) ||
+ bms_is_member(context->rt_index, rinfo->required_relids))
{
+ Relids new_clause_relids;
+
expression_tree_walker((Node *) rinfo->clause, ChangeVarNodes_walker, (void *) context);
expression_tree_walker((Node *) rinfo->orclause, ChangeVarNodes_walker, (void *) context);
- rinfo->clause_relids =
- adjust_relid_set(rinfo->clause_relids, context->rt_index, context->new_index);
- rinfo->num_base_rels = bms_num_members(rinfo->clause_relids);
+ new_clause_relids = adjust_relid_set(rinfo->clause_relids,
+ context->rt_index,
+ context->new_index);
+
+ /*
+ * Incrementally adjust num_base_rels based on the change of
+ * clause_relids, which could contain both base relids and
+ * outer-join relids. This operation is legal until we remove
+ * only baserels.
+ */
+ rinfo->num_base_rels -= bms_num_members(rinfo->clause_relids) -
+ bms_num_members(new_clause_relids);
+
+ rinfo->clause_relids = new_clause_relids;
rinfo->left_relids =
adjust_relid_set(rinfo->left_relids, context->rt_index, context->new_index);
rinfo->right_relids =
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index fa2c7405519..f35a0b18c37 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -7260,7 +7260,21 @@ WHERE t1.id = emp1.id RETURNING emp1.id, emp1.code, t1.code;
Index Cond: (id = emp1.id)
(5 rows)
-INSERT INTO emp1 VALUES (1, 1), (2, 1);
+-- Check that SJE correctly replaces relations in OR-clauses
+EXPLAIN (COSTS OFF)
+SELECT * FROM emp1 t1
+ INNER JOIN emp1 t2 ON t1.id = t2.id
+ LEFT JOIN emp1 t3 ON t1.code = 1 AND (t2.code = t3.code OR t2.code = 1);
+ QUERY PLAN
+---------------------------------------------------------------------------
+ Nested Loop Left Join
+ Join Filter: ((t2.code = 1) AND ((t2.code = t3.code) OR (t2.code = 1)))
+ -> Seq Scan on emp1 t2
+ -> Materialize
+ -> Seq Scan on emp1 t3
+(5 rows)
+
+ INSERT INTO emp1 VALUES (1, 1), (2, 1);
WITH t1 AS (SELECT * FROM emp1)
UPDATE emp1 SET code = t1.code + 1 FROM t1
WHERE t1.id = emp1.id RETURNING emp1.id, emp1.code, t1.code;
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index d01d1da4ef8..cc5128add4d 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -2807,7 +2807,13 @@ WITH t1 AS (SELECT * FROM emp1)
UPDATE emp1 SET code = t1.code + 1 FROM t1
WHERE t1.id = emp1.id RETURNING emp1.id, emp1.code, t1.code;
-INSERT INTO emp1 VALUES (1, 1), (2, 1);
+-- Check that SJE correctly replaces relations in OR-clauses
+EXPLAIN (COSTS OFF)
+SELECT * FROM emp1 t1
+ INNER JOIN emp1 t2 ON t1.id = t2.id
+ LEFT JOIN emp1 t3 ON t1.code = 1 AND (t2.code = t3.code OR t2.code = 1);
+
+ INSERT INTO emp1 VALUES (1, 1), (2, 1);
WITH t1 AS (SELECT * FROM emp1)
UPDATE emp1 SET code = t1.code + 1 FROM t1