Skip to content

Commit 9a85860

Browse files
committed
Fix handling of "Subplans Removed" field in EXPLAIN output.
Commit 499be01 added this field in a rather poorly-thought-through manner, with the result being that rather than being a field of the Append or MergeAppend plan node as intended (and as it seems to be, in text format), it was actually an element of the "Plans" subgroup. At least in JSON format, that's flat out invalid syntax, because "Plans" is an array not an object. While it's not hard to move the generation of the field so that it appears where it's supposed to, this does result in a visible change in field order in text format, in cases where a Append or MergeAppend plan node has any InitPlans attached. That's slightly annoying to do in stable branches; but the alternative of continuing to emit broken non-text formats seems worse. Also, since the set of fields emitted is not supposed to be data-dependent in non-text formats, make sure that "Subplans Removed" appears in Append and MergeAppend nodes even when it's zero, in those formats. (The previous coding made it look like it could appear in some other node types such as BitmapAnd, but we don't actually support runtime pruning there, so don't emit it in those cases.) Per bug #16171 from Mahadevan Ramachandran. Fix by Daniel Gustafsson and Tom Lane, reviewed by Hamid Akhtar. Back-patch to v11 where this code came in. Discussion: https://postgr.es/m/16171-b72259ab75505fa2@postgresql.org
1 parent 42e3187 commit 9a85860

File tree

2 files changed

+50
-29
lines changed

2 files changed

+50
-29
lines changed

