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

Lines changed: 8 additions & 3 deletions
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

Lines changed: 15 additions & 0 deletions
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

Lines changed: 6 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy