diff options
Diffstat (limited to 'src/backend/executor/execExprInterp.c')
-rw-r--r-- | src/backend/executor/execExprInterp.c | 80 |
1 files changed, 78 insertions, 2 deletions
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 3c17cc6b1e1..3f20f1dd314 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -63,6 +63,7 @@ #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" @@ -452,6 +453,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) &&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, @@ -1150,6 +1152,9 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) * 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; @@ -1205,6 +1210,12 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_NEXT(); } + EEO_CASE(EEOP_IOCOERCE_SAFE) + { + ExecEvalCoerceViaIOSafe(state, op); + EEO_NEXT(); + } + EEO_CASE(EEOP_DISTINCT) { /* @@ -2511,6 +2522,71 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext) } /* + * 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. */ void @@ -3730,7 +3806,7 @@ void 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)), @@ -3745,7 +3821,7 @@ ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op) { 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), |