aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execExprInterp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execExprInterp.c')
-rw-r--r--src/backend/executor/execExprInterp.c86
1 files changed, 57 insertions, 29 deletions
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);
}