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 "miscadmin.h"
39 #include "utils/memutils.h"
40
41
42 /* ----------------------------------------------------------------
43 * ExecUnique
44 * ----------------------------------------------------------------
45 */
46 static TupleTableSlot * /* return: a tuple or NULL */
ExecUnique(PlanState * pstate)47 ExecUnique(PlanState *pstate)
48 {
49 UniqueState *node = castNode(UniqueState, pstate);
50 Unique *plannode = (Unique *) node->ps.plan;
51 TupleTableSlot *resultTupleSlot;
52 TupleTableSlot *slot;
53 PlanState *outerPlan;
54
55 CHECK_FOR_INTERRUPTS();
56
57 /*
58 * get information from the node
59 */
60 outerPlan = outerPlanState(node);
61 resultTupleSlot = node->ps.ps_ResultTupleSlot;
62
63 /*
64 * now loop, returning only non-duplicate tuples. We assume that the
65 * tuples arrive in sorted order so we can detect duplicates easily. The
66 * first tuple of each group is returned.
67 */
68 for (;;)
69 {
70 /*
71 * fetch a tuple from the outer subplan
72 */
73 slot = ExecProcNode(outerPlan);
74 if (TupIsNull(slot))
75 {
76 /* end of subplan, so we're done */
77 ExecClearTuple(resultTupleSlot);
78 return NULL;
79 }
80
81 /*
82 * Always return the first tuple from the subplan.
83 */
84 if (TupIsNull(resultTupleSlot))
85 break;
86
87 /*
88 * Else test if the new tuple and the previously returned tuple match.
89 * If so then we loop back and fetch another new tuple from the
90 * subplan.
91 */
92 if (!execTuplesMatch(slot, resultTupleSlot,
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 any).
101 * Save it and return it. We must copy it because the source subplan
102 * won't guarantee that this source tuple is still accessible after
103 * fetching the next source tuple.
104 */
105 return ExecCopySlot(resultTupleSlot, slot);
106 }
107
108 /* ----------------------------------------------------------------
109 * ExecInitUnique
110 *
111 * This initializes the unique node state structures and
112 * the node's subplan.
113 * ----------------------------------------------------------------
114 */
115 UniqueState *
ExecInitUnique(Unique * node,EState * estate,int eflags)116 ExecInitUnique(Unique *node, EState *estate, int eflags)
117 {
118 UniqueState *uniquestate;
119
120 /* check for unsupported flags */
121 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
122
123 /*
124 * create state structure
125 */
126 uniquestate = makeNode(UniqueState);
127 uniquestate->ps.plan = (Plan *) node;
128 uniquestate->ps.state = estate;
129 uniquestate->ps.ExecProcNode = ExecUnique;
130
131 /*
132 * Miscellaneous initialization
133 *
134 * Unique nodes have no ExprContext initialization because they never call
135 * ExecQual or ExecProject. But they do need a per-tuple memory context
136 * anyway for calling execTuplesMatch.
137 */
138 uniquestate->tempContext =
139 AllocSetContextCreate(CurrentMemoryContext,
140 "Unique",
141 ALLOCSET_DEFAULT_SIZES);
142
143 /*
144 * Tuple table initialization
145 */
146 ExecInitResultTupleSlot(estate, &uniquestate->ps);
147
148 /*
149 * then initialize outer plan
150 */
151 outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate, eflags);
152
153 /*
154 * unique nodes do no projections, so initialize projection info for this
155 * node appropriately
156 */
157 ExecAssignResultTypeFromTL(&uniquestate->ps);
158 uniquestate->ps.ps_ProjInfo = NULL;
159
160 /*
161 * Precompute fmgr lookup data for inner loop
162 */
163 uniquestate->eqfunctions =
164 execTuplesMatchPrepare(node->numCols,
165 node->uniqOperators);
166
167 return uniquestate;
168 }
169
170 /* ----------------------------------------------------------------
171 * ExecEndUnique
172 *
173 * This shuts down the subplan and frees resources allocated
174 * to this node.
175 * ----------------------------------------------------------------
176 */
177 void
ExecEndUnique(UniqueState * node)178 ExecEndUnique(UniqueState *node)
179 {
180 /* clean up tuple table */
181 ExecClearTuple(node->ps.ps_ResultTupleSlot);
182
183 MemoryContextDelete(node->tempContext);
184
185 ExecEndNode(outerPlanState(node));
186 }
187
188
189 void
ExecReScanUnique(UniqueState * node)190 ExecReScanUnique(UniqueState *node)
191 {
192 /* must clear result tuple so first input tuple is returned */
193 ExecClearTuple(node->ps.ps_ResultTupleSlot);
194
195 /*
196 * if chgParam of subnode is not null then plan will be re-scanned by
197 * first ExecProcNode.
198 */
199 if (node->ps.lefttree->chgParam == NULL)
200 ExecReScan(node->ps.lefttree);
201 }
202