diff options
Diffstat (limited to 'src/backend/executor/nodeGroup.c')
-rw-r--r-- | src/backend/executor/nodeGroup.c | 502 |
1 files changed, 0 insertions, 502 deletions
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c deleted file mode 100644 index 5d7f6a69924..00000000000 --- a/src/backend/executor/nodeGroup.c +++ /dev/null @@ -1,502 +0,0 @@ -/*------------------------------------------------------------------------- - * - * nodeGroup.c - * Routines to handle group nodes (used for queries with GROUP BY clause). - * - * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * DESCRIPTION - * The Group node is designed for handling queries with a GROUP BY clause. - * Its outer plan must deliver tuples that are sorted in the order - * specified by the grouping columns (ie. tuples from the same group are - * consecutive). That way, we just have to compare adjacent tuples to - * locate group boundaries. - * - * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.47 2002/06/20 20:29:28 momjian Exp $ - * - *------------------------------------------------------------------------- - */ - -#include "postgres.h" - -#include "access/heapam.h" -#include "catalog/pg_operator.h" -#include "executor/executor.h" -#include "executor/nodeGroup.h" -#include "parser/parse_oper.h" -#include "utils/builtins.h" -#include "utils/lsyscache.h" -#include "utils/syscache.h" - -static TupleTableSlot *ExecGroupEveryTuple(Group *node); -static TupleTableSlot *ExecGroupOneTuple(Group *node); - -/* --------------------------------------- - * 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) - * - * 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 are present. This is useful when - * the query does not involve aggregates. (eg. SELECT salary FROM emp - * GROUP BY salary) - * ------------------------------------------ - */ -TupleTableSlot * -ExecGroup(Group *node) -{ - if (node->tuplePerGroup) - return ExecGroupEveryTuple(node); - else - return ExecGroupOneTuple(node); -} - -/* - * ExecGroupEveryTuple - - * return every tuple with a NULL between each group - */ -static TupleTableSlot * -ExecGroupEveryTuple(Group *node) -{ - GroupState *grpstate; - EState *estate; - ExprContext *econtext; - TupleDesc tupdesc; - HeapTuple outerTuple = NULL; - HeapTuple firsttuple; - TupleTableSlot *outerslot; - ProjectionInfo *projInfo; - TupleTableSlot *resultSlot; - - /* - * get state info from node - */ - grpstate = node->grpstate; - if (grpstate->grp_done) - return NULL; - estate = node->plan.state; - econtext = grpstate->csstate.cstate.cs_ExprContext; - tupdesc = ExecGetScanType(&grpstate->csstate); - - /* - * We need not call ResetExprContext here because execTuplesMatch will - * reset the per-tuple memory context once per input tuple. - */ - - /* if we haven't returned first tuple of a new group yet ... */ - if (grpstate->grp_useFirstTuple) - { - grpstate->grp_useFirstTuple = FALSE; - - /* - * note we rely on subplan to hold ownership of the tuple for as - * long as we need it; we don't copy it. - */ - ExecStoreTuple(grpstate->grp_firstTuple, - grpstate->csstate.css_ScanTupleSlot, - InvalidBuffer, false); - } - else - { - outerslot = ExecProcNode(outerPlan(node), (Plan *) node); - if (TupIsNull(outerslot)) - { - grpstate->grp_done = TRUE; - return NULL; - } - outerTuple = outerslot->val; - - firsttuple = grpstate->grp_firstTuple; - if (firsttuple == NULL) - { - /* this should occur on the first call only */ - grpstate->grp_firstTuple = heap_copytuple(outerTuple); - } - else - { - /* - * Compare with first tuple and see if this tuple is of the - * same group. - */ - if (!execTuplesMatch(firsttuple, outerTuple, - tupdesc, - node->numCols, node->grpColIdx, - grpstate->eqfunctions, - econtext->ecxt_per_tuple_memory)) - { - /* - * No; save the tuple to return it next time, and return - * NULL - */ - grpstate->grp_useFirstTuple = TRUE; - heap_freetuple(firsttuple); - grpstate->grp_firstTuple = heap_copytuple(outerTuple); - - return NULL; /* signifies the end of the group */ - } - } - - /* - * note we rely on subplan to hold ownership of the tuple for as - * long as we need it; we don't copy it. - */ - ExecStoreTuple(outerTuple, - grpstate->csstate.css_ScanTupleSlot, - InvalidBuffer, 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, NULL); - - return resultSlot; -} - -/* - * ExecGroupOneTuple - - * returns one tuple per group, a NULL at the end when there are no more - * tuples. - */ -static TupleTableSlot * -ExecGroupOneTuple(Group *node) -{ - GroupState *grpstate; - EState *estate; - ExprContext *econtext; - TupleDesc tupdesc; - HeapTuple outerTuple = NULL; - HeapTuple firsttuple; - TupleTableSlot *outerslot; - ProjectionInfo *projInfo; - TupleTableSlot *resultSlot; - - /* - * get state info from node - */ - grpstate = node->grpstate; - if (grpstate->grp_done) - return NULL; - estate = node->plan.state; - econtext = node->grpstate->csstate.cstate.cs_ExprContext; - tupdesc = ExecGetScanType(&grpstate->csstate); - - /* - * We need not call ResetExprContext here because execTuplesMatch will - * reset the per-tuple memory context once per input tuple. - */ - - firsttuple = grpstate->grp_firstTuple; - if (firsttuple == NULL) - { - /* this should occur on the first call only */ - outerslot = ExecProcNode(outerPlan(node), (Plan *) node); - if (TupIsNull(outerslot)) - { - grpstate->grp_done = TRUE; - return NULL; - } - grpstate->grp_firstTuple = firsttuple = - heap_copytuple(outerslot->val); - } - - /* - * find all tuples that belong to a group - */ - for (;;) - { - outerslot = ExecProcNode(outerPlan(node), (Plan *) node); - if (TupIsNull(outerslot)) - { - grpstate->grp_done = TRUE; - outerTuple = NULL; - break; - } - outerTuple = outerslot->val; - - /* - * Compare with first tuple and see if this tuple is of the same - * group. - */ - if (!execTuplesMatch(firsttuple, outerTuple, - tupdesc, - node->numCols, node->grpColIdx, - grpstate->eqfunctions, - econtext->ecxt_per_tuple_memory)) - break; - } - - /* - * form a projection tuple, store it in the result tuple slot and - * return it. - */ - projInfo = grpstate->csstate.cstate.cs_ProjInfo; - - /* - * note we rely on subplan to hold ownership of the tuple for as long - * as we need it; we don't copy it. - */ - ExecStoreTuple(firsttuple, - grpstate->csstate.css_ScanTupleSlot, - InvalidBuffer, false); - econtext->ecxt_scantuple = grpstate->csstate.css_ScanTupleSlot; - resultSlot = ExecProject(projInfo, NULL); - - /* save outerTuple if we are not done yet */ - if (!grpstate->grp_done) - { - heap_freetuple(firsttuple); - grpstate->grp_firstTuple = heap_copytuple(outerTuple); - } - - return resultSlot; -} - -/* ----------------- - * ExecInitGroup - * - * 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) -{ - 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_useFirstTuple = FALSE; - grpstate->grp_done = FALSE; - grpstate->grp_firstTuple = NULL; - - /* - * create expression context - */ - 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); - - /* - * Precompute fmgr lookup data for inner loop - */ - grpstate->eqfunctions = - execTuplesMatchPrepare(ExecGetScanType(&grpstate->csstate), - node->numCols, - node->grpColIdx); - - return TRUE; -} - -int -ExecCountSlotsGroup(Group *node) -{ - return ExecCountSlotsNode(outerPlan(node)) + GROUP_NSLOTS; -} - -/* ------------------------ - * ExecEndGroup(node) - * - * ----------------------- - */ -void -ExecEndGroup(Group *node) -{ - GroupState *grpstate; - Plan *outerPlan; - - grpstate = node->grpstate; - - ExecFreeProjectionInfo(&grpstate->csstate.cstate); - ExecFreeExprContext(&grpstate->csstate.cstate); - - outerPlan = outerPlan(node); - ExecEndNode(outerPlan, (Plan *) node); - - /* clean up tuple table */ - ExecClearTuple(grpstate->csstate.css_ScanTupleSlot); - if (grpstate->grp_firstTuple != NULL) - { - heap_freetuple(grpstate->grp_firstTuple); - grpstate->grp_firstTuple = NULL; - } -} - -void -ExecReScanGroup(Group *node, ExprContext *exprCtxt, Plan *parent) -{ - GroupState *grpstate = node->grpstate; - - grpstate->grp_useFirstTuple = FALSE; - grpstate->grp_done = FALSE; - if (grpstate->grp_firstTuple != NULL) - { - heap_freetuple(grpstate->grp_firstTuple); - grpstate->grp_firstTuple = NULL; - } - - if (((Plan *) node)->lefttree && - ((Plan *) node)->lefttree->chgParam == NULL) - ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node); -} - -/***************************************************************************** - * Code shared with nodeUnique.c - *****************************************************************************/ - -/* - * execTuplesMatch - * Return true if two tuples match in all the indicated fields. - * This is used to detect group boundaries in nodeGroup, and to - * decide whether two tuples are distinct or not in nodeUnique. - * - * tuple1, tuple2: the tuples to compare - * tupdesc: tuple descriptor applying to both tuples - * numCols: the number of attributes to be examined - * matchColIdx: array of attribute column numbers - * eqFunctions: array of fmgr lookup info for the equality functions to use - * evalContext: short-term memory context for executing the functions - * - * NB: evalContext is reset each time! - */ -bool -execTuplesMatch(HeapTuple tuple1, - HeapTuple tuple2, - TupleDesc tupdesc, - int numCols, - AttrNumber *matchColIdx, - FmgrInfo *eqfunctions, - MemoryContext evalContext) -{ - MemoryContext oldContext; - bool result; - int i; - - /* Reset and switch into the temp context. */ - MemoryContextReset(evalContext); - oldContext = MemoryContextSwitchTo(evalContext); - - /* - * We cannot report a match without checking all the fields, but we - * can report a non-match as soon as we find unequal fields. So, - * start comparing at the last field (least significant sort key). - * That's the most likely to be different... - */ - result = true; - - for (i = numCols; --i >= 0;) - { - AttrNumber att = matchColIdx[i]; - Datum attr1, - attr2; - bool isNull1, - isNull2; - - attr1 = heap_getattr(tuple1, - att, - tupdesc, - &isNull1); - - attr2 = heap_getattr(tuple2, - att, - tupdesc, - &isNull2); - - if (isNull1 != isNull2) - { - result = false; /* one null and one not; they aren't equal */ - break; - } - - if (isNull1) - continue; /* both are null, treat as equal */ - - /* Apply the type-specific equality function */ - - if (!DatumGetBool(FunctionCall2(&eqfunctions[i], - attr1, attr2))) - { - result = false; /* they aren't equal */ - break; - } - } - - MemoryContextSwitchTo(oldContext); - - return result; -} - -/* - * execTuplesMatchPrepare - * Look up the equality functions needed for execTuplesMatch. - * The result is a palloc'd array. - */ -FmgrInfo * -execTuplesMatchPrepare(TupleDesc tupdesc, - int numCols, - AttrNumber *matchColIdx) -{ - FmgrInfo *eqfunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo)); - int i; - - for (i = 0; i < numCols; i++) - { - AttrNumber att = matchColIdx[i]; - Oid typid = tupdesc->attrs[att - 1]->atttypid; - Oid eq_function; - - eq_function = compatible_oper_funcid(makeList1(makeString("=")), - typid, typid, true); - if (!OidIsValid(eq_function)) - elog(ERROR, "Unable to identify an equality operator for type %s", - format_type_be(typid)); - fmgr_info(eq_function, &eqfunctions[i]); - } - - return eqfunctions; -} |