diff options
Diffstat (limited to 'src/backend/executor/execExpr.c')
-rw-r--r-- | src/backend/executor/execExpr.c | 58 |
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; } |