diff options
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/copyfrom.c | 6 | ||||
-rw-r--r-- | src/backend/commands/indexcmds.c | 31 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 50 |
3 files changed, 33 insertions, 54 deletions
diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c index c6dbd972761..182047a4a40 100644 --- a/src/backend/commands/copyfrom.c +++ b/src/backend/commands/copyfrom.c @@ -758,6 +758,9 @@ CopyFrom(CopyFromState cstate) * Can't support multi-inserts if there are any volatile function * expressions in WHERE clause. Similarly to the trigger case above, * such expressions may query the table we're inserting into. + * + * Note: the whereClause was already preprocessed in DoCopy(), so it's + * okay to use contain_volatile_functions() directly. */ insertMethod = CIM_SINGLE; } @@ -1453,7 +1456,8 @@ BeginCopyFrom(ParseState *pstate, * known to be safe for use with the multi-insert * optimization. Hence we use this special case function * checker rather than the standard check for - * contain_volatile_functions(). + * contain_volatile_functions(). Note also that we already + * ran the expression through expression_planner(). */ if (!volatile_defexprs) volatile_defexprs = contain_volatile_functions_not_nextval((Node *) defexpr); diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index d3f7b0904ec..cf7b264cd11 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -1712,33 +1712,6 @@ DefineIndex(Oid relationId, /* - * CheckMutability - * Test whether given expression is mutable - */ -static bool -CheckMutability(Expr *expr) -{ - /* - * First run the expression through the planner. This has a couple of - * important consequences. First, function default arguments will get - * inserted, which may affect volatility (consider "default now()"). - * Second, inline-able functions will get inlined, which may allow us to - * conclude that the function is really less volatile than it's marked. As - * an example, polymorphic functions must be marked with the most volatile - * behavior that they have for any input type, but once we inline the - * function we may be able to conclude that it's not so volatile for the - * particular input type we're dealing with. - * - * We assume here that expression_planner() won't scribble on its input. - */ - expr = expression_planner(expr); - - /* Now we can search for non-immutable functions */ - return contain_mutable_functions((Node *) expr); -} - - -/* * CheckPredicate * Checks that the given partial-index predicate is valid. * @@ -1761,7 +1734,7 @@ CheckPredicate(Expr *predicate) * A predicate using mutable functions is probably wrong, for the same * reasons that we don't allow an index expression to use one. */ - if (CheckMutability(predicate)) + if (contain_mutable_functions_after_planning(predicate)) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("functions in index predicate must be marked IMMUTABLE"))); @@ -1904,7 +1877,7 @@ ComputeIndexAttrs(IndexInfo *indexInfo, * same data every time, it's not clear what the index entries * mean at all. */ - if (CheckMutability((Expr *) expr)) + if (contain_mutable_functions_after_planning((Expr *) expr)) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("functions in index expression must be marked IMMUTABLE"))); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 97f9a222c82..962bde5d38a 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -17407,30 +17407,6 @@ ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNu *partexprs = lappend(*partexprs, expr); /* - * Try to simplify the expression before checking for - * mutability. The main practical value of doing it in this - * order is that an inline-able SQL-language function will be - * accepted if its expansion is immutable, whether or not the - * function itself is marked immutable. - * - * Note that expression_planner does not change the passed in - * expression destructively and we have already saved the - * expression to be stored into the catalog above. - */ - expr = (Node *) expression_planner((Expr *) expr); - - /* - * Partition expression cannot contain mutable functions, - * because a given row must always map to the same partition - * as long as there is no change in the partition boundary - * structure. - */ - if (contain_mutable_functions(expr)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("functions in partition key expression must be marked IMMUTABLE"))); - - /* * transformPartitionSpec() should have already rejected * subqueries, aggregates, window functions, and SRFs, based * on the EXPR_KIND_ for partition expressions. @@ -17472,6 +17448,32 @@ ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNu } /* + * Preprocess the expression before checking for mutability. + * This is essential for the reasons described in + * contain_mutable_functions_after_planning. However, we call + * expression_planner for ourselves rather than using that + * function, because if constant-folding reduces the + * expression to a constant, we'd like to know that so we can + * complain below. + * + * Like contain_mutable_functions_after_planning, assume that + * expression_planner won't scribble on its input, so this + * won't affect the partexprs entry we saved above. + */ + expr = (Node *) expression_planner((Expr *) expr); + + /* + * Partition expressions cannot contain mutable functions, + * because a given row must always map to the same partition + * as long as there is no change in the partition boundary + * structure. + */ + if (contain_mutable_functions(expr)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("functions in partition key expression must be marked IMMUTABLE"))); + + /* * While it is not exactly *wrong* for a partition expression * to be a constant, it seems better to reject such keys. */ |