mirror of
https://github.com/postgres/postgres.git
synced 2025-06-30 21:42:05 +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:
@ -2561,6 +2561,12 @@ decompile_column_index_array(Datum column_index_array, Oid relId,
|
||||
* the one specified by the second parameter. This is sufficient for
|
||||
* partial indexes, column default expressions, etc. We also support
|
||||
* Var-free expressions, for which the OID can be InvalidOid.
|
||||
*
|
||||
* We expect this function to work, or throw a reasonably clean error,
|
||||
* for any node tree that can appear in a catalog pg_node_tree column.
|
||||
* Query trees, such as those appearing in pg_rewrite.ev_action, are
|
||||
* not supported. Nor are expressions in more than one relation, which
|
||||
* can appear in places like pg_rewrite.ev_qual.
|
||||
* ----------
|
||||
*/
|
||||
Datum
|
||||
@ -2622,11 +2628,13 @@ static text *
|
||||
pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
|
||||
{
|
||||
Node *node;
|
||||
Node *tst;
|
||||
Relids relids;
|
||||
List *context;
|
||||
char *exprstr;
|
||||
char *str;
|
||||
|
||||
/* Convert input TEXT object to C string */
|
||||
/* Convert input pg_node_tree (really TEXT) object to C string */
|
||||
exprstr = text_to_cstring(expr);
|
||||
|
||||
/* Convert expression to node tree */
|
||||
@ -2634,6 +2642,40 @@ pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
|
||||
|
||||
pfree(exprstr);
|
||||
|
||||
/*
|
||||
* Throw error if the input is a querytree rather than an expression tree.
|
||||
* While we could support queries here, there seems no very good reason
|
||||
* to. In most such catalog columns, we'll see a List of Query nodes, or
|
||||
* even nested Lists, so drill down to a non-List node before checking.
|
||||
*/
|
||||
tst = node;
|
||||
while (tst && IsA(tst, List))
|
||||
tst = linitial((List *) tst);
|
||||
if (tst && IsA(tst, Query))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("input is a query, not an expression")));
|
||||
|
||||
/*
|
||||
* Throw error if the expression contains Vars we won't be able to
|
||||
* deparse.
|
||||
*/
|
||||
relids = pull_varnos(NULL, node);
|
||||
if (OidIsValid(relid))
|
||||
{
|
||||
if (!bms_is_subset(relids, bms_make_singleton(1)))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("expression contains variables of more than one relation")));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!bms_is_empty(relids))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("expression contains variables")));
|
||||
}
|
||||
|
||||
/* Prepare deparse context if needed */
|
||||
if (OidIsValid(relid))
|
||||
context = deparse_context_for(relname, relid);
|
||||
|
Reference in New Issue
Block a user