Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e047783

Browse files
committed
Make replace_relid() leave argument unmodified
There are a lot of situations when we share the same pointer to a Bitmapset structure across different places. In order to evade undesirable side effects replace_relid() function should always return a copy. Reported-by: Richard Guo Discussion: https://postgr.es/m/CAMbWs4_wJthNtYBL%2BSsebpgF-5L2r5zFFk6xYbS0A78GKOTFHw%40mail.gmail.com Reviewed-by: Richard Guo, Andres Freund, Ashutosh Bapat, Andrei Lepikhov
1 parent 7d58f23 commit e047783

File tree

3 files changed

+29
-3
lines changed

3 files changed

+29
-3
lines changed

src/backend/optimizer/plan/analyzejoins.c

+8-3
Original file line numberDiff line numberDiff line change
@@ -1522,19 +1522,24 @@ replace_varno_walker(Node *node, ReplaceVarnoContext *ctx)
15221522

15231523
/*
15241524
* Substitute newId by oldId in relids.
1525+
*
1526+
* We must make a copy of the original Bitmapset before making any
1527+
* modifications, because the same pointer to it might be shared among
1528+
* different places.
15251529
*/
15261530
static Bitmapset *
15271531
replace_relid(Relids relids, int oldId, int newId)
15281532
{
15291533
if (oldId < 0)
15301534
return relids;
15311535

1536+
/* Delete relid without substitution. */
15321537
if (newId < 0)
1533-
/* Delete relid without substitution. */
1534-
return bms_del_member(relids, oldId);
1538+
return bms_del_member(bms_copy(relids), oldId);
15351539

1540+
/* Substitute newId for oldId. */
15361541
if (bms_is_member(oldId, relids))
1537-
return bms_add_member(bms_del_member(relids, oldId), newId);
1542+
return bms_add_member(bms_del_member(bms_copy(relids), oldId), newId);
15381543

15391544
return relids;
15401545
}

src/test/regress/expected/join.out

+15
Original file line numberDiff line numberDiff line change
@@ -6853,6 +6853,21 @@ on true;
68536853
Filter: (t3.id IS NOT NULL)
68546854
(8 rows)
68556855

6856+
-- Check that SJE replaces join clauses involving the removed rel correctly
6857+
explain (costs off)
6858+
select * from emp1 t1
6859+
inner join emp1 t2 on t1.id = t2.id
6860+
left join emp1 t3 on t1.id > 1 and t1.id < 2;
6861+
QUERY PLAN
6862+
----------------------------------------------
6863+
Nested Loop Left Join
6864+
Join Filter: ((t2.id > 1) AND (t2.id < 2))
6865+
-> Seq Scan on emp1 t2
6866+
Filter: (id IS NOT NULL)
6867+
-> Materialize
6868+
-> Seq Scan on emp1 t3
6869+
(6 rows)
6870+
68566871
-- We can remove the join even if we find the join can't duplicate rows and
68576872
-- the base quals of each side are different. In the following case we end up
68586873
-- moving quals over to s1 to make it so it can't match any rows.

src/test/regress/sql/join.sql

+6
Original file line numberDiff line numberDiff line change
@@ -2610,6 +2610,12 @@ select * from generate_series(1,10) t1(id) left join
26102610
lateral (select t1.id as t1id, t2.id from emp1 t2 join emp1 t3 on t2.id = t3.id)
26112611
on true;
26122612

2613+
-- Check that SJE replaces join clauses involving the removed rel correctly
2614+
explain (costs off)
2615+
select * from emp1 t1
2616+
inner join emp1 t2 on t1.id = t2.id
2617+
left join emp1 t3 on t1.id > 1 and t1.id < 2;
2618+
26132619
-- We can remove the join even if we find the join can't duplicate rows and
26142620
-- the base quals of each side are different. In the following case we end up
26152621
-- moving quals over to s1 to make it so it can't match any rows.

0 commit comments

Comments
 (0)