Age Owner TLA 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-2023, 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 */
2092 andres 47 CBC 41396 : ExecUnique(PlanState *pstate)
48 : {
49 41396 : UniqueState *node = castNode(UniqueState, pstate);
1879 50 41396 : ExprContext *econtext = node->ps.ps_ExprContext;
51 : TupleTableSlot *resultTupleSlot;
52 : TupleTableSlot *slot;
53 : PlanState *outerPlan;
54 :
2084 55 41396 : CHECK_FOR_INTERRUPTS();
56 :
57 : /*
58 : * get information from the node
59 : */
7430 tgl 60 41396 : outerPlan = outerPlanState(node);
61 41396 : 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 198736 : slot = ExecProcNode(outerPlan);
9345 bruce 74 198736 : if (TupIsNull(slot))
75 : {
76 : /* end of subplan, so we're done */
6598 tgl 77 678 : ExecClearTuple(resultTupleSlot);
9345 bruce 78 678 : return NULL;
79 : }
80 :
81 : /*
82 : * Always return the first tuple from the subplan.
83 : */
6598 tgl 84 198058 : 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 : */
1879 andres 92 197419 : econtext->ecxt_innertuple = slot;
93 197419 : econtext->ecxt_outertuple = resultTupleSlot;
94 197419 : if (!ExecQualAndReset(node->eqfunction, econtext))
8473 tgl 95 40079 : break;
96 : }
97 :
98 : /*
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.
103 : */
6598 104 40718 : return ExecCopySlot(resultTupleSlot, slot);
105 : }
106 :
107 : /* ----------------------------------------------------------------
108 : * ExecInitUnique
109 : *
110 : * This initializes the unique node state structures and
111 : * the node's subplan.
112 : * ----------------------------------------------------------------
113 : */
114 : UniqueState *
6249 115 793 : ExecInitUnique(Unique *node, EState *estate, int eflags)
116 : {
117 : UniqueState *uniquestate;
118 :
119 : /* check for unsupported flags */
5360 120 793 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
121 :
122 : /*
123 : * create state structure
124 : */
9345 bruce 125 793 : uniquestate = makeNode(UniqueState);
7430 tgl 126 793 : uniquestate->ps.plan = (Plan *) node;
127 793 : uniquestate->ps.state = estate;
2092 andres 128 793 : uniquestate->ps.ExecProcNode = ExecUnique;
129 :
130 : /*
131 : * create expression context
132 : */
1879 133 793 : ExecAssignExprContext(estate, &uniquestate->ps);
134 :
135 : /*
136 : * then initialize outer plan
137 : */
6249 tgl 138 793 : outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate, eflags);
139 :
140 : /*
141 : * Initialize result slot and type. Unique nodes do no projections, so
142 : * initialize projection info for this node appropriately.
143 : */
1606 andres 144 793 : ExecInitResultTupleSlotTL(&uniquestate->ps, &TTSOpsMinimalTuple);
7430 tgl 145 793 : uniquestate->ps.ps_ProjInfo = NULL;
146 :
147 : /*
148 : * Precompute fmgr lookup data for inner loop
149 : */
1879 andres 150 793 : uniquestate->eqfunction =
151 793 : execTuplesMatchPrepare(ExecGetResultType(outerPlanState(uniquestate)),
152 : node->numCols,
153 793 : node->uniqColIdx,
154 793 : node->uniqOperators,
1479 peter 155 793 : node->uniqCollations,
156 : &uniquestate->ps);
157 :
7430 tgl 158 793 : return uniquestate;
159 : }
160 :
161 : /* ----------------------------------------------------------------
162 : * ExecEndUnique
163 : *
164 : * This shuts down the subplan and frees resources allocated
165 : * to this node.
166 : * ----------------------------------------------------------------
167 : */
168 : void
169 793 : ExecEndUnique(UniqueState *node)
170 : {
171 : /* clean up tuple table */
172 793 : ExecClearTuple(node->ps.ps_ResultTupleSlot);
173 :
1879 andres 174 793 : ExecFreeExprContext(&node->ps);
175 :
7420 tgl 176 793 : ExecEndNode(outerPlanState(node));
9345 bruce 177 793 : }
178 :
179 :
180 : void
4654 tgl 181 UBC 0 : ExecReScanUnique(UniqueState *node)
182 : {
276 tgl 183 UNC 0 : PlanState *outerPlan = outerPlanState(node);
184 :
6598 tgl 185 EUB : /* must clear result tuple so first input tuple is returned */
7430 tgl 186 UIC 0 : ExecClearTuple(node->ps.ps_ResultTupleSlot);
187 :
9173 bruce 188 EUB : /*
189 : * if chgParam of subnode is not null then plan will be re-scanned by
190 : * first ExecProcNode.
191 : */
276 tgl 192 UNC 0 : if (outerPlan->chgParam == NULL)
193 0 : ExecReScan(outerPlan);
9176 vadim4o 194 UBC 0 : }
|