From a26c7e3d71d65381bc60b0d0b30f03cd738fb0e9 Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Mon, 8 Sep 2008 00:22:56 +0000 Subject: [PATCH] Support set-returning functions in the target lists of Agg and Group plan nodes. This is a pretty ugly feature but since we don't yet have a plausible substitute, we'd better support it everywhere. Per gripe from Jeff Davis. --- src/backend/executor/nodeAgg.c | 53 +++++++++++++++++++++++++------- src/backend/executor/nodeGroup.c | 41 ++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 14 deletions(-) diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index fa49862912e..80263d174c2 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -61,7 +61,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.160 2008/08/25 22:42:32 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.161 2008/09/08 00:22:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -805,6 +805,23 @@ ExecAgg(AggState *node) if (node->agg_done) return NULL; + /* + * Check to see if we're still projecting out tuples from a previous agg + * tuple (because there is a function-returning-set in the projection + * expressions). If so, try to project another one. + */ + if (node->ss.ps.ps_TupFromTlist) + { + TupleTableSlot *result; + ExprDoneCond isDone; + + result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone); + if (isDone == ExprMultipleResult) + return result; + /* Done with that source tuple... */ + node->ss.ps.ps_TupFromTlist = false; + } + if (((Agg *) node->ss.ps.plan)->aggstrategy == AGG_HASHED) { if (!node->table_filled) @@ -825,7 +842,6 @@ agg_retrieve_direct(AggState *aggstate) PlanState *outerPlan; ExprContext *econtext; ExprContext *tmpcontext; - ProjectionInfo *projInfo; Datum *aggvalues; bool *aggnulls; AggStatePerAgg peragg; @@ -844,7 +860,6 @@ agg_retrieve_direct(AggState *aggstate) aggnulls = econtext->ecxt_aggnulls; /* tmpcontext is the per-input-tuple expression context */ tmpcontext = aggstate->tmpcontext; - projInfo = aggstate->ss.ps.ps_ProjInfo; peragg = aggstate->peragg; pergroup = aggstate->pergroup; firstSlot = aggstate->ss.ss_ScanTupleSlot; @@ -982,10 +997,19 @@ agg_retrieve_direct(AggState *aggstate) { /* * Form and return a projection tuple using the aggregate results - * and the representative input tuple. Note we do not support - * aggregates returning sets ... + * and the representative input tuple. */ - return ExecProject(projInfo, NULL); + TupleTableSlot *result; + ExprDoneCond isDone; + + result = ExecProject(aggstate->ss.ps.ps_ProjInfo, &isDone); + + if (isDone != ExprEndResult) + { + aggstate->ss.ps.ps_TupFromTlist = + (isDone == ExprMultipleResult); + return result; + } } } @@ -1045,7 +1069,6 @@ static TupleTableSlot * agg_retrieve_hash_table(AggState *aggstate) { ExprContext *econtext; - ProjectionInfo *projInfo; Datum *aggvalues; bool *aggnulls; AggStatePerAgg peragg; @@ -1061,7 +1084,6 @@ agg_retrieve_hash_table(AggState *aggstate) econtext = aggstate->ss.ps.ps_ExprContext; aggvalues = econtext->ecxt_aggvalues; aggnulls = econtext->ecxt_aggnulls; - projInfo = aggstate->ss.ps.ps_ProjInfo; peragg = aggstate->peragg; firstSlot = aggstate->ss.ss_ScanTupleSlot; @@ -1125,10 +1147,19 @@ agg_retrieve_hash_table(AggState *aggstate) { /* * Form and return a projection tuple using the aggregate results - * and the representative input tuple. Note we do not support - * aggregates returning sets ... + * and the representative input tuple. */ - return ExecProject(projInfo, NULL); + TupleTableSlot *result; + ExprDoneCond isDone; + + result = ExecProject(aggstate->ss.ps.ps_ProjInfo, &isDone); + + if (isDone != ExprEndResult) + { + aggstate->ss.ps.ps_TupFromTlist = + (isDone == ExprMultipleResult); + return result; + } } } diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c index 414e0b93f70..31566f1fb52 100644 --- a/src/backend/executor/nodeGroup.c +++ b/src/backend/executor/nodeGroup.c @@ -15,7 +15,7 @@ * locate group boundaries. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.70 2008/01/01 19:45:49 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.71 2008/09/08 00:22:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -49,6 +49,23 @@ ExecGroup(GroupState *node) numCols = ((Group *) node->ss.ps.plan)->numCols; grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx; + /* + * Check to see if we're still projecting out tuples from a previous group + * tuple (because there is a function-returning-set in the projection + * expressions). If so, try to project another one. + */ + if (node->ss.ps.ps_TupFromTlist) + { + TupleTableSlot *result; + ExprDoneCond isDone; + + result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone); + if (isDone == ExprMultipleResult) + return result; + /* Done with that source tuple... */ + node->ss.ps.ps_TupFromTlist = false; + } + /* * The ScanTupleSlot holds the (copied) first tuple of each group. */ @@ -90,7 +107,16 @@ ExecGroup(GroupState *node) /* * Form and return a projection tuple using the first input tuple. */ - return ExecProject(node->ss.ps.ps_ProjInfo, NULL); + TupleTableSlot *result; + ExprDoneCond isDone; + + result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone); + + if (isDone != ExprEndResult) + { + node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult); + return result; + } } } @@ -142,7 +168,16 @@ ExecGroup(GroupState *node) /* * Form and return a projection tuple using the first input tuple. */ - return ExecProject(node->ss.ps.ps_ProjInfo, NULL); + TupleTableSlot *result; + ExprDoneCond isDone; + + result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone); + + if (isDone != ExprEndResult) + { + node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult); + return result; + } } } -- GitLab