Store information about range-table flattening in the final plan.
authorRobert Haas <rhaas@postgresql.org>
Mon, 20 Oct 2025 16:00:18 +0000 (12:00 -0400)
committerRobert Haas <rhaas@postgresql.org>
Wed, 29 Oct 2025 19:37:27 +0000 (15:37 -0400)
commit9da671421efdf1d7395f39622c476193dce1ce69
tree865ee8af41cd2c44f50ff93d6c5c8ac48ea513f4
parent16edc1b94fc2db6e6a376471e280b50a418907c2
Store information about range-table flattening in the final plan.

Suppose that we're currently planning a query and, when that same
query was previously planned and executed, we learned something about
how a certain table within that query should be planned. We want to
take note when that same table is being planned during the current
planning cycle, but this is difficult to do, because the RTI of the
table from the previous plan won't necessarily be equal to the RTI
that we see during the current planning cycle. This is because each
subquery has a separate range table during planning, but these are
flattened into one range table when constructing the final plan,
changing RTIs.

Commit 8c49a484e8ebb0199fba4bd68eaaedaf49b48ed0 allows us to match up
subqueries seen in the previous planning cycles with the subqueries
currently being planned just by comparing textual names, but that's
not quite enough to let us deduce anything about individual tables,
because we don't know where each subquery's range table appears in
the final, flattened range table.

To fix that, store a list of SubPlanRTInfo objects in the final
planned statement, each including the name of the subplan, the offset
at which it begins in the flattened range table, and whether or not
it was a dummy subplan -- if it was, some RTIs may have been dropped
from the final range table, but also there's no need to control how
a dummy subquery gets planned. The toplevel subquery has no name and
always begins at rtoffset 0, so we make no entry for it.

This commit teaches pg_overexplain'e RANGE_TABLE option to make use
of this new data to display the subquery name for each range table
entry.

NOTE TO REVIEWERS: If there's a clean way to make pg_overexplain display
this information without the new infrastructure provided by this patch,
then this patch is unnecessary. I thought there would be a way to do
that, but I couldn't figure anything out: there seems to be nothing that
records in the final PlannedStmt where subquery's range table ends and
the next one begins. In practice, one could usually figure it out by
matching up tables by relation OID, but that's neither clean nor
theoretically sound.
contrib/pg_overexplain/pg_overexplain.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/plan/setrefs.c
src/include/nodes/pathnodes.h
src/include/nodes/plannodes.h
src/tools/pgindent/typedefs.list