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-2019, 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 */ |
47 | ExecUnique(PlanState *pstate) |
48 | { |
49 | UniqueState *node = castNode(UniqueState, pstate); |
50 | ExprContext *econtext = node->ps.ps_ExprContext; |
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 | econtext->ecxt_innertuple = slot; |
93 | econtext->ecxt_outertuple = resultTupleSlot; |
94 | if (!ExecQualAndReset(node->eqfunction, econtext)) |
95 | break; |
96 | } |
97 | |
98 | /* |
99 | * We have a new tuple different from the previous saved tuple (if any). |
100 | * Save it and return it. We must copy it because the source subplan |
101 | * won't guarantee that this source tuple is still accessible after |
102 | * fetching the next source tuple. |
103 | */ |
104 | return ExecCopySlot(resultTupleSlot, slot); |
105 | } |
106 | |
107 | /* ---------------------------------------------------------------- |
108 | * ExecInitUnique |
109 | * |
110 | * This initializes the unique node state structures and |
111 | * the node's subplan. |
112 | * ---------------------------------------------------------------- |
113 | */ |
114 | UniqueState * |
115 | ExecInitUnique(Unique *node, EState *estate, int eflags) |
116 | { |
117 | UniqueState *uniquestate; |
118 | |
119 | /* check for unsupported flags */ |
120 | Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); |
121 | |
122 | /* |
123 | * create state structure |
124 | */ |
125 | uniquestate = makeNode(UniqueState); |
126 | uniquestate->ps.plan = (Plan *) node; |
127 | uniquestate->ps.state = estate; |
128 | uniquestate->ps.ExecProcNode = ExecUnique; |
129 | |
130 | /* |
131 | * create expression context |
132 | */ |
133 | ExecAssignExprContext(estate, &uniquestate->ps); |
134 | |
135 | /* |
136 | * then initialize outer plan |
137 | */ |
138 | outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate, eflags); |
139 | |
140 | /* |
141 | * Initialize result slot and type. Unique nodes do no projections, so |
142 | * initialize projection info for this node appropriately. |
143 | */ |
144 | ExecInitResultTupleSlotTL(&uniquestate->ps, &TTSOpsMinimalTuple); |
145 | uniquestate->ps.ps_ProjInfo = NULL; |
146 | |
147 | /* |
148 | * Precompute fmgr lookup data for inner loop |
149 | */ |
150 | uniquestate->eqfunction = |
151 | execTuplesMatchPrepare(ExecGetResultType(outerPlanState(uniquestate)), |
152 | node->numCols, |
153 | node->uniqColIdx, |
154 | node->uniqOperators, |
155 | node->uniqCollations, |
156 | &uniquestate->ps); |
157 | |
158 | return uniquestate; |
159 | } |
160 | |
161 | /* ---------------------------------------------------------------- |
162 | * ExecEndUnique |
163 | * |
164 | * This shuts down the subplan and frees resources allocated |
165 | * to this node. |
166 | * ---------------------------------------------------------------- |
167 | */ |
168 | void |
169 | ExecEndUnique(UniqueState *node) |
170 | { |
171 | /* clean up tuple table */ |
172 | ExecClearTuple(node->ps.ps_ResultTupleSlot); |
173 | |
174 | ExecFreeExprContext(&node->ps); |
175 | |
176 | ExecEndNode(outerPlanState(node)); |
177 | } |
178 | |
179 | |
180 | void |
181 | ExecReScanUnique(UniqueState *node) |
182 | { |
183 | /* must clear result tuple so first input tuple is returned */ |
184 | ExecClearTuple(node->ps.ps_ResultTupleSlot); |
185 | |
186 | /* |
187 | * if chgParam of subnode is not null then plan will be re-scanned by |
188 | * first ExecProcNode. |
189 | */ |
190 | if (node->ps.lefttree->chgParam == NULL) |
191 | ExecReScan(node->ps.lefttree); |
192 | } |
193 | |