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

Commit03f6794

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 parentada34d7 commit03f6794

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
@@ -2006,7 +2006,7 @@ create_projection_plan(PlannerInfo *root, ProjectionPath *best_path, int flags)
20062006
* Convert our subpath to a Plan and determine whether we need a Result
20072007
* node.
20082008
*
2009-
* In most cases where we don't need to project,creation_projection_path
2009+
* In most cases where we don't need to project,create_projection_path
20102010
* will have set dummypp, but not always. First, some createplan.c
20112011
* routines change the tlists of their nodes. (An example is that
20122012
* 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
@@ -7839,17 +7839,31 @@ get_name_for_var_field(Var *var, int fieldno,
78397839
/*
78407840
* We're deparsing a Plan tree so we don't have complete
78417841
* RTE entries (in particular, rte->subquery is NULL). But
7842-
* the only place we'd see a Var directly referencing a
7843-
* SUBQUERY RTE is in a SubqueryScan plan node, and we can
7844-
* look into the child plan's tlist instead.
7842+
* the only place we'd normally see a Var directly
7843+
* referencing a SUBQUERY RTE is in a SubqueryScan plan
7844+
* node, and we can look into the child plan's tlist
7845+
* instead. An exception occurs if the subquery was
7846+
* proven empty and optimized away: then we'd find such a
7847+
* Var in a childless Result node, and there's nothing in
7848+
* the plan tree that would let us figure out what it had
7849+
* originally referenced. In that case, fall back on
7850+
* printing "fN", analogously to the default column names
7851+
* for RowExprs.
78457852
*/
78467853
TargetEntry*tle;
78477854
deparse_namespacesave_dpns;
78487855
constchar*result;
78497856

78507857
if (!dpns->inner_plan)
7851-
elog(ERROR,"failed to find plan for subquery %s",
7852-
rte->eref->aliasname);
7858+
{
7859+
char*dummy_name=palloc(32);
7860+
7861+
Assert(IsA(dpns->plan,Result));
7862+
snprintf(dummy_name,32,"f%d",fieldno);
7863+
returndummy_name;
7864+
}
7865+
Assert(IsA(dpns->plan,SubqueryScan));
7866+
78537867
tle=get_tle_by_resno(dpns->inner_tlist,attnum);
78547868
if (!tle)
78557869
elog(ERROR,"bogus varattno for subquery var: %d",
@@ -7958,20 +7972,30 @@ get_name_for_var_field(Var *var, int fieldno,
79587972
{
79597973
/*
79607974
* We're deparsing a Plan tree so we don't have a CTE
7961-
* list. But the only places we'd see a Var directly
7962-
* referencing a CTE RTE are in CteScan or WorkTableScan
7963-
* plan nodes. For those cases, set_deparse_plan arranged
7964-
* for dpns->inner_plan to be the plan node that emits the
7965-
* CTE or RecursiveUnion result, and we can look at its
7966-
* tlist instead.
7975+
* list. But the only places we'd normally see a Var
7976+
* directly referencing a CTE RTE are in CteScan or
7977+
* WorkTableScan plan nodes. For those cases,
7978+
* set_deparse_plan arranged for dpns->inner_plan to be
7979+
* the plan node that emits the CTE or RecursiveUnion
7980+
* result, and we can look at its tlist instead. As
7981+
* above, this can fail if the CTE has been proven empty,
7982+
* in which case fall back to "fN".
79677983
*/
79687984
TargetEntry*tle;
79697985
deparse_namespacesave_dpns;
79707986
constchar*result;
79717987

79727988
if (!dpns->inner_plan)
7973-
elog(ERROR,"failed to find plan for CTE %s",
7974-
rte->eref->aliasname);
7989+
{
7990+
char*dummy_name=palloc(32);
7991+
7992+
Assert(IsA(dpns->plan,Result));
7993+
snprintf(dummy_name,32,"f%d",fieldno);
7994+
returndummy_name;
7995+
}
7996+
Assert(IsA(dpns->plan,CteScan)||
7997+
IsA(dpns->plan,WorkTableScan));
7998+
79757999
tle=get_tle_by_resno(dpns->inner_tlist,attnum);
79768000
if (!tle)
79778001
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