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

Commit7948522

Browse files
tglsfdcpull[bot]
authored andcommitted
Track nesting depth correctly when drilling down into RECORD Vars.
expandRecordVariable() failed to adjust the parse nesting structurecorrectly when recursing to inspect an outer-level Var. This couldresult in assertion failures or core dumps in corner cases.Likewise, get_name_for_var_field() failed to adjust the deparsenamespace stack correctly when recursing to inspect an outer-levelVar. In this case the likely result was a "bogus varno" errorwhile deparsing a view.Per bug #18077 from Jingzhou Fu. Back-patch to all supportedbranches.Richard Guo, with some adjustments by meDiscussion:https://postgr.es/m/18077-b9db97c6e0ab45d8@postgresql.org
1 parent77553de commit7948522

File tree

4 files changed

+119
-20
lines changed

4 files changed

+119
-20
lines changed

‎src/backend/parser/parse_target.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,7 +1499,8 @@ ExpandRowReference(ParseState *pstate, Node *expr,
14991499
* drill down to find the ultimate defining expression and attempt to infer
15001500
* the tupdesc from it. We ereport if we can't determine the tupdesc.
15011501
*
1502-
* levelsup is an extra offset to interpret the Var's varlevelsup correctly.
1502+
* levelsup is an extra offset to interpret the Var's varlevelsup correctly
1503+
* when recursing. Outside callers should pass zero.
15031504
*/
15041505
TupleDesc
15051506
expandRecordVariable(ParseState*pstate,Var*var,intlevelsup)
@@ -1587,10 +1588,17 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
15871588
/*
15881589
* Recurse into the sub-select to see what its Var refers
15891590
* to. We have to build an additional level of ParseState
1590-
* to keep in step with varlevelsup in the subselect.
1591+
* to keep in step with varlevelsup in the subselect;
1592+
* furthermore, the subquery RTE might be from an outer
1593+
* query level, in which case the ParseState for the
1594+
* subselect must have that outer level as parent.
15911595
*/
15921596
ParseStatemypstate= {0};
1597+
Indexlevelsup;
15931598

1599+
/* this loop must work, since GetRTEByRangeTablePosn did */
1600+
for (levelsup=0;levelsup<netlevelsup;levelsup++)
1601+
pstate=pstate->parentParseState;
15941602
mypstate.parentParseState=pstate;
15951603
mypstate.p_rtable=rte->subquery->rtable;
15961604
/* don't bother filling the rest of the fake pstate */
@@ -1641,12 +1649,11 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
16411649
* Recurse into the CTE to see what its Var refers to. We
16421650
* have to build an additional level of ParseState to keep
16431651
* in step with varlevelsup in the CTE; furthermore it
1644-
* could be an outer CTE.
1652+
* could be an outer CTE (compare SUBQUERY case above).
16451653
*/
1646-
ParseStatemypstate;
1654+
ParseStatemypstate= {0};
16471655
Indexlevelsup;
16481656

1649-
MemSet(&mypstate,0,sizeof(mypstate));
16501657
/* this loop must work, since GetCTEForRTE did */
16511658
for (levelsup=0;
16521659
levelsup<rte->ctelevelsup+netlevelsup;

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

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7820,22 +7820,28 @@ get_name_for_var_field(Var *var, int fieldno,
78207820
* Recurse into the sub-select to see what its Var
78217821
* refers to. We have to build an additional level of
78227822
* namespace to keep in step with varlevelsup in the
7823-
* subselect.
7823+
* subselect; furthermore, the subquery RTE might be
7824+
* from an outer query level, in which case the
7825+
* namespace for the subselect must have that outer
7826+
* level as parent namespace.
78247827
*/
7828+
List*save_nslist=context->namespaces;
7829+
List*parent_namespaces;
78257830
deparse_namespacemydpns;
78267831
constchar*result;
78277832

7833+
parent_namespaces=list_copy_tail(context->namespaces,
7834+
netlevelsup);
7835+
78287836
set_deparse_for_query(&mydpns,rte->subquery,
7829-
context->namespaces);
7837+
parent_namespaces);
78307838

7831-
context->namespaces=lcons(&mydpns,
7832-
context->namespaces);
7839+
context->namespaces=lcons(&mydpns,parent_namespaces);
78337840

78347841
result=get_name_for_var_field((Var*)expr,fieldno,
78357842
0,context);
78367843

7837-
context->namespaces=
7838-
list_delete_first(context->namespaces);
7844+
context->namespaces=save_nslist;
78397845

78407846
returnresult;
78417847
}
@@ -7927,29 +7933,30 @@ get_name_for_var_field(Var *var, int fieldno,
79277933
attnum);
79287934

79297935
if (ste==NULL||ste->resjunk)
7930-
elog(ERROR,"subquery %s does not have attribute %d",
7936+
elog(ERROR,"CTE %s does not have attribute %d",
79317937
rte->eref->aliasname,attnum);
79327938
expr= (Node*)ste->expr;
79337939
if (IsA(expr,Var))
79347940
{
79357941
/*
79367942
* Recurse into the CTE to see what its Var refers to.
79377943
* We have to build an additional level of namespace
7938-
* to keep in step with varlevelsup in the CTE.
7939-
*Furthermore it could be an outer CTE, so we may
7940-
*have to delete some levels of namespace.
7944+
* to keep in step with varlevelsup in the CTE;
7945+
*furthermore it could be an outer CTE (compare
7946+
*SUBQUERY case above).
79417947
*/
79427948
List*save_nslist=context->namespaces;
7943-
List*new_nslist;
7949+
List*parent_namespaces;
79447950
deparse_namespacemydpns;
79457951
constchar*result;
79467952

7953+
parent_namespaces=list_copy_tail(context->namespaces,
7954+
ctelevelsup);
7955+
79477956
set_deparse_for_query(&mydpns,ctequery,
7948-
context->namespaces);
7957+
parent_namespaces);
79497958

7950-
new_nslist=list_copy_tail(context->namespaces,
7951-
ctelevelsup);
7952-
context->namespaces=lcons(&mydpns,new_nslist);
7959+
context->namespaces=lcons(&mydpns,parent_namespaces);
79537960

79547961
result=get_name_for_var_field((Var*)expr,fieldno,
79557962
0,context);

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

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,66 @@ select r, r is null as isnull, r is not null as isnotnull from r;
12401240
(,) | t | f
12411241
(6 rows)
12421242

1243+
--
1244+
-- Check parsing of indirect references to composite values (bug #18077)
1245+
--
1246+
explain (verbose, costs off)
1247+
with cte(c) as materialized (select row(1, 2)),
1248+
cte2(c) as (select * from cte)
1249+
select * from cte2 as t
1250+
where (select * from (select c as c1) s
1251+
where (select (c1).f1 > 0)) is not null;
1252+
QUERY PLAN
1253+
--------------------------------------------
1254+
CTE Scan on cte
1255+
Output: cte.c
1256+
Filter: ((SubPlan 3) IS NOT NULL)
1257+
CTE cte
1258+
-> Result
1259+
Output: '(1,2)'::record
1260+
SubPlan 3
1261+
-> Result
1262+
Output: cte.c
1263+
One-Time Filter: $2
1264+
InitPlan 2 (returns $2)
1265+
-> Result
1266+
Output: ((cte.c).f1 > 0)
1267+
(13 rows)
1268+
1269+
with cte(c) as materialized (select row(1, 2)),
1270+
cte2(c) as (select * from cte)
1271+
select * from cte2 as t
1272+
where (select * from (select c as c1) s
1273+
where (select (c1).f1 > 0)) is not null;
1274+
c
1275+
-------
1276+
(1,2)
1277+
(1 row)
1278+
1279+
-- Also check deparsing of such cases
1280+
create view composite_v as
1281+
with cte(c) as materialized (select row(1, 2)),
1282+
cte2(c) as (select * from cte)
1283+
select 1 as one from cte2 as t
1284+
where (select * from (select c as c1) s
1285+
where (select (c1).f1 > 0)) is not null;
1286+
select pg_get_viewdef('composite_v', true);
1287+
pg_get_viewdef
1288+
--------------------------------------------------------
1289+
WITH cte(c) AS MATERIALIZED ( +
1290+
SELECT ROW(1, 2) AS "row" +
1291+
), cte2(c) AS ( +
1292+
SELECT cte.c +
1293+
FROM cte +
1294+
) +
1295+
SELECT 1 AS one +
1296+
FROM cte2 t +
1297+
WHERE (( SELECT s.c1 +
1298+
FROM ( SELECT t.c AS c1) s +
1299+
WHERE ( SELECT (s.c1).f1 > 0))) IS NOT NULL;
1300+
(1 row)
1301+
1302+
drop view composite_v;
12431303
--
12441304
-- Tests for component access / FieldSelect
12451305
--

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,31 @@ with r(a,b) as materialized
494494
(null,row(1,2)), (null,row(null,null)), (null,null) )
495495
select r, r isnullas isnull, ris not nullas isnotnullfrom r;
496496

497+
--
498+
-- Check parsing of indirect references to composite values (bug #18077)
499+
--
500+
explain (verbose, costs off)
501+
with cte(c)as materialized (select row(1,2)),
502+
cte2(c)as (select*from cte)
503+
select*from cte2as t
504+
where (select*from (select cas c1) s
505+
where (select (c1).f1>0))is not null;
506+
507+
with cte(c)as materialized (select row(1,2)),
508+
cte2(c)as (select*from cte)
509+
select*from cte2as t
510+
where (select*from (select cas c1) s
511+
where (select (c1).f1>0))is not null;
512+
513+
-- Also check deparsing of such cases
514+
createviewcomposite_vas
515+
with cte(c)as materialized (select row(1,2)),
516+
cte2(c)as (select*from cte)
517+
select1as onefrom cte2as t
518+
where (select*from (select cas c1) s
519+
where (select (c1).f1>0))is not null;
520+
select pg_get_viewdef('composite_v', true);
521+
dropview composite_v;
497522

498523
--
499524
-- Tests for component access / FieldSelect

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp