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

Commitae13f81

Browse files
committed
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 parent1988f87 commitae13f81

File tree

4 files changed

+120
-22
lines changed

4 files changed

+120
-22
lines changed

‎src/backend/parser/parse_target.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,7 +1503,8 @@ ExpandRowReference(ParseState *pstate, Node *expr,
15031503
* drill down to find the ultimate defining expression and attempt to infer
15041504
* the tupdesc from it. We ereport if we can't determine the tupdesc.
15051505
*
1506-
* levelsup is an extra offset to interpret the Var's varlevelsup correctly.
1506+
* levelsup is an extra offset to interpret the Var's varlevelsup correctly
1507+
* when recursing. Outside callers should pass zero.
15071508
*/
15081509
TupleDesc
15091510
expandRecordVariable(ParseState*pstate,Var*var,intlevelsup)
@@ -1591,11 +1592,17 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
15911592
/*
15921593
* Recurse into the sub-select to see what its Var refers
15931594
* to. We have to build an additional level of ParseState
1594-
* to keep in step with varlevelsup in the subselect.
1595+
* to keep in step with varlevelsup in the subselect;
1596+
* furthermore, the subquery RTE might be from an outer
1597+
* query level, in which case the ParseState for the
1598+
* subselect must have that outer level as parent.
15951599
*/
1596-
ParseStatemypstate;
1600+
ParseStatemypstate= {0};
1601+
Indexlevelsup;
15971602

1598-
MemSet(&mypstate,0,sizeof(mypstate));
1603+
/* this loop must work, since GetRTEByRangeTablePosn did */
1604+
for (levelsup=0;levelsup<netlevelsup;levelsup++)
1605+
pstate=pstate->parentParseState;
15991606
mypstate.parentParseState=pstate;
16001607
mypstate.p_rtable=rte->subquery->rtable;
16011608
/* don't bother filling the rest of the fake pstate */
@@ -1646,12 +1653,11 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
16461653
* Recurse into the CTE to see what its Var refers to. We
16471654
* have to build an additional level of ParseState to keep
16481655
* in step with varlevelsup in the CTE; furthermore it
1649-
* could be an outer CTE.
1656+
* could be an outer CTE (compare SUBQUERY case above).
16501657
*/
1651-
ParseStatemypstate;
1658+
ParseStatemypstate= {0};
16521659
Indexlevelsup;
16531660

1654-
MemSet(&mypstate,0,sizeof(mypstate));
16551661
/* this loop must work, since GetCTEForRTE did */
16561662
for (levelsup=0;
16571663
levelsup<rte->ctelevelsup+netlevelsup;

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

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7616,22 +7616,28 @@ get_name_for_var_field(Var *var, int fieldno,
76167616
* Recurse into the sub-select to see what its Var
76177617
* refers to. We have to build an additional level of
76187618
* namespace to keep in step with varlevelsup in the
7619-
* subselect.
7619+
* subselect; furthermore, the subquery RTE might be
7620+
* from an outer query level, in which case the
7621+
* namespace for the subselect must have that outer
7622+
* level as parent namespace.
76207623
*/
7624+
List*save_nslist=context->namespaces;
7625+
List*parent_namespaces;
76217626
deparse_namespacemydpns;
76227627
constchar*result;
76237628

7629+
parent_namespaces=list_copy_tail(context->namespaces,
7630+
netlevelsup);
7631+
76247632
set_deparse_for_query(&mydpns,rte->subquery,
7625-
context->namespaces);
7633+
parent_namespaces);
76267634

7627-
context->namespaces=lcons(&mydpns,
7628-
context->namespaces);
7635+
context->namespaces=lcons(&mydpns,parent_namespaces);
76297636

76307637
result=get_name_for_var_field((Var*)expr,fieldno,
76317638
0,context);
76327639

7633-
context->namespaces=
7634-
list_delete_first(context->namespaces);
7640+
context->namespaces=save_nslist;
76357641

76367642
returnresult;
76377643
}
@@ -7723,29 +7729,30 @@ get_name_for_var_field(Var *var, int fieldno,
77237729
attnum);
77247730

77257731
if (ste==NULL||ste->resjunk)
7726-
elog(ERROR,"subquery %s does not have attribute %d",
7732+
elog(ERROR,"CTE %s does not have attribute %d",
77277733
rte->eref->aliasname,attnum);
77287734
expr= (Node*)ste->expr;
77297735
if (IsA(expr,Var))
77307736
{
77317737
/*
77327738
* Recurse into the CTE to see what its Var refers to.
77337739
* We have to build an additional level of namespace
7734-
* to keep in step with varlevelsup in the CTE.
7735-
*Furthermore it could be an outer CTE, so we may
7736-
*have to delete some levels of namespace.
7740+
* to keep in step with varlevelsup in the CTE;
7741+
*furthermore it could be an outer CTE (compare
7742+
*SUBQUERY case above).
77377743
*/
77387744
List*save_nslist=context->namespaces;
7739-
List*new_nslist;
7745+
List*parent_namespaces;
77407746
deparse_namespacemydpns;
77417747
constchar*result;
77427748

7749+
parent_namespaces=list_copy_tail(context->namespaces,
7750+
ctelevelsup);
7751+
77437752
set_deparse_for_query(&mydpns,ctequery,
7744-
context->namespaces);
7753+
parent_namespaces);
77457754

7746-
new_nslist=list_copy_tail(context->namespaces,
7747-
ctelevelsup);
7748-
context->namespaces=lcons(&mydpns,new_nslist);
7755+
context->namespaces=lcons(&mydpns,parent_namespaces);
77497756

77507757
result=get_name_for_var_field((Var*)expr,fieldno,
77517758
0,context);

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

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

1212+
--
1213+
-- Check parsing of indirect references to composite values (bug #18077)
1214+
--
1215+
explain (verbose, costs off)
1216+
with cte(c) as materialized (select row(1, 2)),
1217+
cte2(c) as (select * from cte)
1218+
select * from cte2 as t
1219+
where (select * from (select c as c1) s
1220+
where (select (c1).f1 > 0)) is not null;
1221+
QUERY PLAN
1222+
--------------------------------------------
1223+
CTE Scan on cte
1224+
Output: cte.c
1225+
Filter: ((SubPlan 3) IS NOT NULL)
1226+
CTE cte
1227+
-> Result
1228+
Output: '(1,2)'::record
1229+
SubPlan 3
1230+
-> Result
1231+
Output: cte.c
1232+
One-Time Filter: $2
1233+
InitPlan 2 (returns $2)
1234+
-> Result
1235+
Output: ((cte.c).f1 > 0)
1236+
(13 rows)
1237+
1238+
with cte(c) as materialized (select row(1, 2)),
1239+
cte2(c) as (select * from cte)
1240+
select * from cte2 as t
1241+
where (select * from (select c as c1) s
1242+
where (select (c1).f1 > 0)) is not null;
1243+
c
1244+
-------
1245+
(1,2)
1246+
(1 row)
1247+
1248+
-- Also check deparsing of such cases
1249+
create view composite_v as
1250+
with cte(c) as materialized (select row(1, 2)),
1251+
cte2(c) as (select * from cte)
1252+
select 1 as one from cte2 as t
1253+
where (select * from (select c as c1) s
1254+
where (select (c1).f1 > 0)) is not null;
1255+
select pg_get_viewdef('composite_v', true);
1256+
pg_get_viewdef
1257+
--------------------------------------------------------
1258+
WITH cte(c) AS MATERIALIZED ( +
1259+
SELECT ROW(1, 2) AS "row" +
1260+
), cte2(c) AS ( +
1261+
SELECT cte.c +
1262+
FROM cte +
1263+
) +
1264+
SELECT 1 AS one +
1265+
FROM cte2 t +
1266+
WHERE (( SELECT s.c1 +
1267+
FROM ( SELECT t.c AS c1) s +
1268+
WHERE ( SELECT (s.c1).f1 > 0))) IS NOT NULL;
1269+
(1 row)
1270+
1271+
drop view composite_v;
12121272
--
12131273
-- Tests for component access / FieldSelect
12141274
--

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

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

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

491516
--
492517
-- Tests for component access / FieldSelect

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp