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

Commitc5b7f79

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 parent59bc0df commitc5b7f79

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
@@ -1475,7 +1475,8 @@ ExpandRowReference(ParseState *pstate, Node *expr,
14751475
* drill down to find the ultimate defining expression and attempt to infer
14761476
* the tupdesc from it. We ereport if we can't determine the tupdesc.
14771477
*
1478-
* levelsup is an extra offset to interpret the Var's varlevelsup correctly.
1478+
* levelsup is an extra offset to interpret the Var's varlevelsup correctly
1479+
* when recursing. Outside callers should pass zero.
14791480
*/
14801481
TupleDesc
14811482
expandRecordVariable(ParseState*pstate,Var*var,intlevelsup)
@@ -1563,11 +1564,17 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
15631564
/*
15641565
* Recurse into the sub-select to see what its Var refers
15651566
* to. We have to build an additional level of ParseState
1566-
* to keep in step with varlevelsup in the subselect.
1567+
* to keep in step with varlevelsup in the subselect;
1568+
* furthermore, the subquery RTE might be from an outer
1569+
* query level, in which case the ParseState for the
1570+
* subselect must have that outer level as parent.
15671571
*/
1568-
ParseStatemypstate;
1572+
ParseStatemypstate= {0};
1573+
Indexlevelsup;
15691574

1570-
MemSet(&mypstate,0,sizeof(mypstate));
1575+
/* this loop must work, since GetRTEByRangeTablePosn did */
1576+
for (levelsup=0;levelsup<netlevelsup;levelsup++)
1577+
pstate=pstate->parentParseState;
15711578
mypstate.parentParseState=pstate;
15721579
mypstate.p_rtable=rte->subquery->rtable;
15731580
/* don't bother filling the rest of the fake pstate */
@@ -1618,12 +1625,11 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
16181625
* Recurse into the CTE to see what its Var refers to. We
16191626
* have to build an additional level of ParseState to keep
16201627
* in step with varlevelsup in the CTE; furthermore it
1621-
* could be an outer CTE.
1628+
* could be an outer CTE (compare SUBQUERY case above).
16221629
*/
1623-
ParseStatemypstate;
1630+
ParseStatemypstate= {0};
16241631
Indexlevelsup;
16251632

1626-
MemSet(&mypstate,0,sizeof(mypstate));
16271633
/* this loop must work, since GetCTEForRTE did */
16281634
for (levelsup=0;
16291635
levelsup<rte->ctelevelsup+netlevelsup;

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

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7249,22 +7249,28 @@ get_name_for_var_field(Var *var, int fieldno,
72497249
* Recurse into the sub-select to see what its Var
72507250
* refers to. We have to build an additional level of
72517251
* namespace to keep in step with varlevelsup in the
7252-
* subselect.
7252+
* subselect; furthermore, the subquery RTE might be
7253+
* from an outer query level, in which case the
7254+
* namespace for the subselect must have that outer
7255+
* level as parent namespace.
72537256
*/
7257+
List*save_nslist=context->namespaces;
7258+
List*parent_namespaces;
72547259
deparse_namespacemydpns;
72557260
constchar*result;
72567261

7262+
parent_namespaces=list_copy_tail(context->namespaces,
7263+
netlevelsup);
7264+
72577265
set_deparse_for_query(&mydpns,rte->subquery,
7258-
context->namespaces);
7266+
parent_namespaces);
72597267

7260-
context->namespaces=lcons(&mydpns,
7261-
context->namespaces);
7268+
context->namespaces=lcons(&mydpns,parent_namespaces);
72627269

72637270
result=get_name_for_var_field((Var*)expr,fieldno,
72647271
0,context);
72657272

7266-
context->namespaces=
7267-
list_delete_first(context->namespaces);
7273+
context->namespaces=save_nslist;
72687274

72697275
returnresult;
72707276
}
@@ -7356,29 +7362,30 @@ get_name_for_var_field(Var *var, int fieldno,
73567362
attnum);
73577363

73587364
if (ste==NULL||ste->resjunk)
7359-
elog(ERROR,"subquery %s does not have attribute %d",
7365+
elog(ERROR,"CTE %s does not have attribute %d",
73607366
rte->eref->aliasname,attnum);
73617367
expr= (Node*)ste->expr;
73627368
if (IsA(expr,Var))
73637369
{
73647370
/*
73657371
* Recurse into the CTE to see what its Var refers to.
73667372
* We have to build an additional level of namespace
7367-
* to keep in step with varlevelsup in the CTE.
7368-
*Furthermore it could be an outer CTE, so we may
7369-
*have to delete some levels of namespace.
7373+
* to keep in step with varlevelsup in the CTE;
7374+
*furthermore it could be an outer CTE (compare
7375+
*SUBQUERY case above).
73707376
*/
73717377
List*save_nslist=context->namespaces;
7372-
List*new_nslist;
7378+
List*parent_namespaces;
73737379
deparse_namespacemydpns;
73747380
constchar*result;
73757381

7382+
parent_namespaces=list_copy_tail(context->namespaces,
7383+
ctelevelsup);
7384+
73767385
set_deparse_for_query(&mydpns,ctequery,
7377-
context->namespaces);
7386+
parent_namespaces);
73787387

7379-
new_nslist=list_copy_tail(context->namespaces,
7380-
ctelevelsup);
7381-
context->namespaces=lcons(&mydpns,new_nslist);
7388+
context->namespaces=lcons(&mydpns,parent_namespaces);
73827389

73837390
result=get_name_for_var_field((Var*)expr,fieldno,
73847391
0,context);

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

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

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

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

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

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

487512
--
488513
-- Tests for component access / FieldSelect

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp