diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 2c62b0c9c8..629dd23cf5 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -125,7 +125,17 @@ static void ExecBuildAggTransCall(ExprState *state, AggState *aggstate,
  * although ExecQual and ExecCheck will accept one (and treat it as "true").
  */
 ExprState *
-ExecInitExpr(Expr *node, PlanState *parent)
+ExecInitExpr(Expr* node, PlanState* parent)
+{
+	return ExecInitExprWithErrorContext(node, parent, NULL);
+}
+
+/*
+ * As ExecInitExpr but attempt to save errors into 'err_context' when
+ * supported by the functions being called. XXX write something better here.
+ */
+ExprState *
+ExecInitExprWithErrorContext(Expr *node, PlanState *parent, fmNodePtr *err_context)
 {
 	ExprState  *state;
 	ExprEvalStep scratch = {0};
@@ -139,6 +149,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
 	state->expr = node;
 	state->parent = parent;
 	state->ext_params = NULL;
+	state->err_context = err_context;
 
 	/* Insert setup steps as needed */
 	ExecCreateExprSetupSteps(state, (Node *) node);
@@ -2618,7 +2629,7 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
 
 	/* Initialize function call parameter structure too */
 	InitFunctionCallInfoData(*fcinfo, flinfo,
-							 nargs, inputcollid, NULL, NULL);
+							 nargs, inputcollid, (fmNodePtr) state->err_context, NULL);
 
 	/* Keep extra copies of this info to save an indirection at runtime */
 	scratch->d.func.fn_addr = flinfo->fn_addr;
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index da258968b8..33e96aa6f5 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -31,6 +31,7 @@
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "nodes/miscnodes.h"
 #include "nodes/multibitmapset.h"
 #include "nodes/nodeFuncs.h"
 #include "nodes/subscripting.h"
@@ -2348,7 +2349,7 @@ estimate_expression_value(PlannerInfo *root, Node *node)
 	((Node *) evaluate_expr((Expr *) (node), \
 							exprType((Node *) (node)), \
 							exprTypmod((Node *) (node)), \
-							exprCollation((Node *) (node))))
+							exprCollation((Node *) (node)), false))
 
 /*
  * Recursive guts of eval_const_expressions/estimate_expression_value
@@ -3251,7 +3252,8 @@ eval_const_expressions_mutator(Node *node,
 					return (Node *) evaluate_expr((Expr *) svf,
 												  svf->type,
 												  svf->typmod,
-												  InvalidOid);
+												  InvalidOid,
+												  false);
 				else
 					return copyObject((Node *) svf);
 			}
@@ -4407,7 +4409,7 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
 	newexpr->location = -1;
 
 	return evaluate_expr((Expr *) newexpr, result_type, result_typmod,
-						 result_collid);
+						 result_collid, true);
 }
 
 /*
@@ -4861,11 +4863,16 @@ sql_inline_error_callback(void *arg)
  *
  * We use the executor's routine ExecEvalExpr() to avoid duplication of
  * code and ensure we get the same result as the executor would get.
+ *
+ * 'null_on_error' may be passed as true to have the expression evalulation
+ * code attempt to supress ERRORs and save them.  This of course requires
+ * functions properly errsave/ereturn rather than elog/ereport.
  */
 Expr *
 evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod,
-			  Oid result_collation)
+			  Oid result_collation, bool null_on_error)
 {
+	ErrorSaveContext escontext = {T_ErrorSaveContext};
 	EState	   *estate;
 	ExprState  *exprstate;
 	MemoryContext oldcontext;
@@ -4889,7 +4896,12 @@ evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod,
 	 * Prepare expr for execution.  (Note: we can't use ExecPrepareExpr
 	 * because it'd result in recursively invoking eval_const_expressions.)
 	 */
-	exprstate = ExecInitExpr(expr, NULL);
+	if (null_on_error)
+		exprstate = ExecInitExprWithErrorContext(expr,
+												 NULL,
+												 (fmNodePtr *) &escontext);
+	else
+		exprstate = ExecInitExpr(expr, NULL);
 
 	/*
 	 * And evaluate it.
@@ -4917,7 +4929,7 @@ evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod,
 	 * data.  (makeConst would handle detoasting anyway, but it's worth a few
 	 * extra lines here so that we can do the copy and detoast in one step.)
 	 */
-	if (!const_is_null)
+	if (!escontext.error_occurred && !const_is_null)
 	{
 		if (resultTypLen == -1)
 			const_val = PointerGetDatum(PG_DETOAST_DATUM_COPY(const_val));
@@ -4928,6 +4940,9 @@ evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod,
 	/* Release all the junk we just created */
 	FreeExecutorState(estate);
 
+	if (escontext.error_occurred)
+		return NULL;
+
 	/*
 	 * Make the constant result node.
 	 */
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index cf0d432ab1..efe7c210a2 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -4462,7 +4462,7 @@ transformPartitionBoundValue(ParseState *pstate, Node *val,
 		assign_expr_collations(pstate, value);
 		value = (Node *) expression_planner((Expr *) value);
 		value = (Node *) evaluate_expr((Expr *) value, colType, colTypmod,
-									   partCollation);
+									   partCollation, false);
 		if (!IsA(value, Const))
 			elog(ERROR, "could not evaluate partition bound expression");
 	}
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index aeebe0e0ff..e926d9e62b 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -278,6 +278,8 @@ ExecProcNode(PlanState *node)
  * prototypes from functions in execExpr.c
  */
 extern ExprState *ExecInitExpr(Expr *node, PlanState *parent);
+extern ExprState *ExecInitExprWithErrorContext(Expr *node, PlanState *parent,
+											   fmNodePtr *err_context);
 extern ExprState *ExecInitExprWithParams(Expr *node, ParamListInfo ext_params);
 extern ExprState *ExecInitQual(List *qual, PlanState *parent);
 extern ExprState *ExecInitCheck(List *qual, PlanState *parent);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index cb714f4a19..c008515f17 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -124,6 +124,12 @@ typedef struct ExprState
 	struct PlanState *parent;	/* parent PlanState node, if any */
 	ParamListInfo ext_params;	/* for compiling PARAM_EXTERN nodes */
 
+	/*
+	 * ErrorSaveContext pointer to record any saved ERRORs into or NULL if
+	 * errors are to be raised right away.
+	 */
+	fmNodePtr *err_context;
+
 	Datum	   *innermost_caseval;
 	bool	   *innermost_casenull;
 
diff --git a/src/include/optimizer/optimizer.h b/src/include/optimizer/optimizer.h
index 514746c585..da994760ed 100644
--- a/src/include/optimizer/optimizer.h
+++ b/src/include/optimizer/optimizer.h
@@ -148,7 +148,7 @@ extern void convert_saop_to_hashed_saop(Node *node);
 extern Node *estimate_expression_value(PlannerInfo *root, Node *node);
 
 extern Expr *evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod,
-						   Oid result_collation);
+						   Oid result_collation, bool null_on_error);
 
 extern List *expand_function_arguments(List *args, bool include_out_arguments,
 									   Oid result_type,
