mirror of
https://github.com/postgres/postgres.git
synced 2025-07-02 09:02:37 +03:00
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
This commit is contained in:
@ -7806,22 +7806,28 @@ get_name_for_var_field(Var *var, int fieldno,
|
||||
* Recurse into the sub-select to see what its Var
|
||||
* refers to. We have to build an additional level of
|
||||
* namespace to keep in step with varlevelsup in the
|
||||
* subselect.
|
||||
* subselect; furthermore, the subquery RTE might be
|
||||
* from an outer query level, in which case the
|
||||
* namespace for the subselect must have that outer
|
||||
* level as parent namespace.
|
||||
*/
|
||||
List *save_nslist = context->namespaces;
|
||||
List *parent_namespaces;
|
||||
deparse_namespace mydpns;
|
||||
const char *result;
|
||||
|
||||
set_deparse_for_query(&mydpns, rte->subquery,
|
||||
context->namespaces);
|
||||
parent_namespaces = list_copy_tail(context->namespaces,
|
||||
netlevelsup);
|
||||
|
||||
context->namespaces = lcons(&mydpns,
|
||||
context->namespaces);
|
||||
set_deparse_for_query(&mydpns, rte->subquery,
|
||||
parent_namespaces);
|
||||
|
||||
context->namespaces = lcons(&mydpns, parent_namespaces);
|
||||
|
||||
result = get_name_for_var_field((Var *) expr, fieldno,
|
||||
0, context);
|
||||
|
||||
context->namespaces =
|
||||
list_delete_first(context->namespaces);
|
||||
context->namespaces = save_nslist;
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -7913,7 +7919,7 @@ get_name_for_var_field(Var *var, int fieldno,
|
||||
attnum);
|
||||
|
||||
if (ste == NULL || ste->resjunk)
|
||||
elog(ERROR, "subquery %s does not have attribute %d",
|
||||
elog(ERROR, "CTE %s does not have attribute %d",
|
||||
rte->eref->aliasname, attnum);
|
||||
expr = (Node *) ste->expr;
|
||||
if (IsA(expr, Var))
|
||||
@ -7921,21 +7927,22 @@ get_name_for_var_field(Var *var, int fieldno,
|
||||
/*
|
||||
* Recurse into the CTE to see what its Var refers to.
|
||||
* We have to build an additional level of namespace
|
||||
* to keep in step with varlevelsup in the CTE.
|
||||
* Furthermore it could be an outer CTE, so we may
|
||||
* have to delete some levels of namespace.
|
||||
* to keep in step with varlevelsup in the CTE;
|
||||
* furthermore it could be an outer CTE (compare
|
||||
* SUBQUERY case above).
|
||||
*/
|
||||
List *save_nslist = context->namespaces;
|
||||
List *new_nslist;
|
||||
List *parent_namespaces;
|
||||
deparse_namespace mydpns;
|
||||
const char *result;
|
||||
|
||||
set_deparse_for_query(&mydpns, ctequery,
|
||||
context->namespaces);
|
||||
parent_namespaces = list_copy_tail(context->namespaces,
|
||||
ctelevelsup);
|
||||
|
||||
new_nslist = list_copy_tail(context->namespaces,
|
||||
ctelevelsup);
|
||||
context->namespaces = lcons(&mydpns, new_nslist);
|
||||
set_deparse_for_query(&mydpns, ctequery,
|
||||
parent_namespaces);
|
||||
|
||||
context->namespaces = lcons(&mydpns, parent_namespaces);
|
||||
|
||||
result = get_name_for_var_field((Var *) expr, fieldno,
|
||||
0, context);
|
||||
|
Reference in New Issue
Block a user