]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeUnique.c
Update misleading comment about the use of lanpltrusted ... it is
[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-2005, 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.46 2005/03/16 21:38:08 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
48         /*
49          * get information from the node
50          */
51         outerPlan = outerPlanState(node);
52         resultTupleSlot = node->ps.ps_ResultTupleSlot;
53
54         /*
55          * now loop, returning only non-duplicate tuples. We assume that the
56          * tuples arrive in sorted order so we can detect duplicates easily.
57          *
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.
62          */
63         for (;;)
64         {
65                 /*
66                  * fetch a tuple from the outer subplan
67                  */
68                 slot = ExecProcNode(outerPlan);
69                 if (TupIsNull(slot))
70                 {
71                         /* end of subplan; reset in case we change direction */
72                         ExecClearTuple(resultTupleSlot);
73                         return NULL;
74                 }
75
76                 /*
77                  * Always return the first/last tuple from the subplan.
78                  */
79                 if (TupIsNull(resultTupleSlot))
80                         break;
81
82                 /*
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
85                  * from the subplan.
86                  */
87                 if (!execTuplesMatch(slot, resultTupleSlot,
88                                                          plannode->numCols, plannode->uniqColIdx,
89                                                          node->eqfunctions,
90                                                          node->tempContext))
91                         break;
92         }
93
94         /*
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.
99          */
100         return ExecCopySlot(resultTupleSlot, slot);
101 }
102
103 /* ----------------------------------------------------------------
104  *              ExecInitUnique
105  *
106  *              This initializes the unique node state structures and
107  *              the node's subplan.
108  * ----------------------------------------------------------------
109  */
110 UniqueState *
111 ExecInitUnique(Unique *node, EState *estate)
112 {
113         UniqueState *uniquestate;
114
115         /*
116          * create state structure
117          */
118         uniquestate = makeNode(UniqueState);
119         uniquestate->ps.plan = (Plan *) node;
120         uniquestate->ps.state = estate;
121
122         /*
123          * Miscellaneous initialization
124          *
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.
128          */
129         uniquestate->tempContext =
130                 AllocSetContextCreate(CurrentMemoryContext,
131                                                           "Unique",
132                                                           ALLOCSET_DEFAULT_MINSIZE,
133                                                           ALLOCSET_DEFAULT_INITSIZE,
134                                                           ALLOCSET_DEFAULT_MAXSIZE);
135
136 #define UNIQUE_NSLOTS 1
137
138         /*
139          * Tuple table initialization
140          */
141         ExecInitResultTupleSlot(estate, &uniquestate->ps);
142
143         /*
144          * then initialize outer plan
145          */
146         outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate);
147
148         /*
149          * unique nodes do no projections, so initialize projection info for
150          * this node appropriately
151          */
152         ExecAssignResultTypeFromOuterPlan(&uniquestate->ps);
153         uniquestate->ps.ps_ProjInfo = NULL;
154
155         /*
156          * Precompute fmgr lookup data for inner loop
157          */
158         uniquestate->eqfunctions =
159                 execTuplesMatchPrepare(ExecGetResultType(&uniquestate->ps),
160                                                            node->numCols,
161                                                            node->uniqColIdx);
162
163         return uniquestate;
164 }
165
166 int
167 ExecCountSlotsUnique(Unique *node)
168 {
169         return ExecCountSlotsNode(outerPlan(node)) +
170                 ExecCountSlotsNode(innerPlan(node)) +
171                 UNIQUE_NSLOTS;
172 }
173
174 /* ----------------------------------------------------------------
175  *              ExecEndUnique
176  *
177  *              This shuts down the subplan and frees resources allocated
178  *              to this node.
179  * ----------------------------------------------------------------
180  */
181 void
182 ExecEndUnique(UniqueState *node)
183 {
184         /* clean up tuple table */
185         ExecClearTuple(node->ps.ps_ResultTupleSlot);
186
187         MemoryContextDelete(node->tempContext);
188
189         ExecEndNode(outerPlanState(node));
190 }
191
192
193 void
194 ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt)
195 {
196         /* must clear result tuple so first input tuple is returned */
197         ExecClearTuple(node->ps.ps_ResultTupleSlot);
198
199         /*
200          * if chgParam of subnode is not null then plan will be re-scanned by
201          * first ExecProcNode.
202          */
203         if (((PlanState *) node)->lefttree->chgParam == NULL)
204                 ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
205 }