Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 727bc6a

Browse files
author
Richard Guo
committed
Fix freeing a child join's SpecialJoinInfo
In try_partitionwise_join, we try to break down the join between two partitioned relations into joins between matching partitions. To achieve this, we iterate through each pair of partitions from the two joining relations and create child join relations for them. To reduce memory accumulation during each iteration, one step we take is freeing the SpecialJoinInfos created for the child joins. A child join's SpecialJoinInfo is a copy of the parent join's SpecialJoinInfo, with some members being translated copies of their counterparts in the parent. However, when freeing the bitmapset members in a child join's SpecialJoinInfo, we failed to check whether they were translated copies. As a result, we inadvertently freed the members that were still in use by the parent SpecialJoinInfo, leading to crashes when those freed members were accessed. To fix, check if each member of the child join's SpecialJoinInfo is a translated copy and free it only if that's the case. This requires passing the parent join's SpecialJoinInfo as a parameter to free_child_join_sjinfo. Back-patch to v17 where this bug crept in. Bug: #18806 Reported-by: 孟令彬 <m_lingbin@126.com> Diagnosed-by: Tender Wang <tndrwang@gmail.com> Author: Richard Guo <guofenglinux@gmail.com> Reviewed-by: Amit Langote <amitlangote09@gmail.com> Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com> Discussion: https://postgr.es/m/18806-d70b0c9fdf63dcbf@postgresql.org Backpatch-through: 17
1 parent a68a759 commit 727bc6a

File tree

3 files changed

+64
-9
lines changed

3 files changed

+64
-9
lines changed

src/backend/optimizer/path/joinrels.c

+25-9
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ static void try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1,
4545
static SpecialJoinInfo *build_child_join_sjinfo(PlannerInfo *root,
4646
SpecialJoinInfo *parent_sjinfo,
4747
Relids left_relids, Relids right_relids);
48-
static void free_child_join_sjinfo(SpecialJoinInfo *sjinfo);
48+
static void free_child_join_sjinfo(SpecialJoinInfo *child_sjinfo,
49+
SpecialJoinInfo *parent_sjinfo);
4950
static void compute_partition_bounds(PlannerInfo *root, RelOptInfo *rel1,
5051
RelOptInfo *rel2, RelOptInfo *joinrel,
5152
SpecialJoinInfo *parent_sjinfo,
@@ -1677,7 +1678,7 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
16771678
child_restrictlist);
16781679

16791680
pfree(appinfos);
1680-
free_child_join_sjinfo(child_sjinfo);
1681+
free_child_join_sjinfo(child_sjinfo, parent_sjinfo);
16811682
}
16821683
}
16831684

