diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2023-09-15 17:01:26 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2023-09-15 17:01:52 -0400 |
commit | e0e492e5a928e9c9eda01eeebadcfc36f9f8e7b7 (patch) | |
tree | 49c817e2514dd2cfc077ce361d70e084cee1725a /src/backend/parser/parse_target.c | |
parent | a396e20ad0da42b9cf64c39a99034523d819f008 (diff) | |
download | postgresql-e0e492e5a928e9c9eda01eeebadcfc36f9f8e7b7.tar.gz postgresql-e0e492e5a928e9c9eda01eeebadcfc36f9f8e7b7.zip |
Track nesting depth correctly when drilling down into RECORD Vars.
expandRecordVariable() failed to adjust the parse nesting structure
correctly when recursing to inspect an outer-level Var. This could
result in assertion failures or core dumps in corner cases.
Likewise, get_name_for_var_field() failed to adjust the deparse
namespace stack correctly when recursing to inspect an outer-level
Var. In this case the likely result was a "bogus varno" error
while deparsing a view.
Per bug #18077 from Jingzhou Fu. Back-patch to all supported
branches.
Richard Guo, with some adjustments by me
Discussion: https://postgr.es/m/18077-b9db97c6e0ab45d8@postgresql.org
Diffstat (limited to 'src/backend/parser/parse_target.c')
-rw-r--r-- | src/backend/parser/parse_target.c | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 57247de363b..3bc62ac3ba5 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -1499,7 +1499,8 @@ ExpandRowReference(ParseState *pstate, Node *expr, * drill down to find the ultimate defining expression and attempt to infer * the tupdesc from it. We ereport if we can't determine the tupdesc. * - * levelsup is an extra offset to interpret the Var's varlevelsup correctly. + * levelsup is an extra offset to interpret the Var's varlevelsup correctly + * when recursing. Outside callers should pass zero. */ TupleDesc expandRecordVariable(ParseState *pstate, Var *var, int levelsup) @@ -1587,10 +1588,17 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup) /* * Recurse into the sub-select to see what its Var refers * to. We have to build an additional level of ParseState - * to keep in step with varlevelsup in the subselect. + * to keep in step with varlevelsup in the subselect; + * furthermore, the subquery RTE might be from an outer + * query level, in which case the ParseState for the + * subselect must have that outer level as parent. */ ParseState mypstate = {0}; + Index levelsup; + /* this loop must work, since GetRTEByRangeTablePosn did */ + for (levelsup = 0; levelsup < netlevelsup; levelsup++) + pstate = pstate->parentParseState; mypstate.parentParseState = pstate; mypstate.p_rtable = rte->subquery->rtable; /* don't bother filling the rest of the fake pstate */ @@ -1641,12 +1649,11 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup) * Recurse into the CTE to see what its Var refers to. We * have to build an additional level of ParseState to keep * in step with varlevelsup in the CTE; furthermore it - * could be an outer CTE. + * could be an outer CTE (compare SUBQUERY case above). */ - ParseState mypstate; + ParseState mypstate = {0}; Index levelsup; - MemSet(&mypstate, 0, sizeof(mypstate)); /* this loop must work, since GetCTEForRTE did */ for (levelsup = 0; levelsup < rte->ctelevelsup + netlevelsup; |