Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb919a97

Browse files
committed
Fix "failed to find plan for subquery/CTE" errors in EXPLAIN.
To deparse a reference to a field of a RECORD-type output of asubquery, EXPLAIN normally digs down into the subquery's plan to tryto discover exactly which anonymous RECORD type is meant. However,this can fail if the subquery has been optimized out of the planaltogether on the grounds that no rows could pass the WHERE quals,which has been possible at least since3fc6e2d. There isn'tanything remaining in the plan tree that would help us, so fall backto printing the field name as "fN" for the N'th column of the record.(This will actually be the right thing some of the time, since itmatches the column names we assign to RowExprs.)In passing, fix a comment typo in create_projection_plan, whichI noticed while experimenting with an alternative fix for this.Per bug #18576 from Vasya B. Back-patch to all supported branches.Richard Guo and Tom LaneDiscussion:https://postgr.es/m/18576-9feac34e132fea9e@postgresql.org
1 parent7da1bdc commitb919a97

File tree

4 files changed

+113
-14
lines changed

4 files changed

+113
-14
lines changed

‎src/backend/optimizer/plan/createplan.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2022,7 +2022,7 @@ create_projection_plan(PlannerInfo *root, ProjectionPath *best_path, int flags)
20222022
* Convert our subpath to a Plan and determine whether we need a Result
20232023
* node.
20242024
*
2025-
* In most cases where we don't need to project,creation_projection_path
2025+
* In most cases where we don't need to project,create_projection_path
20262026
* will have set dummypp, but not always. First, some createplan.c
20272027
* routines change the tlists of their nodes. (An example is that
20282028
* create_merge_append_plan might add resjunk sort columns to a

‎src/backend/utils/adt/ruleutils.c

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7895,17 +7895,31 @@ get_name_for_var_field(Var *var, int fieldno,
78957895
/*
78967896
* We're deparsing a Plan tree so we don't have complete
78977897
* RTE entries (in particular, rte->subquery is NULL). But
7898-
* the only place we'd see a Var directly referencing a
7899-
* SUBQUERY RTE is in a SubqueryScan plan node, and we can
7900-
* look into the child plan's tlist instead.
7898+
* the only place we'd normally see a Var directly
7899+
* referencing a SUBQUERY RTE is in a SubqueryScan plan
7900+
* node, and we can look into the child plan's tlist
7901+
* instead. An exception occurs if the subquery was
7902+
* proven empty and optimized away: then we'd find such a
7903+
* Var in a childless Result node, and there's nothing in
7904+
* the plan tree that would let us figure out what it had
7905+
* originally referenced. In that case, fall back on
7906+
* printing "fN", analogously to the default column names
7907+
* for RowExprs.
79017908
*/
79027909
TargetEntry*tle;
79037910
deparse_namespacesave_dpns;
79047911
constchar*result;
79057912

79067913
if (!dpns->inner_plan)
7907-
elog(ERROR,"failed to find plan for subquery %s",
7908-
rte->eref->aliasname);
7914+
{
7915+
char*dummy_name=palloc(32);
7916+
7917+
Assert(IsA(dpns->plan,Result));
7918+
snprintf(dummy_name,32,"f%d",fieldno);
7919+
returndummy_name;
7920+
}
7921+
Assert(IsA(dpns->plan,SubqueryScan));
7922+
79097923
tle=get_tle_by_resno(dpns->inner_tlist,attnum);
79107924
if (!tle)
79117925
elog(ERROR,"bogus varattno for subquery var: %d",
@@ -8014,20 +8028,30 @@ get_name_for_var_field(Var *var, int fieldno,
80148028
{
80158029
/*
80168030
* We're deparsing a Plan tree so we don't have a CTE
8017-
* list. But the only places we'd see a Var directly
8018-
* referencing a CTE RTE are in CteScan or WorkTableScan
8019-
* plan nodes. For those cases, set_deparse_plan arranged
8020-
* for dpns->inner_plan to be the plan node that emits the
8021-
* CTE or RecursiveUnion result, and we can look at its
8022-
* tlist instead.
8031+
* list. But the only places we'd normally see a Var
8032+
* directly referencing a CTE RTE are in CteScan or
8033+
* WorkTableScan plan nodes. For those cases,
8034+
* set_deparse_plan arranged for dpns->inner_plan to be
8035+
* the plan node that emits the CTE or RecursiveUnion
8036+
* result, and we can look at its tlist instead. As
8037+
* above, this can fail if the CTE has been proven empty,
8038+
* in which case fall back to "fN".
80238039
*/
80248040
TargetEntry*tle;
80258041
deparse_namespacesave_dpns;
80268042
constchar*result;
80278043

80288044
if (!dpns->inner_plan)
8029-
elog(ERROR,"failed to find plan for CTE %s",
8030-
rte->eref->aliasname);
8045+
{
8046+
char*dummy_name=palloc(32);
8047+
8048+
Assert(IsA(dpns->plan,Result));
8049+
snprintf(dummy_name,32,"f%d",fieldno);
8050+
returndummy_name;
8051+
}
8052+
Assert(IsA(dpns->plan,CteScan)||
8053+
IsA(dpns->plan,WorkTableScan));
8054+
80318055
tle=get_tle_by_resno(dpns->inner_tlist,attnum);
80328056
if (!tle)
80338057
elog(ERROR,"bogus varattno for subquery var: %d",

‎src/test/regress/expected/rowtypes.out

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,6 +1300,60 @@ select pg_get_viewdef('composite_v', true);
13001300
(1 row)
13011301

13021302
drop view composite_v;
1303+
--
1304+
-- Check cases where the composite comes from a proven-dummy rel (bug #18576)
1305+
--
1306+
explain (verbose, costs off)
1307+
select (ss.a).x, (ss.a).n from
1308+
(select information_schema._pg_expandarray(array[1,2]) AS a) ss;
1309+
QUERY PLAN
1310+
------------------------------------------------------------------------
1311+
Subquery Scan on ss
1312+
Output: (ss.a).x, (ss.a).n
1313+
-> ProjectSet
1314+
Output: information_schema._pg_expandarray('{1,2}'::integer[])
1315+
-> Result
1316+
(5 rows)
1317+
1318+
explain (verbose, costs off)
1319+
select (ss.a).x, (ss.a).n from
1320+
(select information_schema._pg_expandarray(array[1,2]) AS a) ss
1321+
where false;
1322+
QUERY PLAN
1323+
--------------------------
1324+
Result
1325+
Output: (a).f1, (a).f2
1326+
One-Time Filter: false
1327+
(3 rows)
1328+
1329+
explain (verbose, costs off)
1330+
with cte(c) as materialized (select row(1, 2)),
1331+
cte2(c) as (select * from cte)
1332+
select (c).f1 from cte2 as t;
1333+
QUERY PLAN
1334+
-----------------------------------
1335+
CTE Scan on cte
1336+
Output: (cte.c).f1
1337+
CTE cte
1338+
-> Result
1339+
Output: '(1,2)'::record
1340+
(5 rows)
1341+
1342+
explain (verbose, costs off)
1343+
with cte(c) as materialized (select row(1, 2)),
1344+
cte2(c) as (select * from cte)
1345+
select (c).f1 from cte2 as t
1346+
where false;
1347+
QUERY PLAN
1348+
-----------------------------------
1349+
Result
1350+
Output: (cte.c).f1
1351+
One-Time Filter: false
1352+
CTE cte
1353+
-> Result
1354+
Output: '(1,2)'::record
1355+
(6 rows)
1356+
13031357
--
13041358
-- Tests for component access / FieldSelect
13051359
--

‎src/test/regress/sql/rowtypes.sql

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,27 @@ where (select * from (select c as c1) s
520520
select pg_get_viewdef('composite_v', true);
521521
dropview composite_v;
522522

523+
--
524+
-- Check cases where the composite comes from a proven-dummy rel (bug #18576)
525+
--
526+
explain (verbose, costs off)
527+
select (ss.a).x, (ss.a).nfrom
528+
(selectinformation_schema._pg_expandarray(array[1,2])AS a) ss;
529+
explain (verbose, costs off)
530+
select (ss.a).x, (ss.a).nfrom
531+
(selectinformation_schema._pg_expandarray(array[1,2])AS a) ss
532+
where false;
533+
534+
explain (verbose, costs off)
535+
with cte(c)as materialized (select row(1,2)),
536+
cte2(c)as (select*from cte)
537+
select (c).f1from cte2as t;
538+
explain (verbose, costs off)
539+
with cte(c)as materialized (select row(1,2)),
540+
cte2(c)as (select*from cte)
541+
select (c).f1from cte2as t
542+
where false;
543+
523544
--
524545
-- Tests for component access / FieldSelect
525546
--

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp