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;
+           }
        }
    }