* We don't check permissions here as a type's input/output
                 * function are assumed to be executable by everyone.
                 */
-               scratch.opcode = EEOP_IOCOERCE;
+               if (state->escontext == NULL)
+                   scratch.opcode = EEOP_IOCOERCE;
+               else
+                   scratch.opcode = EEOP_IOCOERCE_SAFE;
 
                /* lookup the source type's output function */
                scratch.d.iocoerce.finfo_out = palloc0(sizeof(FmgrInfo));
                fcinfo_in->args[2].value = Int32GetDatum(-1);
                fcinfo_in->args[2].isnull = false;
 
+               fcinfo_in->context = (Node *) state->escontext;
+
                ExprEvalPushStep(state, &scratch);
                break;
            }
    /* we'll allocate workspace only if needed */
    scratch->d.domaincheck.checkvalue = NULL;
    scratch->d.domaincheck.checknull = NULL;
+   scratch->d.domaincheck.escontext = state->escontext;
 
    /*
     * Evaluate argument - it's fine to directly store it into resv/resnull,
 
 #include "executor/nodeSubplan.h"
 #include "funcapi.h"
 #include "miscadmin.h"
+#include "nodes/miscnodes.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/parsetree.h"
 #include "pgstat.h"
        &&CASE_EEOP_CASE_TESTVAL,
        &&CASE_EEOP_MAKE_READONLY,
        &&CASE_EEOP_IOCOERCE,
+       &&CASE_EEOP_IOCOERCE_SAFE,
        &&CASE_EEOP_DISTINCT,
        &&CASE_EEOP_NOT_DISTINCT,
        &&CASE_EEOP_NULLIF,
             * Evaluate a CoerceViaIO node.  This can be quite a hot path, so
             * inline as much work as possible.  The source value is in our
             * result variable.
+            *
+            * Also look at ExecEvalCoerceViaIOSafe() if you change anything
+            * here.
             */
            char       *str;
 
            EEO_NEXT();
        }
 
+       EEO_CASE(EEOP_IOCOERCE_SAFE)
+       {
+           ExecEvalCoerceViaIOSafe(state, op);
+           EEO_NEXT();
+       }
+
        EEO_CASE(EEOP_DISTINCT)
        {
            /*
             errmsg("no value found for parameter %d", paramId)));
 }
 
+/*
+ * Evaluate a CoerceViaIO node in soft-error mode.
+ *
+ * The source value is in op's result variable.
+ *
+ * Note: This implements EEOP_IOCOERCE_SAFE. If you change anything here,
+ * also look at the inline code for EEOP_IOCOERCE.
+ */
+void
+ExecEvalCoerceViaIOSafe(ExprState *state, ExprEvalStep *op)
+{
+   char       *str;
+
+   /* call output function (similar to OutputFunctionCall) */
+   if (*op->resnull)
+   {
+       /* output functions are not called on nulls */
+       str = NULL;
+   }
+   else
+   {
+       FunctionCallInfo fcinfo_out;
+
+       fcinfo_out = op->d.iocoerce.fcinfo_data_out;
+       fcinfo_out->args[0].value = *op->resvalue;
+       fcinfo_out->args[0].isnull = false;
+
+       fcinfo_out->isnull = false;
+       str = DatumGetCString(FunctionCallInvoke(fcinfo_out));
+
+       /* OutputFunctionCall assumes result isn't null */
+       Assert(!fcinfo_out->isnull);
+   }
+
+   /* call input function (similar to InputFunctionCallSafe) */
+   if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)
+   {
+       FunctionCallInfo fcinfo_in;
+
+       fcinfo_in = op->d.iocoerce.fcinfo_data_in;
+       fcinfo_in->args[0].value = PointerGetDatum(str);
+       fcinfo_in->args[0].isnull = *op->resnull;
+       /* second and third arguments are already set up */
+
+       /* ErrorSaveContext must be present. */
+       Assert(IsA(fcinfo_in->context, ErrorSaveContext));
+
+       fcinfo_in->isnull = false;
+       *op->resvalue = FunctionCallInvoke(fcinfo_in);
+
+       if (SOFT_ERROR_OCCURRED(fcinfo_in->context))
+       {
+           *op->resnull = true;
+           *op->resvalue = (Datum) 0;
+           return;
+       }
+
+       /* Should get null result if and only if str is NULL */
+       if (str == NULL)
+           Assert(*op->resnull);
+       else
+           Assert(!*op->resnull);
+   }
+}
+
 /*
  * Evaluate a SQLValueFunction expression.
  */
 ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op)
 {
    if (*op->resnull)
-       ereport(ERROR,
+       errsave((Node *) op->d.domaincheck.escontext,
                (errcode(ERRCODE_NOT_NULL_VIOLATION),
                 errmsg("domain %s does not allow null values",
                        format_type_be(op->d.domaincheck.resulttype)),
 {
    if (!*op->d.domaincheck.checknull &&
        !DatumGetBool(*op->d.domaincheck.checkvalue))
-       ereport(ERROR,
+       errsave((Node *) op->d.domaincheck.escontext,
                (errcode(ERRCODE_CHECK_VIOLATION),
                 errmsg("value for domain %s violates check constraint \"%s\"",
                        format_type_be(op->d.domaincheck.resulttype),
 
 
 #include "executor/nodeAgg.h"
 #include "nodes/execnodes.h"
+#include "nodes/miscnodes.h"
 
 /* forward references to avoid circularity */
 struct ExprEvalStep;
 
    /* evaluate assorted special-purpose expression types */
    EEOP_IOCOERCE,
+   EEOP_IOCOERCE_SAFE,
    EEOP_DISTINCT,
    EEOP_NOT_DISTINCT,
    EEOP_NULLIF,
            bool       *checknull;
            /* OID of domain type */
            Oid         resulttype;
+           ErrorSaveContext *escontext;
        }           domaincheck;
 
        /* for EEOP_CONVERT_ROWTYPE */
                              ExprContext *econtext);
 extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep *op,
                                ExprContext *econtext);
+extern void ExecEvalCoerceViaIOSafe(ExprState *state, ExprEvalStep *op);
 extern void ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op);
 extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op);
 extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op);