1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Add child_append_relid_sets to ElidedNode; use in pg_plan_advice.

Commit 0d4391b265 taught the planner
to store information about the RTIs of SubqueryScan, Append, and
MergeAppend node elided from the plan using a new ElidedNode data
structure; an hour later, 7358abcc60
taught to save the RTIs of an Append node into another Append
node using a new child_append_relid_sets field.  Regrettably,
despite the fact that both commits were written by me and the
fact that both were part of the same patch set, the latter commit
failed to deal with the case where an Append node first acquires
child_append_relid_sets != NIL and then gets elided. I believe that
I thought that was impossible, but the included test case shows that
it isn't.

The proper fix involves updating the definition of ElidedNode to
carry child_append_relid_sets, so this commit does that, breaking
ABI compatibility. That's fine for the master branch, but it's a
bit unfortunate to be doing do that so close to the planned ship
date for v19.  However, shipping v19 without fixing this appears
(at least to me) to be even more unfortunate.

Backpatch-through: 19
Discussion: http://postgr.es/m/CA+TgmoYYHC4i-Gpzc9-JYHqih6pOK+6LTYFiNR-PioXG1nKkOQ@mail.gmail.com
This commit is contained in:
Robert Haas
2026-10-08 14:12:24 -04:00
parent 08f24a1152
commit 80db5ca9ec
7 changed files with 46 additions and 8 deletions

View File

@@ -592,6 +592,7 @@ SELECT * FROM vegetables WHERE genus = 'daucus';
Scan RTI: 2
Elided Node Type: Append
Elided Node RTIs: 1
Elided Node Child Append RTIs: none
RTI 1 (relation, inherited, in-from-clause):
Eref: vegetables (id, name, genus)
Relation: vegetables
@@ -605,7 +606,7 @@ SELECT * FROM vegetables WHERE genus = 'daucus';
Relation Kind: relation
Relation Lock Mode: AccessShareLock
Unprunable RTIs: 1 2
(18 rows)
(19 rows)
-- Also test a case that involves a write.
EXPLAIN (RANGE_TABLE, COSTS OFF)
@@ -641,6 +642,7 @@ SELECT * FROM vegetables v,
Scan RTI: 6
Elided Node Type: Append
Elided Node RTIs: 5
Elided Node Child Append RTIs: none
Elided Node Type: SubqueryScan
Elided Node RTIs: 2
-> Append
@@ -687,7 +689,7 @@ SELECT * FROM vegetables v,
Relation Kind: relation
Relation Lock Mode: AccessShareLock
Unprunable RTIs: 1 3 4 5 6
(52 rows)
(53 rows)
-- should show "Subplan: unnamed_subquery"
EXPLAIN (RANGE_TABLE, COSTS OFF)
@@ -701,6 +703,7 @@ SELECT * FROM vegetables v,
Scan RTI: 6
Elided Node Type: Append
Elided Node RTIs: 5
Elided Node Child Append RTIs: none
Elided Node Type: SubqueryScan
Elided Node RTIs: 2
-> Append
@@ -746,7 +749,7 @@ SELECT * FROM vegetables v,
Relation Kind: relation
Relation Lock Mode: AccessShareLock
Unprunable RTIs: 1 3 4 5 6
(51 rows)
(52 rows)
-- test display of child append RTIs
EXPLAIN (RANGE_TABLE, COSTS OFF)

View File

@@ -297,6 +297,9 @@ overexplain_per_node_hook(PlanState *planstate, List *ancestors,
ExplainOpenGroup("Elided Node", NULL, true, es);
ExplainPropertyText("Elided Node Type", elidednodetag, es);
overexplain_bitmapset("Elided Node RTIs", n->relids, es);
if (n->elided_type == T_Append || n->elided_type == T_MergeAppend)
overexplain_bitmapset_list("Elided Node Child Append RTIs",
n->child_append_relid_sets, es);
ExplainCloseGroup("Elided Node", NULL, true, es);
}
if (opened_elided_nodes)

View File

