Skip to content

Commit c7be3c0

Browse files
committed
Make left-join removal safe under -DREALLOCATE_BITMAPSETS.
The initial building of RestrictInfos and SpecialJoinInfos tends to create structures that share relid sets (such as syn_lefthand and outer_relids). There's nothing wrong with that in itself, but when we modify those relid sets during join removal, we have to be sure not to corrupt the values that other structures are pointing at. remove_rel_from_query() was careless about this. It accidentally worked anyway because (1) we'd never be reducing the sets to empty, so they wouldn't get pfree'd; and (2) the in-place modification is the same one that we did or will apply to the other struct's relid set, so that there wasn't visible corruption at the end of the process. While there's no live bug in a standard build, of course this is way too fragile to accept going forward. (Maybe we should back-patch this change too for safety, but I've refrained for now.) This bug was exposed by the recent invention of REALLOCATE_BITMAPSETS. Commit e047783 had installed a fix, but that went away with the reversion of SJE, so now we need to fix it again. David Rowley and Tom Lane Discussion: https://postgr.es/m/CACJufxFVQmr4=JWHAOSLuKA5Zy9H26nY6tVrRFBOekHoALyCkQ@mail.gmail.com
1 parent e2d5508 commit c7be3c0

File tree

1 file changed

+16
-2
lines changed

1 file changed

+16
-2
lines changed

src/backend/optimizer/plan/analyzejoins.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,17 @@ remove_rel_from_query(PlannerInfo *root, int relid, SpecialJoinInfo *sjinfo)
390390
{
391391
SpecialJoinInfo *sjinf = (SpecialJoinInfo *) lfirst(l);
392392

393+
/*
394+
* initsplan.c is fairly cavalier about allowing SpecialJoinInfos'
395+
* lefthand/righthand relid sets to be shared with other data
396+
* structures. Ensure that we don't modify the original relid sets.
397+
* (The commute_xxx sets are always per-SpecialJoinInfo though.)
398+
*/
399+
sjinf->min_lefthand = bms_copy(sjinf->min_lefthand);
400+
sjinf->min_righthand = bms_copy(sjinf->min_righthand);
401+
sjinf->syn_lefthand = bms_copy(sjinf->syn_lefthand);
402+
sjinf->syn_righthand = bms_copy(sjinf->syn_righthand);
403+
/* Now remove relid and ojrelid bits from the sets: */
393404
sjinf->min_lefthand = bms_del_member(sjinf->min_lefthand, relid);
394405
sjinf->min_righthand = bms_del_member(sjinf->min_righthand, relid);
395406
sjinf->syn_lefthand = bms_del_member(sjinf->syn_lefthand, relid);
@@ -551,8 +562,11 @@ static void
551562
remove_rel_from_restrictinfo(RestrictInfo *rinfo, int relid, int ojrelid)
552563
{
553564
/*
554-
* The clause_relids probably aren't shared with anything else, but let's
555-
* copy them just to be sure.
565+
* initsplan.c is fairly cavalier about allowing RestrictInfos to share
566+
* relid sets with other RestrictInfos, and SpecialJoinInfos too. Make
567+
* sure this RestrictInfo has its own relid sets before we modify them.
568+
* (In present usage, clause_relids is probably not shared, but
569+
* required_relids could be; let's not assume anything.)
556570
*/
557571
rinfo->clause_relids = bms_copy(rinfo->clause_relids);
558572
rinfo->clause_relids = bms_del_member(rinfo->clause_relids, relid);

0 commit comments

Comments
 (0)