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.45 2004-12-31 21:59:45 pgsql 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
113
* think anyplace else does either. Not worth changing this code
116
if (node->priorTuple != NULL)
117
heap_freetuple(node->priorTuple);
118
node->priorTuple = heap_copytuple(slot->val);
120
ExecStoreTuple(node->priorTuple,
123
false); /* tuple does not belong to slot */
125
return resultTupleSlot;
128
/* ----------------------------------------------------------------
131
* This initializes the unique node state structures and
132
* the node's subplan.
133
* ----------------------------------------------------------------
136
ExecInitUnique(Unique *node, EState *estate)
138
UniqueState *uniquestate;
141
* create state structure
143
uniquestate = makeNode(UniqueState);
144
uniquestate->ps.plan = (Plan *) node;
145
uniquestate->ps.state = estate;
147
uniquestate->priorTuple = NULL;
150
* Miscellaneous initialization
152
* Unique nodes have no ExprContext initialization because they never
153
* call ExecQual or ExecProject. But they do need a per-tuple memory
154
* context anyway for calling execTuplesMatch.
156
uniquestate->tempContext =
157
AllocSetContextCreate(CurrentMemoryContext,
159
ALLOCSET_DEFAULT_MINSIZE,
160
ALLOCSET_DEFAULT_INITSIZE,
161
ALLOCSET_DEFAULT_MAXSIZE);
163
#define UNIQUE_NSLOTS 1
166
* Tuple table initialization
168
ExecInitResultTupleSlot(estate, &uniquestate->ps);
171
* then initialize outer plan
173
outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate);
176
* unique nodes do no projections, so initialize projection info for
177
* this node appropriately
179
ExecAssignResultTypeFromOuterPlan(&uniquestate->ps);
180
uniquestate->ps.ps_ProjInfo = NULL;
183
* Precompute fmgr lookup data for inner loop
185
uniquestate->eqfunctions =
186
execTuplesMatchPrepare(ExecGetResultType(&uniquestate->ps),
194
ExecCountSlotsUnique(Unique *node)
196
return ExecCountSlotsNode(outerPlan(node)) +
197
ExecCountSlotsNode(innerPlan(node)) +
201
/* ----------------------------------------------------------------
204
* This shuts down the subplan and frees resources allocated
206
* ----------------------------------------------------------------
209
ExecEndUnique(UniqueState *node)
211
/* clean up tuple table */
212
ExecClearTuple(node->ps.ps_ResultTupleSlot);
214
MemoryContextDelete(node->tempContext);
216
ExecEndNode(outerPlanState(node));
221
ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt)
223
ExecClearTuple(node->ps.ps_ResultTupleSlot);
224
if (node->priorTuple != NULL)
226
heap_freetuple(node->priorTuple);
227
node->priorTuple = NULL;
231
* if chgParam of subnode is not null then plan will be re-scanned by
232
* first ExecProcNode.
234
if (((PlanState *) node)->lefttree->chgParam == NULL)
235
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);