@@ -476,3 +476,16 @@ SELECT * FROM mllpt WHERE a = 1 UNION ALL SELECT * FROM mllpt;
mllpt/public.mllpt_a1_b2@unnamed_subquery mllpt/public.mllpt_a1_b3@unnamed_subquery)
(27 rows)
-- Same, but prune down to a single leaf so the Append is elided.
EXPLAIN (PLAN_ADVICE, COSTS OFF)
SELECT * FROM mllpt WHERE a = 1 AND b = 1;
QUERY PLAN
----------------------------------------------
Seq Scan on mllpt_a1_b1 mllpt
Filter: ((a = 1) AND (b = 1))
Generated Plan Advice:
SEQ_SCAN(mllpt/public.mllpt_a1_b1)
PARTITIONWISE(mllpt/public.mllpt_a1 mllpt)
NO_GATHER(mllpt/public.mllpt_a1_b1)
(6 rows)

View File

@@ -83,6 +83,9 @@ pgpa_build_scan(pgpa_plan_walker_context *walker, Plan *plan,
else
strategy = PGPA_SCAN_ORDINARY;
/* Be sure to account for pulled-up scans, as for a live Append. */
child_append_relid_sets = elided_node->child_append_relid_sets;
/* Join RTIs can be present, but advice never refers to them. */
relids = pgpa_filter_out_join_relids(relids, walker->pstmt->rtable);
}

View File

@@ -123,3 +123,7 @@ COMMIT;
-- We should get PARTITIONWISE advice for all unpruned partition tables.
EXPLAIN (PLAN_ADVICE, COSTS OFF)
SELECT * FROM mllpt WHERE a = 1 UNION ALL SELECT * FROM mllpt;
-- Same, but prune down to a single leaf so the Append is elided.
EXPLAIN (PLAN_ADVICE, COSTS OFF)
SELECT * FROM mllpt WHERE a = 1 AND b = 1;

View File

@@ -214,7 +214,8 @@ static List *set_windowagg_runcondition_references(PlannerInfo *root,
Plan *plan);
static void record_elided_node(PlannerGlobal *glob, int plan_node_id,
NodeTag elided_type, Bitmapset *relids);
NodeTag elided_type, Bitmapset *relids,
List *child_append_relid_sets);
/*****************************************************************************
@@ -1480,7 +1481,8 @@ set_subqueryscan_references(PlannerInfo *root,
/* Remember that we removed a SubqueryScan */
scanrelid = plan->scan.scanrelid + rtoffset;
record_elided_node(root->glob, plan->subplan->plan_node_id,
T_SubqueryScan, bms_make_singleton(scanrelid));
T_SubqueryScan, bms_make_singleton(scanrelid),
NIL);
}
else
{
@@ -1915,7 +1917,9 @@ set_append_references(PlannerInfo *root,
/* Remember that we removed an Append */
record_elided_node(root->glob, p->plan_node_id, T_Append,
offset_relid_set(aplan->apprelids, rtoffset));
offset_relid_set(aplan->apprelids, rtoffset),
offset_relid_set_list(aplan->child_append_relid_sets,
rtoffset));
return result;
}
@@ -1995,7 +1999,9 @@ set_mergeappend_references(PlannerInfo *root,
/* Remember that we removed a MergeAppend */
record_elided_node(root->glob, p->plan_node_id, T_MergeAppend,
offset_relid_set(mplan->apprelids, rtoffset));
offset_relid_set(mplan->apprelids, rtoffset),
offset_relid_set_list(mplan->child_append_relid_sets,
rtoffset));
return result;
}
@@ -3873,13 +3879,15 @@ extract_query_dependencies_walker(Node *node, PlannerInfo *context)
*/
static void
record_elided_node(PlannerGlobal *glob, int plan_node_id,
NodeTag elided_type, Bitmapset *relids)
NodeTag elided_type, Bitmapset *relids,
List *child_append_relid_sets)
{
ElidedNode *n = makeNode(ElidedNode);
n->plan_node_id = plan_node_id;
n->elided_type = elided_type;
n->relids = relids;
n->child_append_relid_sets = child_append_relid_sets;
glob->elidedNodes = lappend(glob->elidedNodes, n);
}

View File

@@ -1862,6 +1862,9 @@ typedef struct SubPlanRTInfo
*
* plan_node_id is that of the surviving plan node, the sole child of the
* one which was elided.
*
* For an elided Append or MergeAppend, child_append_relid_sets is the
* child_append_relid_sets value from the removed node; otherwise, it is NIL.
*/
typedef struct ElidedNode
{
@@ -1869,6 +1872,7 @@ typedef struct ElidedNode
int plan_node_id;
NodeTag elided_type;
Bitmapset *relids;
List *child_append_relid_sets;
} ElidedNode;
#endif /* PLANNODES_H */