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