Line data Source code
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 */
47 551 : ExecUnique(PlanState *pstate)
48 : {
49 551 : UniqueState *node = castNode(UniqueState, pstate);
50 551 : Unique *plannode = (Unique *) node->ps.plan;
51 : TupleTableSlot *resultTupleSlot;
52 : TupleTableSlot *slot;
53 : PlanState *outerPlan;
54 :
55 551 : CHECK_FOR_INTERRUPTS();
56 :
57 : /*
58 : * get information from the node
59 : */
60 551 : outerPlan = outerPlanState(node);
61 551 : 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 23911 : slot = ExecProcNode(outerPlan);
74 23911 : if (TupIsNull(slot))
75 : {
76 : /* end of subplan, so we're done */
77 48 : ExecClearTuple(resultTupleSlot);
78 48 : return NULL;
79 : }
80 :
81 : /*
82 : * Always return the first tuple from the subplan.
83 : */
84 23863 : 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 23820 : if (!execTuplesMatch(slot, resultTupleSlot,
93 : plannode->numCols, plannode->uniqColIdx,
94 : node->eqfunctions,
95 : node->tempContext))
96 460 : break;
97 23360 : }
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 503 : 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 *
116 53 : ExecInitUnique(Unique *node, EState *estate, int eflags)
117 : {
118 : UniqueState *uniquestate;
119 :
120 : /* check for unsupported flags */
121 53 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
122 :
123 : /*
124 : * create state structure
125 : */
126 53 : uniquestate = makeNode(UniqueState);
127 53 : uniquestate->ps.plan = (Plan *) node;
128 53 : uniquestate->ps.state = estate;
129 53 : 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 53 : uniquestate->tempContext =
139 53 : AllocSetContextCreate(CurrentMemoryContext,
140 : "Unique",
141 : ALLOCSET_DEFAULT_SIZES);
142 :
143 : /*
144 : * Tuple table initialization
145 : */
146 53 : ExecInitResultTupleSlot(estate, &uniquestate->ps);
147 :
148 : /*
149 : * then initialize outer plan
150 : */
151 53 : 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 53 : ExecAssignResultTypeFromTL(&uniquestate->ps);
158 53 : uniquestate->ps.ps_ProjInfo = NULL;
159 :
160 : /*
161 : * Precompute fmgr lookup data for inner loop
162 : */
163 53 : uniquestate->eqfunctions =
164 53 : execTuplesMatchPrepare(node->numCols,
165 : node->uniqOperators);
166 :
167 53 : 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
178 53 : ExecEndUnique(UniqueState *node)
179 : {
180 : /* clean up tuple table */
181 53 : ExecClearTuple(node->ps.ps_ResultTupleSlot);
182 :
183 53 : MemoryContextDelete(node->tempContext);
184 :
185 53 : ExecEndNode(outerPlanState(node));
186 53 : }
187 :
188 :
189 : void
190 0 : ExecReScanUnique(UniqueState *node)
191 : {
192 : /* must clear result tuple so first input tuple is returned */
193 0 : 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 0 : if (node->ps.lefttree->chgParam == NULL)
200 0 : ExecReScan(node->ps.lefttree);
201 0 : }
|