1 /*-------------------------------------------------------------------------
4 * Routines to handle unique'ing of queries where appropriate
6 * Portions Copyright (c) 1996-2003, 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.42 2004/03/02 22:05:24 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;
50 * get information from the node
52 outerPlan = outerPlanState(node);
53 resultTupleSlot = node->ps.ps_ResultTupleSlot;
54 tupDesc = ExecGetResultType(&node->ps);
57 * now loop, returning only non-duplicate tuples. We assume that the
58 * tuples arrive in sorted order so we can detect duplicates easily.
60 * We return the first tuple from each group of duplicates (or the last
61 * tuple of each group, when moving backwards). At either end of the
62 * subplan, clear priorTuple so that we correctly return the
63 * first/last tuple when reversing direction.
68 * fetch a tuple from the outer subplan
70 slot = ExecProcNode(outerPlan);
73 /* end of subplan; reset in case we change direction */
74 if (node->priorTuple != NULL)
75 heap_freetuple(node->priorTuple);
76 node->priorTuple = NULL;
81 * Always return the first/last tuple from the subplan.
83 if (node->priorTuple == NULL)
87 * Else test if the new tuple and the previously returned tuple
88 * match. If so then we loop back and fetch another new tuple
91 if (!execTuplesMatch(slot->val, node->priorTuple,
93 plannode->numCols, plannode->uniqColIdx,
100 * We have a new tuple different from the previous saved tuple (if
101 * any). Save it and return it. We must copy it because the source
102 * subplan won't guarantee that this source tuple is still accessible
103 * after fetching the next source tuple.
105 * Note that we manage the copy ourselves. We can't rely on the result
106 * tuple slot to maintain the tuple reference because our caller may
107 * replace the slot contents with a different tuple. We assume that
108 * the caller will no longer be interested in the current tuple after
111 * tgl 3/2004: the above concern is no longer valid; junkfilters used to
112 * modify their input's return slot but don't anymore, and I don't think
113 * anyplace else does either. Not worth changing this code though.
115 if (node->priorTuple != NULL)
116 heap_freetuple(node->priorTuple);
117 node->priorTuple = heap_copytuple(slot->val);
119 ExecStoreTuple(node->priorTuple,
122 false); /* tuple does not belong to slot */
124 return resultTupleSlot;
127 /* ----------------------------------------------------------------
130 * This initializes the unique node state structures and
131 * the node's subplan.
132 * ----------------------------------------------------------------
135 ExecInitUnique(Unique *node, EState *estate)
137 UniqueState *uniquestate;
140 * create state structure
142 uniquestate = makeNode(UniqueState);
143 uniquestate->ps.plan = (Plan *) node;
144 uniquestate->ps.state = estate;
146 uniquestate->priorTuple = NULL;
149 * Miscellaneous initialization
151 * Unique nodes have no ExprContext initialization because they never
152 * call ExecQual or ExecProject. But they do need a per-tuple memory
153 * context anyway for calling execTuplesMatch.
155 uniquestate->tempContext =
156 AllocSetContextCreate(CurrentMemoryContext,
158 ALLOCSET_DEFAULT_MINSIZE,
159 ALLOCSET_DEFAULT_INITSIZE,
160 ALLOCSET_DEFAULT_MAXSIZE);
162 #define UNIQUE_NSLOTS 1
165 * Tuple table initialization
167 ExecInitResultTupleSlot(estate, &uniquestate->ps);
170 * then initialize outer plan
172 outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate);
175 * unique nodes do no projections, so initialize projection info for
176 * this node appropriately
178 ExecAssignResultTypeFromOuterPlan(&uniquestate->ps);
179 uniquestate->ps.ps_ProjInfo = NULL;
182 * Precompute fmgr lookup data for inner loop
184 uniquestate->eqfunctions =
185 execTuplesMatchPrepare(ExecGetResultType(&uniquestate->ps),
193 ExecCountSlotsUnique(Unique *node)
195 return ExecCountSlotsNode(outerPlan(node)) +
196 ExecCountSlotsNode(innerPlan(node)) +
200 /* ----------------------------------------------------------------
203 * This shuts down the subplan and frees resources allocated
205 * ----------------------------------------------------------------
208 ExecEndUnique(UniqueState *node)
210 /* clean up tuple table */
211 ExecClearTuple(node->ps.ps_ResultTupleSlot);
213 MemoryContextDelete(node->tempContext);
215 ExecEndNode(outerPlanState(node));
220 ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt)
222 ExecClearTuple(node->ps.ps_ResultTupleSlot);
223 if (node->priorTuple != NULL)
225 heap_freetuple(node->priorTuple);
226 node->priorTuple = NULL;
230 * if chgParam of subnode is not null then plan will be re-scanned by
231 * first ExecProcNode.
233 if (((PlanState *) node)->lefttree->chgParam == NULL)
234 ExecReScan(((PlanState *) node)->lefttree, exprCtxt);