aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/indexcmds.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2023-11-16 10:05:14 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2023-11-16 10:05:14 -0500
commitf07a3039c72b4a7afbe2b898fd1194575d13c37e (patch)
treeadebc00967b313c690c3a894a259c56d89c20412 /src/backend/commands/indexcmds.c
parent2927b1dca7ae55a7bd4e24a2053afa62d9796404 (diff)
downloadpostgresql-f07a3039c72b4a7afbe2b898fd1194575d13c37e.tar.gz
postgresql-f07a3039c72b4a7afbe2b898fd1194575d13c37e.zip
Ensure we preprocess expressions before checking their volatility.
contain_mutable_functions and contain_volatile_functions give reliable answers only after expression preprocessing (specifically eval_const_expressions). Some places understand this, but some did not get the memo --- which is not entirely their fault, because the problem is documented only in places far away from those functions. Introduce wrapper functions that allow doing the right thing easily, and add commentary in hopes of preventing future mistakes from copy-and-paste of code that's only conditionally safe. Two actual bugs of this ilk are fixed here. We failed to preprocess column GENERATED expressions before checking mutability, so that the code could fail to detect the use of a volatile function default-argument expression, or it could reject a polymorphic function that is actually immutable on the datatype of interest. Likewise, column DEFAULT expressions weren't preprocessed before determining if it's safe to apply the attmissingval mechanism. A false negative would just result in an unnecessary table rewrite, but a false positive could allow the attmissingval mechanism to be used in a case where it should not be, resulting in unexpected initial values in a new column. In passing, re-order the steps in ComputePartitionAttrs so that its checks for invalid column references are done before applying expression_planner, rather than after. The previous coding would not complain if a partition expression contains a disallowed column reference that gets optimized away by constant folding, which seems to me to be a behavior we do not want. Per bug #18097 from Jim Keener. Back-patch to all supported versions. Discussion: https://postgr.es/m/18097-ebb179674f22932f@postgresql.org
Diffstat (limited to 'src/backend/commands/indexcmds.c')
-rw-r--r--src/backend/commands/indexcmds.c31
1 files changed, 2 insertions, 29 deletions
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 02250ae74be..cd23ab3b257 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -1772,33 +1772,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.
*
@@ -1821,7 +1794,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")));
@@ -1964,7 +1937,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")));