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 53757 : ExecUnique(PlanState *pstate)
47 : {
48 53757 : UniqueState *node = castNode(UniqueState, pstate);
49 53757 : ExprContext *econtext = node->ps.ps_ExprContext;
50 : TupleTableSlot *resultTupleSlot;
51 : TupleTableSlot *slot;
52 : PlanState *outerPlan;
53 :
54 53757 : CHECK_FOR_INTERRUPTS();
55 :
56 : /*
57 : * get information from the node
58 : */
59 53757 : outerPlan = outerPlanState(node);
60 53757 : 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 : for (;;)
68 : {
69 : /*
70 : * fetch a tuple from the outer subplan
71 : */
72 356038 : slot = ExecProcNode(outerPlan);
73 356038 : if (TupIsNull(slot))
74 : {
75 : /* end of subplan, so we're done */
76 2712 : ExecClearTuple(resultTupleSlot);
77 2712 : return NULL;
78 : }
79 :
80 : /*
81 : * Always return the first tuple from the subplan.
82 : */
83 353326 : if (TupIsNull(resultTupleSlot))
84 : 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 352193 : econtext->ecxt_innertuple = slot;
92 352193 : econtext->ecxt_outertuple = resultTupleSlot;
93 352193 : if (!ExecQualAndReset(node->eqfunction, econtext))
94 49912 : 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 51045 : return ExecCopySlot(resultTupleSlot, slot);
104 : }
105 :
106 : /* ----------------------------------------------------------------
107 : * ExecInitUnique
108 : *
109 : * This initializes the unique node state structures and
110 : * the node's subplan.
111 : * ----------------------------------------------------------------
112 : */
113 : UniqueState *
114 2968 : ExecInitUnique(Unique *node, EState *estate, int eflags)
115 : {
116 : UniqueState *uniquestate;
117 :
118 : /* check for unsupported flags */
119 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
120 :
121 : /*
122 : * create state structure
123 : */
124 2968 : uniquestate = makeNode(UniqueState);
125 2968 : uniquestate->ps.plan = (Plan *) node;
126 2968 : uniquestate->ps.state = estate;
127 2968 : uniquestate->ps.ExecProcNode = ExecUnique;
128 :
129 : /*
130 : * create expression context
131 : */
132 2968 : ExecAssignExprContext(estate, &uniquestate->ps);
133 :
134 : /*
135 : * then initialize outer plan
136 : */
137 2968 : 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 2968 : ExecInitResultTupleSlotTL(&uniquestate->ps, &TTSOpsMinimalTuple);
144 2968 : uniquestate->ps.ps_ProjInfo = NULL;
145 :
146 : /*
147 : * Precompute fmgr lookup data for inner loop
148 : */
149 2968 : uniquestate->eqfunction =
150 2968 : execTuplesMatchPrepare(ExecGetResultType(outerPlanState(uniquestate)),
151 : node->numCols,
152 2968 : node->uniqColIdx,
153 2968 : node->uniqOperators,
154 2968 : node->uniqCollations,
155 : &uniquestate->ps);
156 :
157 2968 : return uniquestate;
158 : }
159 :
160 : /* ----------------------------------------------------------------
161 : * ExecEndUnique
162 : *
163 : * This shuts down the subplan and frees resources allocated
164 : * to this node.
165 : * ----------------------------------------------------------------
166 : */
167 : void
168 2968 : ExecEndUnique(UniqueState *node)
169 : {
170 2968 : ExecEndNode(outerPlanState(node));
171 2968 : }
172 :
173 :
174 : void
175 18 : ExecReScanUnique(UniqueState *node)
176 : {
177 18 : PlanState *outerPlan = outerPlanState(node);
178 :
179 : /* must clear result tuple so first input tuple is returned */
180 18 : 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 18 : if (outerPlan->chgParam == NULL)
187 18 : ExecReScan(outerPlan);
188 18 : }
|