Branch data 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-2026, 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 : :
40 : :
41 : : /* ----------------------------------------------------------------
42 : : * ExecUnique
43 : : * ----------------------------------------------------------------
44 : : */
45 : : static TupleTableSlot * /* return: a tuple or NULL */
46 : 15697 : ExecUnique(PlanState *pstate)
47 : : {
48 : 15697 : UniqueState *node = castNode(UniqueState, pstate);
49 : 15697 : ExprContext *econtext = node->ps.ps_ExprContext;
50 : 15697 : TupleTableSlot *resultTupleSlot;
51 : 15697 : TupleTableSlot *slot;
52 : 15697 : PlanState *outerPlan;
53 : :
54 [ + - ]: 15697 : CHECK_FOR_INTERRUPTS();
55 : :
56 : : /*
57 : : * get information from the node
58 : : */
59 : 15697 : outerPlan = outerPlanState(node);
60 : 15697 : resultTupleSlot = node->ps.ps_ResultTupleSlot;
61 : :
62 : : /*
63 : : * now loop, returning only non-duplicate tuples. We assume that the
64 : : * tuples arrive in sorted order so we can detect duplicates easily. The
65 : : * first tuple of each group is returned.
66 : : */
67 : 114268 : for (;;)
68 : : {
69 : : /*
70 : : * fetch a tuple from the outer subplan
71 : : */
72 : 114268 : slot = ExecProcNode(outerPlan);
73 [ + + + + ]: 114268 : if (TupIsNull(slot))
74 : : {
75 : : /* end of subplan, so we're done */
76 : 641 : ExecClearTuple(resultTupleSlot);
77 : 641 : return NULL;
78 : : }
79 : :
80 : : /*
81 : : * Always return the first tuple from the subplan.
82 : : */
83 [ + - + + ]: 113627 : if (TupIsNull(resultTupleSlot))
84 : 143 : break;
85 : :
86 : : /*
87 : : * Else test if the new tuple and the previously returned tuple match.
88 : : * If so then we loop back and fetch another new tuple from the
89 : : * subplan.
90 : : */
91 : 113484 : econtext->ecxt_innertuple = slot;
92 : 113484 : econtext->ecxt_outertuple = resultTupleSlot;
93 [ + + ]: 113484 : if (!ExecQualAndReset(node->eqfunction, econtext))
94 : 14913 : break;
95 : : }
96 : :
97 : : /*
98 : : * We have a new tuple different from the previous saved tuple (if any).
99 : : * Save it and return it. We must copy it because the source subplan
100 : : * won't guarantee that this source tuple is still accessible after
101 : : * fetching the next source tuple.
102 : : */
103 : 15056 : return ExecCopySlot(resultTupleSlot, slot);
104 : 15697 : }
105 : :
106 : : /* ----------------------------------------------------------------
107 : : * ExecInitUnique
108 : : *
109 : : * This initializes the unique node state structures and
110 : : * the node's subplan.
111 : : * ----------------------------------------------------------------
112 : : */
113 : : UniqueState *
114 : 712 : ExecInitUnique(Unique *node, EState *estate, int eflags)
115 : : {
116 : 712 : UniqueState *uniquestate;
117 : :
118 : : /* check for unsupported flags */
119 [ + - ]: 712 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
120 : :
121 : : /*
122 : : * create state structure
123 : : */
124 : 712 : uniquestate = makeNode(UniqueState);
125 : 712 : uniquestate->ps.plan = (Plan *) node;
126 : 712 : uniquestate->ps.state = estate;
127 : 712 : uniquestate->ps.ExecProcNode = ExecUnique;
128 : :
129 : : /*
130 : : * create expression context
131 : : */
132 : 712 : ExecAssignExprContext(estate, &uniquestate->ps);
133 : :
134 : : /*
135 : : * then initialize outer plan
136 : : */
137 : 712 : outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate, eflags);
138 : :
139 : : /*
140 : : * Initialize result slot and type. Unique nodes do no projections, so
141 : : * initialize projection info for this node appropriately.
142 : : */
143 : 712 : ExecInitResultTupleSlotTL(&uniquestate->ps, &TTSOpsMinimalTuple);
144 : 712 : uniquestate->ps.ps_ProjInfo = NULL;
145 : :
146 : : /*
147 : : * Precompute fmgr lookup data for inner loop
148 : : */
149 : 712 : uniquestate->eqfunction =
150 : 1424 : execTuplesMatchPrepare(ExecGetResultType(outerPlanState(uniquestate)),
151 : 712 : node->numCols,
152 : 712 : node->uniqColIdx,
153 : 712 : node->uniqOperators,
154 : 712 : node->uniqCollations,
155 : 712 : &uniquestate->ps);
156 : :
157 : 1424 : return uniquestate;
158 : 712 : }
159 : :
160 : : /* ----------------------------------------------------------------
161 : : * ExecEndUnique
162 : : *
163 : : * This shuts down the subplan and frees resources allocated
164 : : * to this node.
165 : : * ----------------------------------------------------------------
166 : : */
167 : : void
168 : 712 : ExecEndUnique(UniqueState *node)
169 : : {
170 : 712 : ExecEndNode(outerPlanState(node));
171 : 712 : }
172 : :
173 : :
174 : : void
175 : 6 : ExecReScanUnique(UniqueState *node)
176 : : {
177 : 6 : PlanState *outerPlan = outerPlanState(node);
178 : :
179 : : /* must clear result tuple so first input tuple is returned */
180 : 6 : ExecClearTuple(node->ps.ps_ResultTupleSlot);
181 : :
182 : : /*
183 : : * if chgParam of subnode is not null then plan will be re-scanned by
184 : : * first ExecProcNode.
185 : : */
186 [ - + ]: 6 : if (outerPlan->chgParam == NULL)
187 : 6 : ExecReScan(outerPlan);
188 : 6 : }
|