aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/ruleutils.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2023-09-15 17:01:26 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2023-09-15 17:01:52 -0400
commite0e492e5a928e9c9eda01eeebadcfc36f9f8e7b7 (patch)
tree49c817e2514dd2cfc077ce361d70e084cee1725a /src/backend/utils/adt/ruleutils.c
parenta396e20ad0da42b9cf64c39a99034523d819f008 (diff)
downloadpostgresql-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/utils/adt/ruleutils.c')
-rw-r--r--src/backend/utils/adt/ruleutils.c37
1 files changed, 22 insertions, 15 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 97b0ef22ac5..68f301484e3 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -7820,22 +7820,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;
+ parent_namespaces = list_copy_tail(context->namespaces,
+ netlevelsup);
+
set_deparse_for_query(&mydpns, rte->subquery,
- context->namespaces);
+ parent_namespaces);
- context->namespaces = lcons(&mydpns,
- context->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;
}
@@ -7927,7 +7933,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))
@@ -7935,21 +7941,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;
+ parent_namespaces = list_copy_tail(context->namespaces,
+ ctelevelsup);
+
set_deparse_for_query(&mydpns, ctequery,
- context->namespaces);
+ parent_namespaces);
- new_nslist = list_copy_tail(context->namespaces,
- ctelevelsup);
- context->namespaces = lcons(&mydpns, new_nslist);
+ context->namespaces = lcons(&mydpns, parent_namespaces);
result = get_name_for_var_field((Var *) expr, fieldno,
0, context);