src/backend/commands/explain.c

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,9 @@ static void ExplainModifyTarget(ModifyTable *plan, ExplainState *es);
117117
static void ExplainTargetRel(Plan *plan, Index rti, ExplainState *es);
118118
static void show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
119119
ExplainState *es);
120-
static void ExplainMemberNodes(PlanState **planstates, int nsubnodes,
121-
int nplans, List *ancestors, ExplainState *es);
120+
static void ExplainMemberNodes(PlanState **planstates, int nplans,
121+
List *ancestors, ExplainState *es);
122+
static void ExplainMissingMembers(int nplans, int nchildren, ExplainState *es);
122123
static void ExplainSubPlans(List *plans, List *ancestors,
123124
const char *relationship, ExplainState *es);
124125
static void ExplainCustomChildren(CustomScanState *css,
@@ -1933,6 +1934,30 @@ ExplainNode(PlanState *planstate, List *ancestors,
19331934
ExplainCloseGroup("Workers", "Workers", false, es);
19341935
}
19351936

1937+
/*
1938+
* If partition pruning was done during executor initialization, the
1939+
* number of child plans we'll display below will be less than the number
1940+
* of subplans that was specified in the plan. To make this a bit less
1941+
* mysterious, emit an indication that this happened. Note that this
1942+
* field is emitted now because we want it to be a property of the parent
1943+
* node; it *cannot* be emitted within the Plans sub-node we'll open next.
1944+
*/
1945+
switch (nodeTag(plan))
1946+
{
1947+
case T_Append:
1948+
ExplainMissingMembers(((AppendState *) planstate)->as_nplans,
1949+
list_length(((Append *) plan)->appendplans),
1950+
es);
1951+
break;
1952+
case T_MergeAppend:
1953+
ExplainMissingMembers(((MergeAppendState *) planstate)->ms_nplans,
1954+
list_length(((MergeAppend *) plan)->mergeplans),
1955+
es);
1956+
break;
1957+
default:
1958+
break;
1959+
}
1960+
19361961
/* Get ready to display the child plans */
19371962
haschildren = planstate->initPlan ||
19381963
outerPlanState(planstate) ||
@@ -1973,31 +1998,26 @@ ExplainNode(PlanState *planstate, List *ancestors,
19731998
case T_ModifyTable:
19741999
ExplainMemberNodes(((ModifyTableState *) planstate)->mt_plans,
19752000
((ModifyTableState *) planstate)->mt_nplans,
1976-
list_length(((ModifyTable *) plan)->plans),
19772001
ancestors, es);
19782002
break;
19792003
case T_Append:
19802004
ExplainMemberNodes(((AppendState *) planstate)->appendplans,
19812005
((AppendState *) planstate)->as_nplans,
1982-
list_length(((Append *) plan)->appendplans),
19832006
ancestors, es);
19842007
break;
19852008
case T_MergeAppend:
19862009
ExplainMemberNodes(((MergeAppendState *) planstate)->mergeplans,
19872010
((MergeAppendState *) planstate)->ms_nplans,
1988-
list_length(((MergeAppend *) plan)->mergeplans),
19892011
ancestors, es);
19902012
break;
19912013
case T_BitmapAnd:
19922014
ExplainMemberNodes(((BitmapAndState *) planstate)->bitmapplans,
19932015
((BitmapAndState *) planstate)->nplans,
1994-
list_length(((BitmapAnd *) plan)->bitmapplans),
19952016
ancestors, es);
19962017
break;
19972018
case T_BitmapOr:
19982019
ExplainMemberNodes(((BitmapOrState *) planstate)->bitmapplans,
19992020
((BitmapOrState *) planstate)->nplans,
2000-
list_length(((BitmapOr *) plan)->bitmapplans),
20012021
ancestors, es);
20022022
break;
20032023
case T_SubqueryScan:
@@ -3310,32 +3330,33 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
33103330
*
33113331
* The ancestors list should already contain the immediate parent of these
33123332
* plans.
3313-
*
3314-
* nsubnodes indicates the number of items in the planstates array.
3315-
* nplans indicates the original number of subnodes in the Plan, some of these
3316-
* may have been pruned by the run-time pruning code.
33173333
*/
33183334
static void
3319-
ExplainMemberNodes(PlanState **planstates, int nsubnodes, int nplans,
3335+
ExplainMemberNodes(PlanState **planstates, int nplans,
33203336
List *ancestors, ExplainState *es)
33213337
{
33223338
int j;
33233339

3324-
/*
3325-
* The number of subnodes being lower than the number of subplans that was
3326-
* specified in the plan means that some subnodes have been ignored per
3327-
* instruction for the partition pruning code during the executor
3328-
* initialization. To make this a bit less mysterious, we'll indicate
3329-
* here that this has happened.
3330-
*/
3331-
if (nsubnodes < nplans)
3332-
ExplainPropertyInteger("Subplans Removed", NULL, nplans - nsubnodes, es);
3333-
3334-
for (j = 0; j < nsubnodes; j++)
3340+
for (j = 0; j < nplans; j++)
33353341
ExplainNode(planstates[j], ancestors,
33363342
"Member", NULL, es);
33373343
}
33383344

3345+
/*
3346+
* Report about any pruned subnodes of an Append or MergeAppend node.
3347+
*
3348+
* nplans indicates the number of live subplans.
3349+
* nchildren indicates the original number of subnodes in the Plan;
3350+
* some of these may have been pruned by the run-time pruning code.
3351+
*/
3352+
static void
3353+
ExplainMissingMembers(int nplans, int nchildren, ExplainState *es)
3354+
{
3355+
if (nplans < nchildren || es->format != EXPLAIN_FORMAT_TEXT)
3356+
ExplainPropertyInteger("Subplans Removed", NULL,
3357+
nchildren - nplans, es);
3358+
}
3359+
33393360
/*
33403361
* Explain a list of SubPlans (or initPlans, which also use SubPlan nodes).
33413362
*

src/test/regress/expected/partition_prune.out

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,9 +1846,9 @@ explain (analyze, costs off, summary off, timing off) execute ab_q2 (2, 2);
18461846
QUERY PLAN
18471847
--------------------------------------------------------
18481848
Append (actual rows=0 loops=1)
1849+
Subplans Removed: 6
18491850
InitPlan 1 (returns $0)
18501851
-> Result (actual rows=1 loops=1)
1851-
Subplans Removed: 6
18521852
-> Seq Scan on ab_a2_b1 (actual rows=0 loops=1)
18531853
Filter: ((a >= $1) AND (a <= $2) AND (b < $0))
18541854
-> Seq Scan on ab_a2_b2 (actual rows=0 loops=1)
@@ -1889,9 +1889,9 @@ explain (analyze, costs off, summary off, timing off) execute ab_q3 (2, 2);
18891889
QUERY PLAN
18901890
--------------------------------------------------------
18911891
Append (actual rows=0 loops=1)
1892+
Subplans Removed: 6
18921893
InitPlan 1 (returns $0)
18931894
-> Result (actual rows=1 loops=1)
1894-
Subplans Removed: 6
18951895
-> Seq Scan on ab_a1_b2 (actual rows=0 loops=1)
18961896
Filter: ((b >= $1) AND (b <= $2) AND (a < $0))
18971897
-> Seq Scan on ab_a2_b2 (actual rows=0 loops=1)
@@ -2527,9 +2527,9 @@ explain (analyze, costs off, summary off, timing off) execute ab_q6(1);
25272527
QUERY PLAN
25282528
--------------------------------------------------------
25292529
Append (actual rows=0 loops=1)
2530+
Subplans Removed: 12
25302531
InitPlan 1 (returns $0)
25312532
-> Result (actual rows=1 loops=1)
2532-
Subplans Removed: 12
25332533
-> Seq Scan on ab_a1_b1 (never executed)
25342534
Filter: ((a = $1) AND (b = $0))
25352535
-> Seq Scan on ab_a1_b2 (never executed)
@@ -3250,9 +3250,9 @@ execute ps1(1);
32503250
QUERY PLAN
32513251
-------------------------------------------------
32523252
Append (actual rows=1 loops=1)
3253+
Subplans Removed: 2
32533254
InitPlan 1 (returns $0)
32543255
-> Result (actual rows=1 loops=1)
3255-
Subplans Removed: 2
32563256
-> Seq Scan on mc3p1 (actual rows=1 loops=1)
32573257
Filter: ((a = $1) AND (abs(b) < $0))
32583258
(6 rows)
@@ -3265,9 +3265,9 @@ execute ps2(1);
32653265
QUERY PLAN
32663266
-------------------------------------------------
32673267
Append (actual rows=2 loops=1)
3268+
Subplans Removed: 1
32683269
InitPlan 1 (returns $0)
32693270
-> Result (actual rows=1 loops=1)
3270-
Subplans Removed: 1
32713271
-> Seq Scan on mc3p0 (actual rows=1 loops=1)
32723272
Filter: ((a <= $1) AND (abs(b) < $0))
32733273
-> Seq Scan on mc3p1 (actual rows=1 loops=1)
@@ -3845,9 +3845,9 @@ explain (costs off) execute q (1, 1);
38453845
QUERY PLAN
38463846
---------------------------------------------------------------
38473847
Append
3848+
Subplans Removed: 1
38483849
InitPlan 1 (returns $0)
38493850
-> Result
3850-
Subplans Removed: 1
38513851
-> Seq Scan on p1
38523852
Filter: ((a = $1) AND (b = $2) AND (c = $0))
38533853
-> Seq Scan on q111

0 commit comments

Comments
 (0)