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-2022, PostgreSQL Global Development Group
15 * Portions Copyright (c) 1994, Regents of the University of California
19 * src/backend/executor/nodeUnique.c
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 "miscadmin.h"
39 #include "utils/memutils.h"
42 /* ----------------------------------------------------------------
44 * ----------------------------------------------------------------
46 static TupleTableSlot
* /* return: a tuple or NULL */
47 ExecUnique(PlanState
*pstate
)
49 UniqueState
*node
= castNode(UniqueState
, pstate
);
50 ExprContext
*econtext
= node
->ps
.ps_ExprContext
;
51 TupleTableSlot
*resultTupleSlot
;
55 CHECK_FOR_INTERRUPTS();
58 * get information from the node
60 outerPlan
= outerPlanState(node
);
61 resultTupleSlot
= node
->ps
.ps_ResultTupleSlot
;
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.
71 * fetch a tuple from the outer subplan
73 slot
= ExecProcNode(outerPlan
);
76 /* end of subplan, so we're done */
77 ExecClearTuple(resultTupleSlot
);
82 * Always return the first tuple from the subplan.
84 if (TupIsNull(resultTupleSlot
))
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
92 econtext
->ecxt_innertuple
= slot
;
93 econtext
->ecxt_outertuple
= resultTupleSlot
;
94 if (!ExecQualAndReset(node
->eqfunction
, econtext
))
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.
104 return ExecCopySlot(resultTupleSlot
, slot
);
107 /* ----------------------------------------------------------------
110 * This initializes the unique node state structures and
111 * the node's subplan.
112 * ----------------------------------------------------------------
115 ExecInitUnique(Unique
*node
, EState
*estate
, int eflags
)
117 UniqueState
*uniquestate
;
119 /* check for unsupported flags */
120 Assert(!(eflags
& (EXEC_FLAG_BACKWARD
| EXEC_FLAG_MARK
)));
123 * create state structure
125 uniquestate
= makeNode(UniqueState
);
126 uniquestate
->ps
.plan
= (Plan
*) node
;
127 uniquestate
->ps
.state
= estate
;
128 uniquestate
->ps
.ExecProcNode
= ExecUnique
;
131 * create expression context
133 ExecAssignExprContext(estate
, &uniquestate
->ps
);
136 * then initialize outer plan
138 outerPlanState(uniquestate
) = ExecInitNode(outerPlan(node
), estate
, eflags
);
141 * Initialize result slot and type. Unique nodes do no projections, so
142 * initialize projection info for this node appropriately.
144 ExecInitResultTupleSlotTL(&uniquestate
->ps
, &TTSOpsMinimalTuple
);
145 uniquestate
->ps
.ps_ProjInfo
= NULL
;
148 * Precompute fmgr lookup data for inner loop
150 uniquestate
->eqfunction
=
151 execTuplesMatchPrepare(ExecGetResultType(outerPlanState(uniquestate
)),
155 node
->uniqCollations
,
161 /* ----------------------------------------------------------------
164 * This shuts down the subplan and frees resources allocated
166 * ----------------------------------------------------------------
169 ExecEndUnique(UniqueState
*node
)
171 /* clean up tuple table */
172 ExecClearTuple(node
->ps
.ps_ResultTupleSlot
);
174 ExecFreeExprContext(&node
->ps
);
176 ExecEndNode(outerPlanState(node
));
181 ExecReScanUnique(UniqueState
*node
)
183 PlanState
*outerPlan
= outerPlanState(node
);
185 /* must clear result tuple so first input tuple is returned */
186 ExecClearTuple(node
->ps
.ps_ResultTupleSlot
);
189 * if chgParam of subnode is not null then plan will be re-scanned by
190 * first ExecProcNode.
192 if (outerPlan
->chgParam
== NULL
)
193 ExecReScan(outerPlan
);