aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeGroup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeGroup.c')
-rw-r--r--src/backend/executor/nodeGroup.c632
1 files changed, 330 insertions, 302 deletions
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index 0637a8dd282..1a96a1ee911 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -1,19 +1,19 @@
/*-------------------------------------------------------------------------
*
* nodeGroup.c--
- * Routines to handle group nodes (used for queries with GROUP BY clause).
+ * Routines to handle group nodes (used for queries with GROUP BY clause).
*
* Copyright (c) 1994, Regents of the University of California
*
*
* DESCRIPTION
- * The Group node is designed for handling queries with a GROUP BY clause.
- * It's outer plan must be a sort node. It assumes that the tuples it gets
- * back from the outer plan is sorted in the order specified by the group
- * columns. (ie. tuples from the same group are consecutive)
+ * The Group node is designed for handling queries with a GROUP BY clause.
+ * It's outer plan must be a sort node. It assumes that the tuples it gets
+ * back from the outer plan is sorted in the order specified by the group
+ * columns. (ie. tuples from the same group are consecutive)
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.5 1997/01/10 20:17:35 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.6 1997/09/07 04:41:31 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,329 +28,348 @@
#include "executor/executor.h"
#include "executor/nodeGroup.h"
-static TupleTableSlot *ExecGroupEveryTuple(Group *node);
-static TupleTableSlot *ExecGroupOneTuple(Group *node);
-static bool sameGroup(TupleTableSlot *oldslot, TupleTableSlot *newslot,
- int numCols, AttrNumber *grpColIdx, TupleDesc tupdesc);
+static TupleTableSlot *ExecGroupEveryTuple(Group * node);
+static TupleTableSlot *ExecGroupOneTuple(Group * node);
+static bool
+sameGroup(TupleTableSlot * oldslot, TupleTableSlot * newslot,
+ int numCols, AttrNumber * grpColIdx, TupleDesc tupdesc);
/* ---------------------------------------
- * ExecGroup -
+ * ExecGroup -
*
- * There are two modes in which tuples are returned by ExecGroup. If
- * tuplePerGroup is TRUE, every tuple from the same group will be
- * returned, followed by a NULL at the end of each group. This is
- * useful for Agg node which needs to aggregate over tuples of the same
- * group. (eg. SELECT salary, count{*} FROM emp GROUP BY salary)
+ * There are two modes in which tuples are returned by ExecGroup. If
+ * tuplePerGroup is TRUE, every tuple from the same group will be
+ * returned, followed by a NULL at the end of each group. This is
+ * useful for Agg node which needs to aggregate over tuples of the same
+ * group. (eg. SELECT salary, count{*} FROM emp GROUP BY salary)
*
- * If tuplePerGroup is FALSE, only one tuple per group is returned. The
- * tuple returned contains only the group columns. NULL is returned only
- * at the end when no more groups is present. This is useful when
- * the query does not involve aggregates. (eg. SELECT salary FROM emp
- * GROUP BY salary)
+ * If tuplePerGroup is FALSE, only one tuple per group is returned. The
+ * tuple returned contains only the group columns. NULL is returned only
+ * at the end when no more groups is present. This is useful when
+ * the query does not involve aggregates. (eg. SELECT salary FROM emp
+ * GROUP BY salary)
* ------------------------------------------
*/
TupleTableSlot *
-ExecGroup(Group *node)
+ExecGroup(Group * node)
{
- if (node->tuplePerGroup)
- return ExecGroupEveryTuple(node);
- else
- return ExecGroupOneTuple(node);
+ if (node->tuplePerGroup)
+ return ExecGroupEveryTuple(node);
+ else
+ return ExecGroupOneTuple(node);
}
/*
* ExecGroupEveryTuple -
- * return every tuple with a NULL between each group
+ * return every tuple with a NULL between each group
*/
static TupleTableSlot *
-ExecGroupEveryTuple(Group *node)
+ExecGroupEveryTuple(Group * node)
{
- GroupState *grpstate;
- EState *estate;
- ExprContext *econtext;
+ GroupState *grpstate;
+ EState *estate;
+ ExprContext *econtext;
- HeapTuple outerTuple = NULL;
- TupleTableSlot *outerslot, *lastslot;
- ProjectionInfo *projInfo;
- TupleTableSlot *resultSlot;
+ HeapTuple outerTuple = NULL;
+ TupleTableSlot *outerslot,
+ *lastslot;
+ ProjectionInfo *projInfo;
+ TupleTableSlot *resultSlot;
- bool isDone;
+ bool isDone;
- /* ---------------------
- * get state info from node
- * ---------------------
- */
- grpstate = node->grpstate;
- if (grpstate->grp_done)
- return NULL;
+ /* ---------------------
+ * get state info from node
+ * ---------------------
+ */
+ grpstate = node->grpstate;
+ if (grpstate->grp_done)
+ return NULL;
- estate = node->plan.state;
+ estate = node->plan.state;
- econtext = grpstate->csstate.cstate.cs_ExprContext;
+ econtext = grpstate->csstate.cstate.cs_ExprContext;
- if (grpstate->grp_useLastTuple) {
- /*
- * we haven't returned last tuple yet because it is not of the
- * same group
- */
- grpstate->grp_useLastTuple = FALSE;
+ if (grpstate->grp_useLastTuple)
+ {
+
+ /*
+ * we haven't returned last tuple yet because it is not of the
+ * same group
+ */
+ grpstate->grp_useLastTuple = FALSE;
- ExecStoreTuple(grpstate->grp_lastSlot->val,
- grpstate->csstate.css_ScanTupleSlot,
- grpstate->grp_lastSlot->ttc_buffer,
- false);
- } else {
- outerslot = ExecProcNode(outerPlan(node), (Plan*)node);
- if (outerslot)
- outerTuple = outerslot->val;
- if (!HeapTupleIsValid(outerTuple)) {
- grpstate->grp_done = TRUE;
- return NULL;
+ ExecStoreTuple(grpstate->grp_lastSlot->val,
+ grpstate->csstate.css_ScanTupleSlot,
+ grpstate->grp_lastSlot->ttc_buffer,
+ false);
+ }
+ else
+ {
+ outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
+ if (outerslot)
+ outerTuple = outerslot->val;
+ if (!HeapTupleIsValid(outerTuple))
+ {
+ grpstate->grp_done = TRUE;
+ return NULL;
+ }
+
+ /* ----------------
+ * Compare with last tuple and see if this tuple is of
+ * the same group.
+ * ----------------
+ */
+ lastslot = grpstate->csstate.css_ScanTupleSlot;
+
+ if (lastslot->val != NULL &&
+ (!sameGroup(lastslot, outerslot,
+ node->numCols, node->grpColIdx,
+ ExecGetScanType(&grpstate->csstate))))
+ {
+/* ExecGetResultType(&grpstate->csstate.cstate)))) {*/
+
+ grpstate->grp_useLastTuple = TRUE;
+
+ /* save it for next time */
+ grpstate->grp_lastSlot = outerslot;
+
+ /*
+ * signifies the end of the group
+ */
+ return NULL;
+ }
+
+ ExecStoreTuple(outerTuple,
+ grpstate->csstate.css_ScanTupleSlot,
+ outerslot->ttc_buffer,
+ false);
}
/* ----------------
- * Compare with last tuple and see if this tuple is of
- * the same group.
+ * form a projection tuple, store it in the result tuple
+ * slot and return it.
* ----------------
*/
- lastslot = grpstate->csstate.css_ScanTupleSlot;
-
- if (lastslot->val != NULL &&
- (!sameGroup(lastslot, outerslot,
- node->numCols, node->grpColIdx,
- ExecGetScanType(&grpstate->csstate)))) {
-/* ExecGetResultType(&grpstate->csstate.cstate)))) {*/
-
- grpstate->grp_useLastTuple = TRUE;
+ projInfo = grpstate->csstate.cstate.cs_ProjInfo;
- /* save it for next time */
- grpstate->grp_lastSlot = outerslot;
+ econtext->ecxt_scantuple = grpstate->csstate.css_ScanTupleSlot;
+ resultSlot = ExecProject(projInfo, &isDone);
- /*
- * signifies the end of the group
- */
- return NULL;
- }
-
- ExecStoreTuple(outerTuple,
- grpstate->csstate.css_ScanTupleSlot,
- outerslot->ttc_buffer,
- false);
- }
-
- /* ----------------
- * form a projection tuple, store it in the result tuple
- * slot and return it.
- * ----------------
- */
- projInfo = grpstate->csstate.cstate.cs_ProjInfo;
-
- econtext->ecxt_scantuple = grpstate->csstate.css_ScanTupleSlot;
- resultSlot = ExecProject(projInfo, &isDone);
-
- return resultSlot;
+ return resultSlot;
}
/*
* ExecGroupOneTuple -
- * returns one tuple per group, a NULL at the end when there are no more
- * tuples.
+ * returns one tuple per group, a NULL at the end when there are no more
+ * tuples.
*/
static TupleTableSlot *
-ExecGroupOneTuple(Group *node)
+ExecGroupOneTuple(Group * node)
{
- GroupState *grpstate;
- EState *estate;
- ExprContext *econtext;
+ GroupState *grpstate;
+ EState *estate;
+ ExprContext *econtext;
- HeapTuple outerTuple = NULL;
- TupleTableSlot *outerslot, *lastslot;
- ProjectionInfo *projInfo;
- TupleTableSlot *resultSlot;
+ HeapTuple outerTuple = NULL;
+ TupleTableSlot *outerslot,
+ *lastslot;
+ ProjectionInfo *projInfo;
+ TupleTableSlot *resultSlot;
- bool isDone;
+ bool isDone;
- /* ---------------------
- * get state info from node
- * ---------------------
- */
- grpstate = node->grpstate;
- if (grpstate->grp_done)
- return NULL;
+ /* ---------------------
+ * get state info from node
+ * ---------------------
+ */
+ grpstate = node->grpstate;
+ if (grpstate->grp_done)
+ return NULL;
- estate = node->plan.state;
+ estate = node->plan.state;
- econtext = node->grpstate->csstate.cstate.cs_ExprContext;
+ econtext = node->grpstate->csstate.cstate.cs_ExprContext;
- if (grpstate->grp_useLastTuple) {
- grpstate->grp_useLastTuple = FALSE;
- ExecStoreTuple(grpstate->grp_lastSlot->val,
- grpstate->csstate.css_ScanTupleSlot,
- grpstate->grp_lastSlot->ttc_buffer,
- false);
- } else {
- outerslot = ExecProcNode(outerPlan(node), (Plan*)node);
- if (outerslot) outerTuple = outerslot->val;
- if (!HeapTupleIsValid(outerTuple)) {
- grpstate->grp_done = TRUE;
- return NULL;
+ if (grpstate->grp_useLastTuple)
+ {
+ grpstate->grp_useLastTuple = FALSE;
+ ExecStoreTuple(grpstate->grp_lastSlot->val,
+ grpstate->csstate.css_ScanTupleSlot,
+ grpstate->grp_lastSlot->ttc_buffer,
+ false);
}
- ExecStoreTuple(outerTuple,
- grpstate->csstate.css_ScanTupleSlot,
- outerslot->ttc_buffer,
- false);
- }
- lastslot = grpstate->csstate.css_ScanTupleSlot;
-
- /*
- * find all tuples that belong to a group
- */
- for(;;) {
- outerslot = ExecProcNode(outerPlan(node), (Plan*)node);
- outerTuple = (outerslot) ? outerslot->val : NULL;
- if (!HeapTupleIsValid(outerTuple)) {
- /*
- * we have at least one tuple (lastslot) if we reach here
- */
- grpstate->grp_done = TRUE;
-
- /* return lastslot */
- break;
+ else
+ {
+ outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
+ if (outerslot)
+ outerTuple = outerslot->val;
+ if (!HeapTupleIsValid(outerTuple))
+ {
+ grpstate->grp_done = TRUE;
+ return NULL;
+ }
+ ExecStoreTuple(outerTuple,
+ grpstate->csstate.css_ScanTupleSlot,
+ outerslot->ttc_buffer,
+ false);
}
+ lastslot = grpstate->csstate.css_ScanTupleSlot;
- /* ----------------
- * Compare with last tuple and see if this tuple is of
- * the same group.
- * ----------------
+ /*
+ * find all tuples that belong to a group
*/
- if ((!sameGroup(lastslot, outerslot,
- node->numCols, node->grpColIdx,
- ExecGetScanType(&grpstate->csstate)))) {
-/* ExecGetResultType(&grpstate->csstate.cstate)))) {*/
+ for (;;)
+ {
+ outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
+ outerTuple = (outerslot) ? outerslot->val : NULL;
+ if (!HeapTupleIsValid(outerTuple))
+ {
+
+ /*
+ * we have at least one tuple (lastslot) if we reach here
+ */
+ grpstate->grp_done = TRUE;
+
+ /* return lastslot */
+ break;
+ }
+
+ /* ----------------
+ * Compare with last tuple and see if this tuple is of
+ * the same group.
+ * ----------------
+ */
+ if ((!sameGroup(lastslot, outerslot,
+ node->numCols, node->grpColIdx,
+ ExecGetScanType(&grpstate->csstate))))
+ {
+/* ExecGetResultType(&grpstate->csstate.cstate)))) {*/
+
+ grpstate->grp_useLastTuple = TRUE;
+
+ /* save it for next time */
+ grpstate->grp_lastSlot = outerslot;
+
+ /* return lastslot */
+ break;
+ }
+
+ ExecStoreTuple(outerTuple,
+ grpstate->csstate.css_ScanTupleSlot,
+ outerslot->ttc_buffer,
+ false);
+
+ lastslot = grpstate->csstate.css_ScanTupleSlot;
+ }
- grpstate->grp_useLastTuple = TRUE;
+ ExecStoreTuple(lastslot->val,
+ grpstate->csstate.css_ScanTupleSlot,
+ lastslot->ttc_buffer,
+ false);
- /* save it for next time */
- grpstate->grp_lastSlot = outerslot;
+ /* ----------------
+ * form a projection tuple, store it in the result tuple
+ * slot and return it.
+ * ----------------
+ */
+ projInfo = grpstate->csstate.cstate.cs_ProjInfo;
- /* return lastslot */
- break;
- }
-
- ExecStoreTuple(outerTuple,
- grpstate->csstate.css_ScanTupleSlot,
- outerslot->ttc_buffer,
- false);
+ econtext->ecxt_scantuple = lastslot;
+ resultSlot = ExecProject(projInfo, &isDone);
- lastslot = grpstate->csstate.css_ScanTupleSlot;
- }
-
- ExecStoreTuple(lastslot->val,
- grpstate->csstate.css_ScanTupleSlot,
- lastslot->ttc_buffer,
- false);
-
- /* ----------------
- * form a projection tuple, store it in the result tuple
- * slot and return it.
- * ----------------
- */
- projInfo = grpstate->csstate.cstate.cs_ProjInfo;
-
- econtext->ecxt_scantuple = lastslot;
- resultSlot = ExecProject(projInfo, &isDone);
-
- return resultSlot;
+ return resultSlot;
}
/* -----------------
- * ExecInitGroup
+ * ExecInitGroup
*
- * Creates the run-time information for the group node produced by the
- * planner and initializes its outer subtree
+ * Creates the run-time information for the group node produced by the
+ * planner and initializes its outer subtree
* -----------------
*/
bool
-ExecInitGroup(Group *node, EState *estate, Plan *parent)
+ExecInitGroup(Group * node, EState * estate, Plan * parent)
{
- GroupState *grpstate;
- Plan *outerPlan;
-
- /*
- * assign the node's execution state
- */
- node->plan.state = estate;
-
- /*
- * create state structure
- */
- grpstate = makeNode(GroupState);
- node->grpstate = grpstate;
- grpstate->grp_useLastTuple = FALSE;
- grpstate->grp_done = FALSE;
-
- /*
- * assign node's base id and create expression context
- */
- ExecAssignNodeBaseInfo(estate, &grpstate->csstate.cstate,
- (Plan*) parent);
- ExecAssignExprContext(estate, &grpstate->csstate.cstate);
-
+ GroupState *grpstate;
+ Plan *outerPlan;
+
+ /*
+ * assign the node's execution state
+ */
+ node->plan.state = estate;
+
+ /*
+ * create state structure
+ */
+ grpstate = makeNode(GroupState);
+ node->grpstate = grpstate;
+ grpstate->grp_useLastTuple = FALSE;
+ grpstate->grp_done = FALSE;
+
+ /*
+ * assign node's base id and create expression context
+ */
+ ExecAssignNodeBaseInfo(estate, &grpstate->csstate.cstate,
+ (Plan *) parent);
+ ExecAssignExprContext(estate, &grpstate->csstate.cstate);
+
#define GROUP_NSLOTS 2
- /*
- * tuple table initialization
- */
- ExecInitScanTupleSlot(estate, &grpstate->csstate);
- ExecInitResultTupleSlot(estate, &grpstate->csstate.cstate);
-
- /*
- * initializes child nodes
- */
- outerPlan = outerPlan(node);
- ExecInitNode(outerPlan, estate, (Plan *)node);
-
- /* ----------------
- * initialize tuple type.
- * ----------------
- */
- ExecAssignScanTypeFromOuterPlan((Plan *) node, &grpstate->csstate);
-
- /*
- * Initialize tuple type for both result and scan.
- * This node does no projection
- */
- ExecAssignResultTypeFromTL((Plan*) node, &grpstate->csstate.cstate);
- ExecAssignProjectionInfo((Plan*)node, &grpstate->csstate.cstate);
-
- return TRUE;
+
+ /*
+ * tuple table initialization
+ */
+ ExecInitScanTupleSlot(estate, &grpstate->csstate);
+ ExecInitResultTupleSlot(estate, &grpstate->csstate.cstate);
+
+ /*
+ * initializes child nodes
+ */
+ outerPlan = outerPlan(node);
+ ExecInitNode(outerPlan, estate, (Plan *) node);
+
+ /* ----------------
+ * initialize tuple type.
+ * ----------------
+ */
+ ExecAssignScanTypeFromOuterPlan((Plan *) node, &grpstate->csstate);
+
+ /*
+ * Initialize tuple type for both result and scan. This node does no
+ * projection
+ */
+ ExecAssignResultTypeFromTL((Plan *) node, &grpstate->csstate.cstate);
+ ExecAssignProjectionInfo((Plan *) node, &grpstate->csstate.cstate);
+
+ return TRUE;
}
int
-ExecCountSlotsGroup(Group *node)
+ExecCountSlotsGroup(Group * node)
{
- return ExecCountSlotsNode(outerPlan(node)) + GROUP_NSLOTS;
+ return ExecCountSlotsNode(outerPlan(node)) + GROUP_NSLOTS;
}
/* ------------------------
- * ExecEndGroup(node)
+ * ExecEndGroup(node)
*
* -----------------------
*/
void
-ExecEndGroup(Group *node)
+ExecEndGroup(Group * node)
{
- GroupState *grpstate;
- Plan *outerPlan;
+ GroupState *grpstate;
+ Plan *outerPlan;
+
+ grpstate = node->grpstate;
- grpstate = node->grpstate;
+ ExecFreeProjectionInfo(&grpstate->csstate.cstate);
- ExecFreeProjectionInfo(&grpstate->csstate.cstate);
+ outerPlan = outerPlan(node);
+ ExecEndNode(outerPlan, (Plan *) node);
- outerPlan = outerPlan(node);
- ExecEndNode(outerPlan, (Plan*)node);
-
- /* clean up tuple table */
- ExecClearTuple(grpstate->csstate.css_ScanTupleSlot);
+ /* clean up tuple table */
+ ExecClearTuple(grpstate->csstate.css_ScanTupleSlot);
}
/*****************************************************************************
@@ -360,54 +379,63 @@ ExecEndGroup(Group *node)
/*
* code swiped from nodeUnique.c
*/
-static bool
-sameGroup(TupleTableSlot *oldslot,
- TupleTableSlot *newslot,
- int numCols,
- AttrNumber *grpColIdx,
- TupleDesc tupdesc)
+static bool
+sameGroup(TupleTableSlot * oldslot,
+ TupleTableSlot * newslot,
+ int numCols,
+ AttrNumber * grpColIdx,
+ TupleDesc tupdesc)
{
- bool isNull1,isNull2;
- char *attr1, *attr2;
- char *val1, *val2;
- int i;
- AttrNumber att;
- Oid typoutput;
-
- for(i = 0; i < numCols; i++) {
- att = grpColIdx[i];
- typoutput = typtoout((Oid)tupdesc->attrs[att-1]->atttypid);
-
- attr1 = heap_getattr(oldslot->val,
- InvalidBuffer,
- att,
- tupdesc,
- &isNull1);
-
- attr2 = heap_getattr(newslot->val,
- InvalidBuffer,
- att,
- tupdesc,
- &isNull2);
-
- if (isNull1 == isNull2) {
- if (isNull1) /* both are null, they are equal */
- continue;
-
- val1 = fmgr(typoutput, attr1,
- gettypelem(tupdesc->attrs[att-1]->atttypid));
- val2 = fmgr(typoutput, attr2,
- gettypelem(tupdesc->attrs[att-1]->atttypid));
-
- /* now, val1 and val2 are ascii representations so we can
- use strcmp for comparison */
- if (strcmp(val1,val2) != 0)
- return FALSE;
- } else {
- /* one is null and the other isn't, they aren't equal */
- return FALSE;
+ bool isNull1,
+ isNull2;
+ char *attr1,
+ *attr2;
+ char *val1,
+ *val2;
+ int i;
+ AttrNumber att;
+ Oid typoutput;
+
+ for (i = 0; i < numCols; i++)
+ {
+ att = grpColIdx[i];
+ typoutput = typtoout((Oid) tupdesc->attrs[att - 1]->atttypid);
+
+ attr1 = heap_getattr(oldslot->val,
+ InvalidBuffer,
+ att,
+ tupdesc,
+ &isNull1);
+
+ attr2 = heap_getattr(newslot->val,
+ InvalidBuffer,
+ att,
+ tupdesc,
+ &isNull2);
+
+ if (isNull1 == isNull2)
+ {
+ if (isNull1) /* both are null, they are equal */
+ continue;
+
+ val1 = fmgr(typoutput, attr1,
+ gettypelem(tupdesc->attrs[att - 1]->atttypid));
+ val2 = fmgr(typoutput, attr2,
+ gettypelem(tupdesc->attrs[att - 1]->atttypid));
+
+ /*
+ * now, val1 and val2 are ascii representations so we can use
+ * strcmp for comparison
+ */
+ if (strcmp(val1, val2) != 0)
+ return FALSE;
+ }
+ else
+ {
+ /* one is null and the other isn't, they aren't equal */
+ return FALSE;
+ }
}
- }
- return TRUE;
+ return TRUE;
}