]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeUnique.c
Faster expression evaluation and targetlist projection.
[postgresql] / src / backend / executor / nodeUnique.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeUnique.c
4  *        Routines to handle unique'ing of queries where appropriate
5  *
6  * Unique is a very simple node type that just filters out duplicate
7  * tuples from a stream of sorted tuples from its subplan.  It's essentially
8  * a dumbed-down form of Group: the duplicate-removal functionality is
9  * identical.  However, Unique doesn't do projection nor qual checking,
10  * so it's marginally more efficient for cases where neither is needed.
11  * (It's debatable whether the savings justifies carrying two plan node
12  * types, though.)
13  *
14  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
15  * Portions Copyright (c) 1994, Regents of the University of California
16  *
17  *
18  * IDENTIFICATION
19  *        src/backend/executor/nodeUnique.c
20  *
21  *-------------------------------------------------------------------------
22  */
23 /*
24  * INTERFACE ROUTINES
25  *              ExecUnique              - generate a unique'd temporary relation
26  *              ExecInitUnique  - initialize node and subnodes
27  *              ExecEndUnique   - shutdown node and subnodes
28  *
29  * NOTES
30  *              Assumes tuples returned from subplan arrive in
31  *              sorted order.
32  */
33
34 #include "postgres.h"
35
36 #include "executor/executor.h"
37 #include "executor/nodeUnique.h"
38 #include "utils/memutils.h"
39
40
41 /* ----------------------------------------------------------------
42  *              ExecUnique
43  * ----------------------------------------------------------------
44  */
45 TupleTableSlot *                                /* return: a tuple or NULL */
46 ExecUnique(UniqueState *node)
47 {
48         Unique     *plannode = (Unique *) node->ps.plan;
49         TupleTableSlot *resultTupleSlot;
50         TupleTableSlot *slot;
51         PlanState  *outerPlan;
52
53         /*
54          * get information from the node
55          */
56         outerPlan = outerPlanState(node);
57         resultTupleSlot = node->ps.ps_ResultTupleSlot;
58
59         /*
60          * now loop, returning only non-duplicate tuples. We assume that the
61          * tuples arrive in sorted order so we can detect duplicates easily. The
62          * first tuple of each group is returned.
63          */
64         for (;;)
65         {
66                 /*
67                  * fetch a tuple from the outer subplan
68                  */
69                 slot = ExecProcNode(outerPlan);
70                 if (TupIsNull(slot))
71                 {
72                         /* end of subplan, so we're done */
73                         ExecClearTuple(resultTupleSlot);
74                         return NULL;
75                 }
76
77                 /*
78                  * Always return the first tuple from the subplan.
79                  */
80                 if (TupIsNull(resultTupleSlot))
81                         break;
82
83                 /*
84                  * Else test if the new tuple and the previously returned tuple match.
85                  * If so then we loop back and fetch another new tuple from the
86                  * subplan.
87                  */
88                 if (!execTuplesMatch(slot, resultTupleSlot,
89                                                          plannode->numCols, plannode->uniqColIdx,
90                                                          node->eqfunctions,
91                                                          node->tempContext))
92                         break;
93         }
94
95         /*
96          * We have a new tuple different from the previous saved tuple (if any).
97          * Save it and return it.  We must copy it because the source subplan
98          * won't guarantee that this source tuple is still accessible after
99          * fetching the next source tuple.
100          */
101         return ExecCopySlot(resultTupleSlot, slot);
102 }
103
104 /* ----------------------------------------------------------------
105  *              ExecInitUnique
106  *
107  *              This initializes the unique node state structures and
108  *              the node's subplan.
109  * ----------------------------------------------------------------
110  */
111 UniqueState *
112 ExecInitUnique(Unique *node, EState *estate, int eflags)
113 {
114         UniqueState *uniquestate;
115
116         /* check for unsupported flags */
117         Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
118
119         /*
120          * create state structure
121          */
122         uniquestate = makeNode(UniqueState);
123         uniquestate->ps.plan = (Plan *) node;
124         uniquestate->ps.state = estate;
125
126         /*
127          * Miscellaneous initialization
128          *
129          * Unique nodes have no ExprContext initialization because they never call
130          * ExecQual or ExecProject.  But they do need a per-tuple memory context
131          * anyway for calling execTuplesMatch.
132          */
133         uniquestate->tempContext =
134                 AllocSetContextCreate(CurrentMemoryContext,
135                                                           "Unique",
136                                                           ALLOCSET_DEFAULT_SIZES);
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, eflags);
147
148         /*
149          * unique nodes do no projections, so initialize projection info for this
150          * node appropriately
151          */
152         ExecAssignResultTypeFromTL(&uniquestate->ps);
153         uniquestate->ps.ps_ProjInfo = NULL;
154
155         /*
156          * Precompute fmgr lookup data for inner loop
157          */
158         uniquestate->eqfunctions =
159                 execTuplesMatchPrepare(node->numCols,
160                                                            node->uniqOperators);
161
162         return uniquestate;
163 }
164
165 /* ----------------------------------------------------------------
166  *              ExecEndUnique
167  *
168  *              This shuts down the subplan and frees resources allocated
169  *              to this node.
170  * ----------------------------------------------------------------
171  */
172 void
173 ExecEndUnique(UniqueState *node)
174 {
175         /* clean up tuple table */
176         ExecClearTuple(node->ps.ps_ResultTupleSlot);
177
178         MemoryContextDelete(node->tempContext);
179
180         ExecEndNode(outerPlanState(node));
181 }
182
183
184 void
185 ExecReScanUnique(UniqueState *node)
186 {
187         /* must clear result tuple so first input tuple is returned */
188         ExecClearTuple(node->ps.ps_ResultTupleSlot);
189
190         /*
191          * if chgParam of subnode is not null then plan will be re-scanned by
192          * first ExecProcNode.
193          */
194         if (node->ps.lefttree->chgParam == NULL)
195                 ExecReScan(node->ps.lefttree);
196 }