Commit a26c7e3d authored by Tom Lane's avatar Tom Lane

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.
parent 8818f379
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -805,6 +805,23 @@ ExecAgg(AggState *node)
if (node->agg_done) if (node->agg_done)
return NULL; 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 (((Agg *) node->ss.ps.plan)->aggstrategy == AGG_HASHED)
{ {
if (!node->table_filled) if (!node->table_filled)
...@@ -825,7 +842,6 @@ agg_retrieve_direct(AggState *aggstate) ...@@ -825,7 +842,6 @@ agg_retrieve_direct(AggState *aggstate)
PlanState *outerPlan; PlanState *outerPlan;
ExprContext *econtext; ExprContext *econtext;
ExprContext *tmpcontext; ExprContext *tmpcontext;
ProjectionInfo *projInfo;
Datum *aggvalues; Datum *aggvalues;
bool *aggnulls; bool *aggnulls;
AggStatePerAgg peragg; AggStatePerAgg peragg;
...@@ -844,7 +860,6 @@ agg_retrieve_direct(AggState *aggstate) ...@@ -844,7 +860,6 @@ agg_retrieve_direct(AggState *aggstate)
aggnulls = econtext->ecxt_aggnulls; aggnulls = econtext->ecxt_aggnulls;
/* tmpcontext is the per-input-tuple expression context */ /* tmpcontext is the per-input-tuple expression context */
tmpcontext = aggstate->tmpcontext; tmpcontext = aggstate->tmpcontext;
projInfo = aggstate->ss.ps.ps_ProjInfo;
peragg = aggstate->peragg; peragg = aggstate->peragg;
pergroup = aggstate->pergroup; pergroup = aggstate->pergroup;
firstSlot = aggstate->ss.ss_ScanTupleSlot; firstSlot = aggstate->ss.ss_ScanTupleSlot;
...@@ -982,10 +997,19 @@ agg_retrieve_direct(AggState *aggstate) ...@@ -982,10 +997,19 @@ agg_retrieve_direct(AggState *aggstate)
{ {
/* /*
* Form and return a projection tuple using the aggregate results * Form and return a projection tuple using the aggregate results
* and the representative input tuple. Note we do not support * and the representative input tuple.
* aggregates returning sets ...
*/ */
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 * ...@@ -1045,7 +1069,6 @@ static TupleTableSlot *
agg_retrieve_hash_table(AggState *aggstate) agg_retrieve_hash_table(AggState *aggstate)
{ {
ExprContext *econtext; ExprContext *econtext;
ProjectionInfo *projInfo;
Datum *aggvalues; Datum *aggvalues;
bool *aggnulls; bool *aggnulls;
AggStatePerAgg peragg; AggStatePerAgg peragg;
...@@ -1061,7 +1084,6 @@ agg_retrieve_hash_table(AggState *aggstate) ...@@ -1061,7 +1084,6 @@ agg_retrieve_hash_table(AggState *aggstate)
econtext = aggstate->ss.ps.ps_ExprContext; econtext = aggstate->ss.ps.ps_ExprContext;
aggvalues = econtext->ecxt_aggvalues; aggvalues = econtext->ecxt_aggvalues;
aggnulls = econtext->ecxt_aggnulls; aggnulls = econtext->ecxt_aggnulls;
projInfo = aggstate->ss.ps.ps_ProjInfo;
peragg = aggstate->peragg; peragg = aggstate->peragg;
firstSlot = aggstate->ss.ss_ScanTupleSlot; firstSlot = aggstate->ss.ss_ScanTupleSlot;
...@@ -1125,10 +1147,19 @@ agg_retrieve_hash_table(AggState *aggstate) ...@@ -1125,10 +1147,19 @@ agg_retrieve_hash_table(AggState *aggstate)
{ {
/* /*
* Form and return a projection tuple using the aggregate results * Form and return a projection tuple using the aggregate results
* and the representative input tuple. Note we do not support * and the representative input tuple.
* aggregates returning sets ...
*/ */
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;
}
} }
} }
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* locate group boundaries. * locate group boundaries.
* *
* IDENTIFICATION * 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) ...@@ -49,6 +49,23 @@ ExecGroup(GroupState *node)
numCols = ((Group *) node->ss.ps.plan)->numCols; numCols = ((Group *) node->ss.ps.plan)->numCols;
grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx; 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. * The ScanTupleSlot holds the (copied) first tuple of each group.
*/ */
...@@ -90,7 +107,16 @@ ExecGroup(GroupState *node) ...@@ -90,7 +107,16 @@ ExecGroup(GroupState *node)
/* /*
* Form and return a projection tuple using the first input tuple. * 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) ...@@ -142,7 +168,16 @@ ExecGroup(GroupState *node)
/* /*
* Form and return a projection tuple using the first input tuple. * 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;
}
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment