diff options
Diffstat (limited to 'src/backend/executor/nodeProjectSet.c')
-rw-r--r-- | src/backend/executor/nodeProjectSet.c | 61 |
1 files changed, 42 insertions, 19 deletions
diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c index eae0f1dad93..01048cc8268 100644 --- a/src/backend/executor/nodeProjectSet.c +++ b/src/backend/executor/nodeProjectSet.c @@ -24,6 +24,7 @@ #include "executor/executor.h" #include "executor/nodeProjectSet.h" +#include "nodes/nodeFuncs.h" #include "utils/memutils.h" @@ -119,10 +120,9 @@ ExecProjectSRF(ProjectSetState *node, bool continuing) { TupleTableSlot *resultSlot = node->ps.ps_ResultTupleSlot; ExprContext *econtext = node->ps.ps_ExprContext; - bool hassrf PG_USED_FOR_ASSERTS_ONLY = false; + bool hassrf PG_USED_FOR_ASSERTS_ONLY; bool hasresult; int argno; - ListCell *lc; ExecClearTuple(resultSlot); @@ -132,11 +132,10 @@ ExecProjectSRF(ProjectSetState *node, bool continuing) */ node->pending_srf_tuples = false; - hasresult = false; - argno = 0; - foreach(lc, node->ps.targetlist) + hassrf = hasresult = false; + for (argno = 0; argno < node->nelems; argno++) { - GenericExprState *gstate = (GenericExprState *) lfirst(lc); + Node *elem = node->elems[argno]; ExprDoneCond *isdone = &node->elemdone[argno]; Datum *result = &resultSlot->tts_values[argno]; bool *isnull = &resultSlot->tts_isnull[argno]; @@ -151,13 +150,12 @@ ExecProjectSRF(ProjectSetState *node, bool continuing) *isnull = true; hassrf = true; } - else if (IsA(gstate->arg, FuncExprState) && - ((FuncExprState *) gstate->arg)->funcReturnsSet) + else if (IsA(elem, SetExprState)) { /* * Evaluate SRF - possibly continuing previously started output. */ - *result = ExecMakeFunctionResultSet((FuncExprState *) gstate->arg, + *result = ExecMakeFunctionResultSet((SetExprState *) elem, econtext, isnull, isdone); if (*isdone != ExprEndResult) @@ -169,11 +167,9 @@ ExecProjectSRF(ProjectSetState *node, bool continuing) else { /* Non-SRF tlist expression, just evaluate normally. */ - *result = ExecEvalExpr(gstate->arg, econtext, isnull); + *result = ExecEvalExpr((ExprState *) elem, econtext, isnull); *isdone = ExprSingleResult; } - - argno++; } /* ProjectSet should not be used if there's no SRFs */ @@ -204,6 +200,8 @@ ProjectSetState * ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags) { ProjectSetState *state; + ListCell *lc; + int off; /* check for unsupported flags */ Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD))); @@ -229,12 +227,7 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags) */ ExecInitResultTupleSlot(estate, &state->ps); - /* - * initialize child expressions - */ - state->ps.targetlist = (List *) - ExecInitExpr((Expr *) node->plan.targetlist, - (PlanState *) state); + /* We don't support any qual on ProjectSet nodes */ Assert(node->plan.qual == NIL); /* @@ -252,11 +245,41 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags) */ ExecAssignResultTypeFromTL(&state->ps); - /* Create workspace for per-SRF is-done state */ + /* Create workspace for per-tlist-entry expr state & SRF-is-done state */ state->nelems = list_length(node->plan.targetlist); + state->elems = (Node **) + palloc(sizeof(Node *) * state->nelems); state->elemdone = (ExprDoneCond *) palloc(sizeof(ExprDoneCond) * state->nelems); + /* + * Build expressions to evaluate targetlist. We can't use + * ExecBuildProjectionInfo here, since that doesn't deal with SRFs. + * Instead compile each expression separately, using + * ExecInitFunctionResultSet where applicable. + */ + off = 0; + foreach(lc, node->plan.targetlist) + { + TargetEntry *te = (TargetEntry *) lfirst(lc); + Expr *expr = te->expr; + + if ((IsA(expr, FuncExpr) &&((FuncExpr *) expr)->funcretset) || + (IsA(expr, OpExpr) &&((OpExpr *) expr)->opretset)) + { + state->elems[off] = (Node *) + ExecInitFunctionResultSet(expr, state->ps.ps_ExprContext, + &state->ps); + } + else + { + Assert(!expression_returns_set((Node *) expr)); + state->elems[off] = (Node *) ExecInitExpr(expr, &state->ps); + } + + off++; + } + return state; } |