Age Owner Branch data 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-2024, 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 */
2463 andres@anarazel.de 46 :CBC 55372 : ExecUnique(PlanState *pstate)
47 : : {
48 : 55372 : UniqueState *node = castNode(UniqueState, pstate);
2250 49 : 55372 : ExprContext *econtext = node->ps.ps_ExprContext;
50 : : TupleTableSlot *resultTupleSlot;
51 : : TupleTableSlot *slot;
52 : : PlanState *outerPlan;
53 : :
2455 54 [ - + ]: 55372 : CHECK_FOR_INTERRUPTS();
55 : :
56 : : /*
57 : : * get information from the node
58 : : */
7801 tgl@sss.pgh.pa.us 59 : 55372 : outerPlan = outerPlanState(node);
60 : 55372 : 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 : 221453 : slot = ExecProcNode(outerPlan);
9716 bruce@momjian.us 73 [ + + + + ]: 221453 : if (TupIsNull(slot))
74 : : {
75 : : /* end of subplan, so we're done */
6969 tgl@sss.pgh.pa.us 76 : 6914 : ExecClearTuple(resultTupleSlot);
9716 bruce@momjian.us 77 : 6914 : return NULL;
78 : : }
79 : :
80 : : /*
81 : : * Always return the first tuple from the subplan.
82 : : */
6969 tgl@sss.pgh.pa.us 83 [ + - + + ]: 214539 : 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 : : */
2250 andres@anarazel.de 91 : 208947 : econtext->ecxt_innertuple = slot;
92 : 208947 : econtext->ecxt_outertuple = resultTupleSlot;
93 [ + + ]: 208947 : if (!ExecQualAndReset(node->eqfunction, econtext))
8844 tgl@sss.pgh.pa.us 94 : 42866 : 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 : : */
6969 103 : 48458 : 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 *
6620 114 : 2336 : ExecInitUnique(Unique *node, EState *estate, int eflags)
115 : : {
116 : : UniqueState *uniquestate;
117 : :
118 : : /* check for unsupported flags */
5731 119 [ - + ]: 2336 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
120 : :
121 : : /*
122 : : * create state structure
123 : : */
9716 bruce@momjian.us 124 : 2336 : uniquestate = makeNode(UniqueState);
7801 tgl@sss.pgh.pa.us 125 : 2336 : uniquestate->ps.plan = (Plan *) node;
126 : 2336 : uniquestate->ps.state = estate;
2463 andres@anarazel.de 127 : 2336 : uniquestate->ps.ExecProcNode = ExecUnique;
128 : :
129 : : /*
130 : : * create expression context
131 : : */
2250 132 : 2336 : ExecAssignExprContext(estate, &uniquestate->ps);
133 : :
134 : : /*
135 : : * then initialize outer plan
136 : : */
6620 tgl@sss.pgh.pa.us 137 : 2336 : 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 : : */
1977 andres@anarazel.de 143 : 2336 : ExecInitResultTupleSlotTL(&uniquestate->ps, &TTSOpsMinimalTuple);
7801 tgl@sss.pgh.pa.us 144 : 2336 : uniquestate->ps.ps_ProjInfo = NULL;
145 : :
146 : : /*
147 : : * Precompute fmgr lookup data for inner loop
148 : : */
2250 andres@anarazel.de 149 : 2336 : uniquestate->eqfunction =
150 : 2336 : execTuplesMatchPrepare(ExecGetResultType(outerPlanState(uniquestate)),
151 : : node->numCols,
152 : 2336 : node->uniqColIdx,
153 : 2336 : node->uniqOperators,
1850 peter@eisentraut.org 154 : 2336 : node->uniqCollations,
155 : : &uniquestate->ps);
156 : :
7801 tgl@sss.pgh.pa.us 157 : 2336 : 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 : 2336 : ExecEndUnique(UniqueState *node)
169 : : {
7791 170 : 2336 : ExecEndNode(outerPlanState(node));
9716 bruce@momjian.us 171 : 2336 : }
172 : :
173 : :
174 : : void
5025 tgl@sss.pgh.pa.us 175 :GBC 4736 : ExecReScanUnique(UniqueState *node)
176 : : {
647 177 : 4736 : PlanState *outerPlan = outerPlanState(node);
178 : :
179 : : /* must clear result tuple so first input tuple is returned */
7801 180 : 4736 : 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 : : */
647 186 [ - + ]: 4736 : if (outerPlan->chgParam == NULL)
647 tgl@sss.pgh.pa.us 187 :UBC 0 : ExecReScan(outerPlan);
9547 vadim4o@yahoo.com 188 :GBC 4736 : }
|