aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execExpr.c58
-rw-r--r--src/backend/executor/execExprInterp.c86
2 files changed, 90 insertions, 54 deletions
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index be9d23bc323..e0839616e19 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -1225,6 +1225,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
{
ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
Oid resultelemtype;
+ ExprState *elemstate;
/* evaluate argument into step's result area */
ExecInitExprRec(acoerce->arg, parent, state, resv, resnull);
@@ -1234,42 +1235,49 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("target type is not an array")));
- /* Arrays over domains aren't supported yet */
- Assert(getBaseType(resultelemtype) == resultelemtype);
- scratch.opcode = EEOP_ARRAYCOERCE;
- scratch.d.arraycoerce.coerceexpr = acoerce;
- scratch.d.arraycoerce.resultelemtype = resultelemtype;
+ /*
+ * Construct a sub-expression for the per-element expression;
+ * but don't ready it until after we check it for triviality.
+ * We assume it hasn't any Var references, but does have a
+ * CaseTestExpr representing the source array element values.
+ */
+ elemstate = makeNode(ExprState);
+ elemstate->expr = acoerce->elemexpr;
+ elemstate->innermost_caseval = (Datum *) palloc(sizeof(Datum));
+ elemstate->innermost_casenull = (bool *) palloc(sizeof(bool));
- if (OidIsValid(acoerce->elemfuncid))
- {
- AclResult aclresult;
+ ExecInitExprRec(acoerce->elemexpr, parent, elemstate,
+ &elemstate->resvalue, &elemstate->resnull);
- /* Check permission to call function */
- aclresult = pg_proc_aclcheck(acoerce->elemfuncid,
- GetUserId(),
- ACL_EXECUTE);
- if (aclresult != ACLCHECK_OK)
- aclcheck_error(aclresult, ACL_KIND_PROC,
- get_func_name(acoerce->elemfuncid));
- InvokeFunctionExecuteHook(acoerce->elemfuncid);
+ if (elemstate->steps_len == 1 &&
+ elemstate->steps[0].opcode == EEOP_CASE_TESTVAL)
+ {
+ /* Trivial, so we need no per-element work at runtime */
+ elemstate = NULL;
+ }
+ else
+ {
+ /* Not trivial, so append a DONE step */
+ scratch.opcode = EEOP_DONE;
+ ExprEvalPushStep(elemstate, &scratch);
+ /* and ready the subexpression */
+ ExecReadyExpr(elemstate);
+ }
- /* Set up the primary fmgr lookup information */
- scratch.d.arraycoerce.elemfunc =
- (FmgrInfo *) palloc0(sizeof(FmgrInfo));
- fmgr_info(acoerce->elemfuncid,
- scratch.d.arraycoerce.elemfunc);
- fmgr_info_set_expr((Node *) acoerce,
- scratch.d.arraycoerce.elemfunc);
+ scratch.opcode = EEOP_ARRAYCOERCE;
+ scratch.d.arraycoerce.elemexprstate = elemstate;
+ scratch.d.arraycoerce.resultelemtype = resultelemtype;
+ if (elemstate)
+ {
/* Set up workspace for array_map */
scratch.d.arraycoerce.amstate =
(ArrayMapState *) palloc0(sizeof(ArrayMapState));
}
else
{
- /* Don't need workspace if there's no conversion func */
- scratch.d.arraycoerce.elemfunc = NULL;
+ /* Don't need workspace if there's no subexpression */
scratch.d.arraycoerce.amstate = NULL;
}
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 39d50f98a9d..c5e97ef9e2d 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -34,10 +34,8 @@
*
* For very simple instructions the overhead of the full interpreter
* "startup", as minimal as it is, is noticeable. Therefore
- * ExecReadyInterpretedExpr will choose to implement simple scalar Var
- * and Const expressions using special fast-path routines (ExecJust*).
- * Benchmarking shows anything more complex than those may as well use the
- * "full interpreter".
+ * ExecReadyInterpretedExpr will choose to implement certain simple
+ * opcode patterns using special fast-path routines (ExecJust*).
*
* Complex or uncommon instructions are not implemented in-line in
* ExecInterpExpr(), rather we call out to a helper function appearing later
@@ -149,6 +147,7 @@ static Datum ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull
static Datum ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
static Datum ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
static Datum ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull);
+static Datum ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull);
/*
@@ -184,10 +183,8 @@ ExecReadyInterpretedExpr(ExprState *state)
/*
* Select fast-path evalfuncs for very simple expressions. "Starting up"
- * the full interpreter is a measurable overhead for these. Plain Vars
- * and Const seem to be the only ones where the intrinsic cost is small
- * enough that the overhead of ExecInterpExpr matters. For more complex
- * expressions it's cheaper to use ExecInterpExpr always.
+ * the full interpreter is a measurable overhead for these, and these
+ * patterns occur often enough to be worth optimizing.
*/
if (state->steps_len == 3)
{
@@ -230,6 +227,13 @@ ExecReadyInterpretedExpr(ExprState *state)
state->evalfunc = ExecJustAssignScanVar;
return;
}
+ else if (step0 == EEOP_CASE_TESTVAL &&
+ step1 == EEOP_FUNCEXPR_STRICT &&
+ state->steps[0].d.casetest.value)
+ {
+ state->evalfunc = ExecJustApplyFuncToCase;
+ return;
+ }
}
else if (state->steps_len == 2 &&
state->steps[0].opcode == EEOP_CONST)
@@ -1275,7 +1279,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_CASE(EEOP_ARRAYCOERCE)
{
/* too complex for an inline implementation */
- ExecEvalArrayCoerce(state, op);
+ ExecEvalArrayCoerce(state, op, econtext);
EEO_NEXT();
}
@@ -1811,6 +1815,43 @@ ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
return 0;
}
+/* Evaluate CASE_TESTVAL and apply a strict function to it */
+static Datum
+ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull)
+{
+ ExprEvalStep *op = &state->steps[0];
+ FunctionCallInfo fcinfo;
+ bool *argnull;
+ int argno;
+ Datum d;
+
+ /*
+ * XXX with some redesign of the CaseTestExpr mechanism, maybe we could
+ * get rid of this data shuffling?
+ */
+ *op->resvalue = *op->d.casetest.value;
+ *op->resnull = *op->d.casetest.isnull;
+
+ op++;
+
+ fcinfo = op->d.func.fcinfo_data;
+ argnull = fcinfo->argnull;
+
+ /* strict function, so check for NULL args */
+ for (argno = 0; argno < op->d.func.nargs; argno++)
+ {
+ if (argnull[argno])
+ {
+ *isnull = true;
+ return (Datum) 0;
+ }
+ }
+ fcinfo->isnull = false;
+ d = op->d.func.fn_addr(fcinfo);
+ *isnull = fcinfo->isnull;
+ return d;
+}
+
/*
* Do one-time initialization of interpretation machinery.
@@ -2345,11 +2386,9 @@ ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op)
* Source array is in step's result variable.
*/
void
-ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op)
+ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
{
- ArrayCoerceExpr *acoerce = op->d.arraycoerce.coerceexpr;
Datum arraydatum;
- FunctionCallInfoData locfcinfo;
/* NULL array -> NULL result */
if (*op->resnull)
@@ -2361,7 +2400,7 @@ ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op)
* If it's binary-compatible, modify the element type in the array header,
* but otherwise leave the array as we received it.
*/
- if (!OidIsValid(acoerce->elemfuncid))
+ if (op->d.arraycoerce.elemexprstate == NULL)
{
/* Detoast input array if necessary, and copy in any case */
ArrayType *array = DatumGetArrayTypePCopy(arraydatum);
@@ -2372,23 +2411,12 @@ ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op)
}
/*
- * Use array_map to apply the function to each array element.
- *
- * We pass on the desttypmod and isExplicit flags whether or not the
- * function wants them.
- *
- * Note: coercion functions are assumed to not use collation.
+ * Use array_map to apply the sub-expression to each array element.
*/
- InitFunctionCallInfoData(locfcinfo, op->d.arraycoerce.elemfunc, 3,
- InvalidOid, NULL, NULL);
- locfcinfo.arg[0] = arraydatum;
- locfcinfo.arg[1] = Int32GetDatum(acoerce->resulttypmod);
- locfcinfo.arg[2] = BoolGetDatum(acoerce->isExplicit);
- locfcinfo.argnull[0] = false;
- locfcinfo.argnull[1] = false;
- locfcinfo.argnull[2] = false;
-
- *op->resvalue = array_map(&locfcinfo, op->d.arraycoerce.resultelemtype,
+ *op->resvalue = array_map(arraydatum,
+ op->d.arraycoerce.elemexprstate,
+ econtext,
+ op->d.arraycoerce.resultelemtype,
op->d.arraycoerce.amstate);
}