1 /*-------------------------------------------------------------------------
4 * Routines to handle unique'ing of queries where appropriate
6 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/executor/nodeUnique.c,v 1.46 2005/03/16 21:38:08 tgl Exp $
13 *-------------------------------------------------------------------------
17 * ExecUnique - generate a unique'd temporary relation
18 * ExecInitUnique - initialize node and subnodes..
19 * ExecEndUnique - shutdown node and subnodes
22 * Assumes tuples returned from subplan arrive in
28 #include "access/heapam.h"
29 #include "executor/executor.h"
30 #include "executor/nodeUnique.h"
33 /* ----------------------------------------------------------------
36 * This is a very simple node which filters out duplicate
37 * tuples from a stream of sorted tuples from a subplan.
38 * ----------------------------------------------------------------
40 TupleTableSlot * /* return: a tuple or NULL */
41 ExecUnique(UniqueState *node)
43 Unique *plannode = (Unique *) node->ps.plan;
44 TupleTableSlot *resultTupleSlot;
49 * get information from the node
51 outerPlan = outerPlanState(node);
52 resultTupleSlot = node->ps.ps_ResultTupleSlot;
55 * now loop, returning only non-duplicate tuples. We assume that the
56 * tuples arrive in sorted order so we can detect duplicates easily.
58 * We return the first tuple from each group of duplicates (or the last
59 * tuple of each group, when moving backwards). At either end of the
60 * subplan, clear the result slot so that we correctly return the
61 * first/last tuple when reversing direction.
66 * fetch a tuple from the outer subplan
68 slot = ExecProcNode(outerPlan);
71 /* end of subplan; reset in case we change direction */
72 ExecClearTuple(resultTupleSlot);
77 * Always return the first/last tuple from the subplan.
79 if (TupIsNull(resultTupleSlot))
83 * Else test if the new tuple and the previously returned tuple
84 * match. If so then we loop back and fetch another new tuple
87 if (!execTuplesMatch(slot, resultTupleSlot,
88 plannode->numCols, plannode->uniqColIdx,
95 * We have a new tuple different from the previous saved tuple (if
96 * any). Save it and return it. We must copy it because the source
97 * subplan won't guarantee that this source tuple is still accessible
98 * after fetching the next source tuple.
100 return ExecCopySlot(resultTupleSlot, slot);
103 /* ----------------------------------------------------------------
106 * This initializes the unique node state structures and
107 * the node's subplan.
108 * ----------------------------------------------------------------
111 ExecInitUnique(Unique *node, EState *estate)
113 UniqueState *uniquestate;
116 * create state structure
118 uniquestate = makeNode(UniqueState);
119 uniquestate->ps.plan = (Plan *) node;
120 uniquestate->ps.state = estate;
123 * Miscellaneous initialization
125 * Unique nodes have no ExprContext initialization because they never
126 * call ExecQual or ExecProject. But they do need a per-tuple memory
127 * context anyway for calling execTuplesMatch.
129 uniquestate->tempContext =
130 AllocSetContextCreate(CurrentMemoryContext,
132 ALLOCSET_DEFAULT_MINSIZE,
133 ALLOCSET_DEFAULT_INITSIZE,
134 ALLOCSET_DEFAULT_MAXSIZE);
136 #define UNIQUE_NSLOTS 1
139 * Tuple table initialization
141 ExecInitResultTupleSlot(estate, &uniquestate->ps);
144 * then initialize outer plan
146 outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate);
149 * unique nodes do no projections, so initialize projection info for
150 * this node appropriately
152 ExecAssignResultTypeFromOuterPlan(&uniquestate->ps);
153 uniquestate->ps.ps_ProjInfo = NULL;
156 * Precompute fmgr lookup data for inner loop
158 uniquestate->eqfunctions =
159 execTuplesMatchPrepare(ExecGetResultType(&uniquestate->ps),
167 ExecCountSlotsUnique(Unique *node)
169 return ExecCountSlotsNode(outerPlan(node)) +
170 ExecCountSlotsNode(innerPlan(node)) +
174 /* ----------------------------------------------------------------
177 * This shuts down the subplan and frees resources allocated
179 * ----------------------------------------------------------------
182 ExecEndUnique(UniqueState *node)
184 /* clean up tuple table */
185 ExecClearTuple(node->ps.ps_ResultTupleSlot);
187 MemoryContextDelete(node->tempContext);
189 ExecEndNode(outerPlanState(node));
194 ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt)
196 /* must clear result tuple so first input tuple is returned */
197 ExecClearTuple(node->ps.ps_ResultTupleSlot);
200 * if chgParam of subnode is not null then plan will be re-scanned by
201 * first ExecProcNode.
203 if (((PlanState *) node)->lefttree->chgParam == NULL)
204 ExecReScan(((PlanState *) node)->lefttree, exprCtxt);