1 /*-------------------------------------------------------------------------
4 * Routines to handle unique'ing of queries where appropriate
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
14 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
15 * Portions Copyright (c) 1994, Regents of the University of California
21 *-------------------------------------------------------------------------
25 * ExecUnique - generate a unique'd temporary relation
26 * ExecInitUnique - initialize node and subnodes
27 * ExecEndUnique - shutdown node and subnodes
30 * Assumes tuples returned from subplan arrive in
36 #include "executor/executor.h"
37 #include "executor/nodeUnique.h"
38 #include "utils/memutils.h"
41 /* ----------------------------------------------------------------
43 * ----------------------------------------------------------------
45 TupleTableSlot
* /* return: a tuple or NULL */
46 ExecUnique(UniqueState
*node
)
48 Unique
*plannode
= (Unique
*) node
->ps
.plan
;
49 TupleTableSlot
*resultTupleSlot
;
54 * get information from the node
56 outerPlan
= outerPlanState(node
);
57 resultTupleSlot
= node
->ps
.ps_ResultTupleSlot
;
60 * now loop, returning only non-duplicate tuples. We assume that the
61 * tuples arrive in sorted order so we can detect duplicates easily.
62 * The first tuple of each group is returned.
67 * fetch a tuple from the outer subplan
69 slot
= ExecProcNode(outerPlan
);
72 /* end of subplan, so we're done */
73 ExecClearTuple(resultTupleSlot
);
78 * Always return the first tuple from the subplan.
80 if (TupIsNull(resultTupleSlot
))
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
88 if (!execTuplesMatch(slot
, resultTupleSlot
,
89 plannode
->numCols
, plannode
->uniqColIdx
,
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.
101 return ExecCopySlot(resultTupleSlot
, slot
);
104 /* ----------------------------------------------------------------
107 * This initializes the unique node state structures and
108 * the node's subplan.
109 * ----------------------------------------------------------------
112 ExecInitUnique(Unique
*node
, EState
*estate
, int eflags
)
114 UniqueState
*uniquestate
;
116 /* check for unsupported flags */
117 Assert(!(eflags
& (EXEC_FLAG_BACKWARD
| EXEC_FLAG_MARK
)));
120 * create state structure
122 uniquestate
= makeNode(UniqueState
);
123 uniquestate
->ps
.plan
= (Plan
*) node
;
124 uniquestate
->ps
.state
= estate
;
127 * Miscellaneous initialization
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.
133 uniquestate
->tempContext
=
134 AllocSetContextCreate(CurrentMemoryContext
,
136 ALLOCSET_DEFAULT_MINSIZE
,
137 ALLOCSET_DEFAULT_INITSIZE
,
138 ALLOCSET_DEFAULT_MAXSIZE
);
140 #define UNIQUE_NSLOTS 1
143 * Tuple table initialization
145 ExecInitResultTupleSlot(estate
, &uniquestate
->ps
);
148 * then initialize outer plan
150 outerPlanState(uniquestate
) = ExecInitNode(outerPlan(node
), estate
, eflags
);
153 * unique nodes do no projections, so initialize projection info for this
156 ExecAssignResultTypeFromTL(&uniquestate
->ps
);
157 uniquestate
->ps
.ps_ProjInfo
= NULL
;
160 * Precompute fmgr lookup data for inner loop
162 uniquestate
->eqfunctions
=
163 execTuplesMatchPrepare(node
->numCols
,
164 node
->uniqOperators
);
170 ExecCountSlotsUnique(Unique
*node
)
172 return ExecCountSlotsNode(outerPlan(node
)) +
173 ExecCountSlotsNode(innerPlan(node
)) +
177 /* ----------------------------------------------------------------
180 * This shuts down the subplan and frees resources allocated
182 * ----------------------------------------------------------------
185 ExecEndUnique(UniqueState
*node
)
187 /* clean up tuple table */
188 ExecClearTuple(node
->ps
.ps_ResultTupleSlot
);
190 MemoryContextDelete(node
->tempContext
);
192 ExecEndNode(outerPlanState(node
));
197 ExecReScanUnique(UniqueState
*node
, ExprContext
*exprCtxt
)
199 /* must clear result tuple so first input tuple is returned */
200 ExecClearTuple(node
->ps
.ps_ResultTupleSlot
);
203 * if chgParam of subnode is not null then plan will be re-scanned by
204 * first ExecProcNode.
206 if (((PlanState
*) node
)->lefttree
->chgParam
== NULL
)
207 ExecReScan(((PlanState
*) node
)->lefttree
, exprCtxt
);