Support set-returning functions in the target lists of Agg and Group plan
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 8 Sep 2008 00:22:56 +0000 (00:22 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 8 Sep 2008 00:22:56 +0000 (00:22 +0000)
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
src/backend/executor/nodeGroup.c

index fa49862912ee6f05df78860ba63e903264dc7fb0..80263d174c26a16ace225ee7f78823a052ae16d6 100644 (file)
@@ -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;
+                       }
                }
        }
 
index 414e0b93f70eba7a461c553524259c22f3fa5998..31566f1fb52765626e46f4c731bfa7cfb65dcc72 100644 (file)
@@ -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;
+                       }
                }
        }