aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2016-12-22 15:01:27 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2016-12-22 15:01:37 -0500
commitcd1b215692d2cadf499936dba05f1f60bce59344 (patch)
tree3edeb89844bf63d510a7b3337eeb9a16988ab45c /src/backend/executor
parent6ef2eba3f57f17960b7cd4958e18aa79e357de2f (diff)
downloadpostgresql-cd1b215692d2cadf499936dba05f1f60bce59344.tar.gz
postgresql-cd1b215692d2cadf499936dba05f1f60bce59344.zip
Fix handling of expanded objects in CoerceToDomain and CASE execution.
When the input value to a CoerceToDomain expression node is a read-write expanded datum, we should pass a read-only pointer to any domain CHECK expressions and then return the original read-write pointer as the expression result. Previously we were blindly passing the same pointer to all the consumers of the value, making it possible for a function in CHECK to modify or even delete the expanded value. (Since a plpgsql function will absorb a passed-in read-write expanded array as a local variable value, it will in fact delete the value on exit.) A similar hazard of passing the same read-write pointer to multiple consumers exists in domain_check() and in ExecEvalCase, so fix those too. The fix requires adding MakeExpandedObjectReadOnly calls at the appropriate places, which is simple enough except that we need to get the data type's typlen from somewhere. For the domain cases, solve this by redefining DomainConstraintRef.tcache as okay for callers to access; there wasn't any reason for the original convention against that, other than not wanting the API of typcache.c to be any wider than it had to be. For CASE, there's no good solution except to add a syscache lookup during executor start. Per bug #14472 from Marcos Castedo. Back-patch to 9.5 where expanded values were introduced. Discussion: https://postgr.es/m/15225.1482431619@sss.pgh.pa.us
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execQual.c25
1 files changed, 20 insertions, 5 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 743e7d636a0..ab09691fb20 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -2992,12 +2992,18 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
if (caseExpr->arg)
{
+ Datum arg_value;
bool arg_isNull;
- econtext->caseValue_datum = ExecEvalExpr(caseExpr->arg,
- econtext,
- &arg_isNull,
- NULL);
+ arg_value = ExecEvalExpr(caseExpr->arg,
+ econtext,
+ &arg_isNull,
+ NULL);
+ /* Since caseValue_datum may be read multiple times, force to R/O */
+ econtext->caseValue_datum =
+ MakeExpandedObjectReadOnly(arg_value,
+ arg_isNull,
+ caseExpr->argtyplen);
econtext->caseValue_isNull = arg_isNull;
}
@@ -4127,11 +4133,18 @@ ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext,
* nodes. We must save and restore prior setting of
* econtext's domainValue fields, in case this node is
* itself within a check expression for another domain.
+ *
+ * Also, if we are working with a read-write expanded
+ * datum, be sure that what we pass to CHECK expressions
+ * is a read-only pointer; else called functions might
+ * modify or even delete the expanded object.
*/
save_datum = econtext->domainValue_datum;
save_isNull = econtext->domainValue_isNull;
- econtext->domainValue_datum = result;
+ econtext->domainValue_datum =
+ MakeExpandedObjectReadOnly(result, *isNull,
+ cstate->constraint_ref->tcache->typlen);
econtext->domainValue_isNull = *isNull;
conResult = ExecEvalExpr(con->check_expr,
@@ -4939,6 +4952,8 @@ ExecInitExpr(Expr *node, PlanState *parent)
}
cstate->args = outlist;
cstate->defresult = ExecInitExpr(caseexpr->defresult, parent);
+ if (caseexpr->arg)
+ cstate->argtyplen = get_typlen(exprType((Node *) caseexpr->arg));
state = (ExprState *) cstate;
}
break;