* 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);