summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/nodes/nodeFuncs.c42
-rw-r--r--src/backend/optimizer/util/var.c11
-rw-r--r--src/backend/utils/adt/ruleutils.c44
3 files changed, 94 insertions, 3 deletions
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 7d1a3aff8c..acc17da717 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -2201,6 +2201,26 @@ expression_tree_walker(Node *node,
return true;
}
break;
+ case T_PartitionBoundSpec:
+ {
+ PartitionBoundSpec *pbs = (PartitionBoundSpec *) node;
+
+ if (walker(pbs->listdatums, context))
+ return true;
+ if (walker(pbs->lowerdatums, context))
+ return true;
+ if (walker(pbs->upperdatums, context))
+ return true;
+ }
+ break;
+ case T_PartitionRangeDatum:
+ {
+ PartitionRangeDatum *prd = (PartitionRangeDatum *) node;
+
+ if (walker(prd->value, context))
+ return true;
+ }
+ break;
case T_List:
foreach(temp, (List *) node)
{
@@ -3092,6 +3112,28 @@ expression_tree_mutator(Node *node,
return (Node *) newnode;
}
break;
+ case T_PartitionBoundSpec:
+ {
+ PartitionBoundSpec *pbs = (PartitionBoundSpec *) node;
+ PartitionBoundSpec *newnode;
+
+ FLATCOPY(newnode, pbs, PartitionBoundSpec);
+ MUTATE(newnode->listdatums, pbs->listdatums, List *);
+ MUTATE(newnode->lowerdatums, pbs->lowerdatums, List *);
+ MUTATE(newnode->upperdatums, pbs->upperdatums, List *);
+ return (Node *) newnode;
+ }
+ break;
+ case T_PartitionRangeDatum:
+ {
+ PartitionRangeDatum *prd = (PartitionRangeDatum *) node;
+ PartitionRangeDatum *newnode;
+
+ FLATCOPY(newnode, prd, PartitionRangeDatum);
+ MUTATE(newnode->value, prd->value, Node *);
+ return (Node *) newnode;
+ }
+ break;
case T_List:
{
/*
diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c
index ac048beea0..a0543b7f47 100644
--- a/src/backend/optimizer/util/var.c
+++ b/src/backend/optimizer/util/var.c
@@ -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
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 039f897331..63b8556682 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -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);