diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 743e7d6..ab09691 100644 *** a/src/backend/executor/execQual.c --- b/src/backend/executor/execQual.c *************** ExecEvalCase(CaseExprState *caseExpr, Ex *** 2992,3003 **** if (caseExpr->arg) { bool arg_isNull; ! econtext->caseValue_datum = ExecEvalExpr(caseExpr->arg, ! econtext, ! &arg_isNull, ! NULL); econtext->caseValue_isNull = arg_isNull; } --- 2992,3009 ---- if (caseExpr->arg) { + Datum arg_value; bool arg_isNull; ! 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; } *************** ExecEvalCoerceToDomain(CoerceToDomainSta *** 4127,4137 **** * 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. */ save_datum = econtext->domainValue_datum; save_isNull = econtext->domainValue_isNull; ! econtext->domainValue_datum = result; econtext->domainValue_isNull = *isNull; conResult = ExecEvalExpr(con->check_expr, --- 4133,4150 ---- * 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 = ! MakeExpandedObjectReadOnly(result, *isNull, ! cstate->constraint_ref->tcache->typlen); econtext->domainValue_isNull = *isNull; conResult = ExecEvalExpr(con->check_expr, *************** ExecInitExpr(Expr *node, PlanState *pare *** 4939,4944 **** --- 4952,4959 ---- } cstate->args = outlist; cstate->defresult = ExecInitExpr(caseexpr->defresult, parent); + if (caseexpr->arg) + cstate->argtyplen = get_typlen(exprType((Node *) caseexpr->arg)); state = (ExprState *) cstate; } break; diff --git a/src/backend/utils/adt/domains.c b/src/backend/utils/adt/domains.c index 26bbbb5..1cd80ae 100644 *** a/src/backend/utils/adt/domains.c --- b/src/backend/utils/adt/domains.c *************** *** 35,40 **** --- 35,41 ---- #include "executor/executor.h" #include "lib/stringinfo.h" #include "utils/builtins.h" + #include "utils/expandeddatum.h" #include "utils/lsyscache.h" #include "utils/syscache.h" #include "utils/typcache.h" *************** domain_check_input(Datum value, bool isn *** 166,174 **** * Set up value to be returned by CoerceToDomainValue * nodes. Unlike ExecEvalCoerceToDomain, this econtext * couldn't be shared with anything else, so no need to ! * save and restore fields. */ ! econtext->domainValue_datum = value; econtext->domainValue_isNull = isnull; conResult = ExecEvalExprSwitchContext(con->check_expr, --- 167,180 ---- * Set up value to be returned by CoerceToDomainValue * nodes. Unlike ExecEvalCoerceToDomain, this econtext * couldn't be shared with anything else, so no need to ! * save and restore fields. But we do need to protect the ! * passed-in value against being changed by called ! * functions. (It couldn't be a R/W expanded object for ! * most uses, but that seems possible for domain_check().) */ ! econtext->domainValue_datum = ! MakeExpandedObjectReadOnly(value, isnull, ! my_extra->constraint_ref.tcache->typlen); econtext->domainValue_isNull = isnull; conResult = ExecEvalExprSwitchContext(con->check_expr, diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 5c3b868..cc0821b 100644 *** a/src/include/nodes/execnodes.h --- b/src/include/nodes/execnodes.h *************** typedef struct CaseExprState *** 889,894 **** --- 889,895 ---- ExprState *arg; /* implicit equality comparison argument */ List *args; /* the arguments (list of WHEN clauses) */ ExprState *defresult; /* the default result (ELSE clause) */ + int16 argtyplen; /* if arg is provided, its typlen */ } CaseExprState; /* ---------------- diff --git a/src/include/utils/typcache.h b/src/include/utils/typcache.h index c72efcc..d187650 100644 *** a/src/include/utils/typcache.h --- b/src/include/utils/typcache.h *************** typedef struct DomainConstraintRef *** 131,139 **** { List *constraints; /* list of DomainConstraintState nodes */ MemoryContext refctx; /* context holding DomainConstraintRef */ /* Management data --- treat these fields as private to typcache.c */ - TypeCacheEntry *tcache; /* owning typcache entry */ DomainConstraintCache *dcc; /* current constraints, or NULL if none */ MemoryContextCallback callback; /* used to release refcount when done */ } DomainConstraintRef; --- 131,139 ---- { List *constraints; /* list of DomainConstraintState nodes */ MemoryContext refctx; /* context holding DomainConstraintRef */ + TypeCacheEntry *tcache; /* typcache entry for domain type */ /* Management data --- treat these fields as private to typcache.c */ DomainConstraintCache *dcc; /* current constraints, or NULL if none */ MemoryContextCallback callback; /* used to release refcount when done */ } DomainConstraintRef;