]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeUnique.c
Update obsolete comment.
[postgresql] / src / backend / executor / nodeUnique.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeUnique.c
4  *        Routines to handle unique'ing of queries where appropriate
5  *
6  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/executor/nodeUnique.c,v 1.42 2004/03/02 22:05:24 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  * INTERFACE ROUTINES
17  *              ExecUnique              - generate a unique'd temporary relation
18  *              ExecInitUnique  - initialize node and subnodes..
19  *              ExecEndUnique   - shutdown node and subnodes
20  *
21  * NOTES
22  *              Assumes tuples returned from subplan arrive in
23  *              sorted order.
24  */
25
26 #include "postgres.h"
27
28 #include "access/heapam.h"
29 #include "executor/executor.h"
30 #include "executor/nodeUnique.h"
31
32
33 /* ----------------------------------------------------------------
34  *              ExecUnique
35  *
36  *              This is a very simple node which filters out duplicate
37  *              tuples from a stream of sorted tuples from a subplan.
38  * ----------------------------------------------------------------
39  */
40 TupleTableSlot *                                /* return: a tuple or NULL */
41 ExecUnique(UniqueState *node)
42 {
43         Unique     *plannode = (Unique *) node->ps.plan;
44         TupleTableSlot *resultTupleSlot;
45         TupleTableSlot *slot;
46         PlanState  *outerPlan;
47         TupleDesc       tupDesc;
48
49         /*
50          * get information from the node
51          */
52         outerPlan = outerPlanState(node);
53         resultTupleSlot = node->ps.ps_ResultTupleSlot;
54         tupDesc = ExecGetResultType(&node->ps);
55
56         /*
57          * now loop, returning only non-duplicate tuples. We assume that the
58          * tuples arrive in sorted order so we can detect duplicates easily.
59          *
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.
64          */
65         for (;;)
66         {
67                 /*
68                  * fetch a tuple from the outer subplan
69                  */
70                 slot = ExecProcNode(outerPlan);
71                 if (TupIsNull(slot))
72                 {
73                         /* end of subplan; reset in case we change direction */
74                         if (node->priorTuple != NULL)
75                                 heap_freetuple(node->priorTuple);
76                         node->priorTuple = NULL;
77                         return NULL;
78                 }
79
80                 /*
81                  * Always return the first/last tuple from the subplan.
82                  */
83                 if (node->priorTuple == NULL)
84                         break;
85
86                 /*
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
89                  * from the subplan.
90                  */
91                 if (!execTuplesMatch(slot->val, node->priorTuple,
92                                                          tupDesc,
93                                                          plannode->numCols, plannode->uniqColIdx,
94                                                          node->eqfunctions,
95                                                          node->tempContext))
96                         break;
97         }
98
99         /*
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.
104          *
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
109          * he next calls us.
110          *
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.
114          */
115         if (node->priorTuple != NULL)
116                 heap_freetuple(node->priorTuple);
117         node->priorTuple = heap_copytuple(slot->val);
118
119         ExecStoreTuple(node->priorTuple,
120                                    resultTupleSlot,
121                                    InvalidBuffer,
122                                    false);              /* tuple does not belong to slot */
123
124         return resultTupleSlot;
125 }
126
127 /* ----------------------------------------------------------------
128  *              ExecInitUnique
129  *
130  *              This initializes the unique node state structures and
131  *              the node's subplan.
132  * ----------------------------------------------------------------
133  */
134 UniqueState *
135 ExecInitUnique(Unique *node, EState *estate)
136 {
137         UniqueState *uniquestate;
138
139         /*
140          * create state structure
141          */
142         uniquestate = makeNode(UniqueState);
143         uniquestate->ps.plan = (Plan *) node;
144         uniquestate->ps.state = estate;
145
146         uniquestate->priorTuple = NULL;
147
148         /*
149          * Miscellaneous initialization
150          *
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.
154          */
155         uniquestate->tempContext =
156                 AllocSetContextCreate(CurrentMemoryContext,
157                                                           "Unique",
158                                                           ALLOCSET_DEFAULT_MINSIZE,
159                                                           ALLOCSET_DEFAULT_INITSIZE,
160                                                           ALLOCSET_DEFAULT_MAXSIZE);
161
162 #define UNIQUE_NSLOTS 1
163
164         /*
165          * Tuple table initialization
166          */
167         ExecInitResultTupleSlot(estate, &uniquestate->ps);
168
169         /*
170          * then initialize outer plan
171          */
172         outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate);
173
174         /*
175          * unique nodes do no projections, so initialize projection info for
176          * this node appropriately
177          */
178         ExecAssignResultTypeFromOuterPlan(&uniquestate->ps);
179         uniquestate->ps.ps_ProjInfo = NULL;
180
181         /*
182          * Precompute fmgr lookup data for inner loop
183          */
184         uniquestate->eqfunctions =
185                 execTuplesMatchPrepare(ExecGetResultType(&uniquestate->ps),
186                                                            node->numCols,
187                                                            node->uniqColIdx);
188
189         return uniquestate;
190 }
191
192 int
193 ExecCountSlotsUnique(Unique *node)
194 {
195         return ExecCountSlotsNode(outerPlan(node)) +
196                 ExecCountSlotsNode(innerPlan(node)) +
197                 UNIQUE_NSLOTS;
198 }
199
200 /* ----------------------------------------------------------------
201  *              ExecEndUnique
202  *
203  *              This shuts down the subplan and frees resources allocated
204  *              to this node.
205  * ----------------------------------------------------------------
206  */
207 void
208 ExecEndUnique(UniqueState *node)
209 {
210         /* clean up tuple table */
211         ExecClearTuple(node->ps.ps_ResultTupleSlot);
212
213         MemoryContextDelete(node->tempContext);
214
215         ExecEndNode(outerPlanState(node));
216 }
217
218
219 void
220 ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt)
221 {
222         ExecClearTuple(node->ps.ps_ResultTupleSlot);
223         if (node->priorTuple != NULL)
224         {
225                 heap_freetuple(node->priorTuple);
226                 node->priorTuple = NULL;
227         }
228
229         /*
230          * if chgParam of subnode is not null then plan will be re-scanned by
231          * first ExecProcNode.
232          */
233         if (((PlanState *) node)->lefttree->chgParam == NULL)
234                 ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
235 }