aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeProjectSet.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeProjectSet.c')
-rw-r--r--src/backend/executor/nodeProjectSet.c61
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;
}