1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-27 07:42:10 +03:00

Make pg_get_expr() more bulletproof.

Since this function is defined to accept pg_node_tree values, it could
get applied to any nodetree that can appear in a cataloged pg_node_tree
column.  Some such cases can't be supported --- for example, its API
doesn't allow providing referents for more than one relation --- but
we should try to throw a user-facing error rather than an internal
error when encountering such a case.

In support of this, extend expression_tree_walker/mutator to be sure
they'll work on any such node tree (which basically means adding
support for relpartbound node types).  That allows us to run pull_varnos
and check for the case of multiple relations before we start processing
the tree.  The alternative of changing the low-level error thrown for an
out-of-range varno isn't appealing, because that could mask actual bugs
in other usages of ruleutils.

Per report from Justin Pryzby.  This is basically cosmetic, so no
back-patch.

Discussion: https://postgr.es/m/20211219205422.GT17618@telsasoft.com
This commit is contained in:
Tom Lane
2022-01-09 12:43:09 -05:00
parent 96a6f11c06
commit 6867f963e3
3 changed files with 94 additions and 3 deletions

View File

@@ -88,6 +88,9 @@ static Relids alias_relid_set(Query *query, Relids relids);
* Create a set of all the distinct varnos present in a parsetree.
* Only varnos that reference level-zero rtable entries are considered.
*
* "root" can be passed as NULL if it is not necessary to process
* PlaceHolderVars.
*
* NOTE: this is used on not-yet-planned expressions. It may therefore find
* bare SubLinks, and if so it needs to recurse into them to look for uplevel
* references to the desired rtable level! But when we find a completed
@@ -168,9 +171,13 @@ pull_varnos_walker(Node *node, pull_varnos_context *context)
/*
* If a PlaceHolderVar is not of the target query level, ignore it,
* instead recursing into its expression to see if it contains any
* vars that are of the target level.
* vars that are of the target level. We'll also do that when the
* caller doesn't pass a "root" pointer. (We probably shouldn't see
* PlaceHolderVars at all in such cases, but if we do, this is a
* reasonable behavior.)
*/
if (phv->phlevelsup == context->sublevels_up)
if (phv->phlevelsup == context->sublevels_up &&
context->root != NULL)
{
/*
* Ideally, the PHV's contribution to context->varnos is its