@@ -1744,26 +1745,41 @@ build_child_join_sjinfo(PlannerInfo *root, SpecialJoinInfo *parent_sjinfo,
17441745
* SpecialJoinInfo are freed here.
17451746
*/
17461747
static void
1747-
free_child_join_sjinfo(SpecialJoinInfo *sjinfo)
1748+
free_child_join_sjinfo(SpecialJoinInfo *child_sjinfo,
1749+
SpecialJoinInfo *parent_sjinfo)
17481750
{
17491751
/*
17501752
* Dummy SpecialJoinInfos of inner joins do not have any translated fields
17511753
* and hence no fields that to be freed.
17521754
*/
1753-
if (sjinfo->jointype != JOIN_INNER)
1755+
if (child_sjinfo->jointype != JOIN_INNER)
17541756
{
1755-
bms_free(sjinfo->min_lefthand);
1756-
bms_free(sjinfo->min_righthand);
1757-
bms_free(sjinfo->syn_lefthand);
1758-
bms_free(sjinfo->syn_righthand);
1757+
if (child_sjinfo->min_lefthand != parent_sjinfo->min_lefthand)
1758+
bms_free(child_sjinfo->min_lefthand);
1759+
1760+
if (child_sjinfo->min_righthand != parent_sjinfo->min_righthand)
1761+
bms_free(child_sjinfo->min_righthand);
1762+
1763+
if (child_sjinfo->syn_lefthand != parent_sjinfo->syn_lefthand)
1764+
bms_free(child_sjinfo->syn_lefthand);
1765+
1766+
if (child_sjinfo->syn_righthand != parent_sjinfo->syn_righthand)
1767+
bms_free(child_sjinfo->syn_righthand);
1768+
1769+
Assert(child_sjinfo->commute_above_l == parent_sjinfo->commute_above_l);
1770+
Assert(child_sjinfo->commute_above_r == parent_sjinfo->commute_above_r);
1771+
Assert(child_sjinfo->commute_below_l == parent_sjinfo->commute_below_l);
1772+
Assert(child_sjinfo->commute_below_r == parent_sjinfo->commute_below_r);
1773+
1774+
Assert(child_sjinfo->semi_operators == parent_sjinfo->semi_operators);
17591775

17601776
/*
17611777
* semi_rhs_exprs may in principle be freed, but a simple pfree() does
17621778
* not suffice, so we leave it alone.
17631779
*/
17641780
}
17651781

1766-
pfree(sjinfo);
1782+
pfree(child_sjinfo);
17671783
}
17681784

17691785
/*

src/test/regress/expected/partition_join.out

+35
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,41 @@ SELECT a, b FROM prt1 FULL JOIN prt2 p2(b,a,c) USING(a,b)
674674

675675
RESET enable_partitionwise_aggregate;
676676
RESET enable_hashjoin;
677+
-- bug in freeing the SpecialJoinInfo of a child-join
678+
EXPLAIN (COSTS OFF)
679+
SELECT * FROM prt1 t1 JOIN prt1 t2 ON t1.a = t2.a WHERE t1.a IN (SELECT a FROM prt1 t3);
680+
QUERY PLAN
681+
--------------------------------------------------
682+
Append
683+
-> Hash Semi Join
684+
Hash Cond: (t1_1.a = t3_1.a)
685+
-> Hash Join
686+
Hash Cond: (t1_1.a = t2_1.a)
687+
-> Seq Scan on prt1_p1 t1_1
688+
-> Hash
689+
-> Seq Scan on prt1_p1 t2_1
690+
-> Hash
691+
-> Seq Scan on prt1_p1 t3_1
692+
-> Hash Semi Join
693+
Hash Cond: (t1_2.a = t3_2.a)
694+
-> Hash Join
695+
Hash Cond: (t1_2.a = t2_2.a)
696+
-> Seq Scan on prt1_p2 t1_2
697+
-> Hash
698+
-> Seq Scan on prt1_p2 t2_2
699+
-> Hash
700+
-> Seq Scan on prt1_p2 t3_2
701+
-> Hash Semi Join
702+
Hash Cond: (t1_3.a = t3_3.a)
703+
-> Hash Join
704+
Hash Cond: (t1_3.a = t2_3.a)
705+
-> Seq Scan on prt1_p3 t1_3
706+
-> Hash
707+
-> Seq Scan on prt1_p3 t2_3
708+
-> Hash
709+
-> Seq Scan on prt1_p3 t3_3
710+
(28 rows)
711+
677712
--
678713
-- partitioned by expression
679714
--

src/test/regress/sql/partition_join.sql

+4
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ SELECT a, b FROM prt1 FULL JOIN prt2 p2(b,a,c) USING(a,b)
138138
RESET enable_partitionwise_aggregate;
139139
RESET enable_hashjoin;
140140

141+
-- bug in freeing the SpecialJoinInfo of a child-join
142+
EXPLAIN (COSTS OFF)
143+
SELECT * FROM prt1 t1 JOIN prt1 t2 ON t1.a = t2.a WHERE t1.a IN (SELECT a FROM prt1 t3);
144+
141145
--
142146
-- partitioned by expression
143147
--

0 commit comments

Comments
 (0)