postgresql/src/backend/executor/nodeUnique.c

232 lines
6.1 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* nodeUnique.c
* Routines to handle unique'ing of queries where appropriate
*
2003-08-04 04:40:20 +02:00
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
2003-11-29 20:52:15 +01:00
* $PostgreSQL: pgsql/src/backend/executor/nodeUnique.c,v 1.41 2003/11/29 19:51:48 pgsql Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* ExecUnique - generate a unique'd temporary relation
* ExecInitUnique - initialize node and subnodes..
* ExecEndUnique - shutdown node and subnodes
*
* NOTES
* Assumes tuples returned from subplan arrive in
* sorted order.
*/
#include "postgres.h"
1996-11-08 07:02:30 +01:00
#include "access/heapam.h"
1999-07-16 07:00:38 +02:00
#include "executor/executor.h"
#include "executor/nodeUnique.h"
/* ----------------------------------------------------------------
* ExecUnique
*
* This is a very simple node which filters out duplicate
* tuples from a stream of sorted tuples from a subplan.
* ----------------------------------------------------------------
*/
TupleTableSlot * /* return: a tuple or NULL */
ExecUnique(UniqueState *node)
{
Unique *plannode = (Unique *) node->ps.plan;
TupleTableSlot *resultTupleSlot;
TupleTableSlot *slot;
PlanState *outerPlan;
TupleDesc tupDesc;
/*
* get information from the node
*/
outerPlan = outerPlanState(node);
resultTupleSlot = node->ps.ps_ResultTupleSlot;
tupDesc = ExecGetResultType(&node->ps);
/*
* now loop, returning only non-duplicate tuples. We assume that the
* tuples arrive in sorted order so we can detect duplicates easily.
*
2003-08-04 02:43:34 +02:00
* We return the first tuple from each group of duplicates (or the last
* tuple of each group, when moving backwards). At either end of the
* subplan, clear priorTuple so that we correctly return the
* first/last tuple when reversing direction.
*/
for (;;)
{
/*
* fetch a tuple from the outer subplan
*/
slot = ExecProcNode(outerPlan);
if (TupIsNull(slot))
{
/* end of subplan; reset in case we change direction */
if (node->priorTuple != NULL)
heap_freetuple(node->priorTuple);
node->priorTuple = NULL;
return NULL;
}
/*
* Always return the first/last tuple from the subplan.
*/
if (node->priorTuple == NULL)
break;
/*
* Else test if the new tuple and the previously returned tuple
* match. If so then we loop back and fetch another new tuple
* from the subplan.
*/
if (!execTuplesMatch(slot->val, node->priorTuple,
tupDesc,
plannode->numCols, plannode->uniqColIdx,
node->eqfunctions,
node->tempContext))
break;
}
/*
* We have a new tuple different from the previous saved tuple (if
* any). Save it and return it. We must copy it because the source
* subplan won't guarantee that this source tuple is still accessible
* after fetching the next source tuple.
*
* Note that we manage the copy ourselves. We can't rely on the result
* tuple slot to maintain the tuple reference because our caller may
* replace the slot contents with a different tuple (see junk filter
* handling in execMain.c). We assume that the caller will no longer
* be interested in the current tuple after he next calls us.
*/
if (node->priorTuple != NULL)
heap_freetuple(node->priorTuple);
node->priorTuple = heap_copytuple(slot->val);
ExecStoreTuple(node->priorTuple,
resultTupleSlot,
InvalidBuffer,
false); /* tuple does not belong to slot */
return resultTupleSlot;
}
/* ----------------------------------------------------------------
* ExecInitUnique
*
* This initializes the unique node state structures and
* the node's subplan.
* ----------------------------------------------------------------
*/
UniqueState *
ExecInitUnique(Unique *node, EState *estate)
{
UniqueState *uniquestate;
/*
* create state structure
*/
uniquestate = makeNode(UniqueState);
uniquestate->ps.plan = (Plan *) node;
uniquestate->ps.state = estate;
uniquestate->priorTuple = NULL;
/*
* Miscellaneous initialization
*
* Unique nodes have no ExprContext initialization because they never
* call ExecQual or ExecProject. But they do need a per-tuple memory
* context anyway for calling execTuplesMatch.
*/
uniquestate->tempContext =
AllocSetContextCreate(CurrentMemoryContext,
"Unique",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
#define UNIQUE_NSLOTS 1
/*
* Tuple table initialization
*/
ExecInitResultTupleSlot(estate, &uniquestate->ps);
/*
* then initialize outer plan
*/
outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate);
/*
* unique nodes do no projections, so initialize projection info for
* this node appropriately
*/
ExecAssignResultTypeFromOuterPlan(&uniquestate->ps);
uniquestate->ps.ps_ProjInfo = NULL;
/*
* Precompute fmgr lookup data for inner loop
*/
uniquestate->eqfunctions =
execTuplesMatchPrepare(ExecGetResultType(&uniquestate->ps),
node->numCols,
node->uniqColIdx);
return uniquestate;
}
int
ExecCountSlotsUnique(Unique *node)
{
return ExecCountSlotsNode(outerPlan(node)) +
ExecCountSlotsNode(innerPlan(node)) +
UNIQUE_NSLOTS;
}
/* ----------------------------------------------------------------
* ExecEndUnique
*
* This shuts down the subplan and frees resources allocated
* to this node.
* ----------------------------------------------------------------
*/
void
ExecEndUnique(UniqueState *node)
{
/* clean up tuple table */
ExecClearTuple(node->ps.ps_ResultTupleSlot);
MemoryContextDelete(node->tempContext);
ExecEndNode(outerPlanState(node));
}
1998-02-23 07:28:16 +01:00
void
ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt)
1998-02-23 07:28:16 +01:00
{
ExecClearTuple(node->ps.ps_ResultTupleSlot);
if (node->priorTuple != NULL)
{
heap_freetuple(node->priorTuple);
node->priorTuple = NULL;
}
/*
* if chgParam of subnode is not null then plan will be re-scanned by
* first ExecProcNode.
1998-02-23 07:28:16 +01:00
*/
if (((PlanState *) node)->lefttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
1998-02-23 07:28:16 +01:00
}