~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/executor/nodeUnique.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * nodeUnique.c
 
4
 *        Routines to handle unique'ing of queries where appropriate
 
5
 *
 
6
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        $PostgreSQL: pgsql/src/backend/executor/nodeUnique.c,v 1.45 2004-12-31 21:59:45 pgsql Exp $
 
12
 *
 
13
 *-------------------------------------------------------------------------
 
14
 */
 
15
/*
 
16
 * INTERFACE ROUTINES
 
17
 *              ExecUnique              - generate a unique'd temporary relation
 
18
 *              ExecInitUnique  - initialize node and subnodes..
 
19
 *              ExecEndUnique   - shutdown node and subnodes
 
20
 *
 
21
 * NOTES
 
22
 *              Assumes tuples returned from subplan arrive in
 
23
 *              sorted order.
 
24
 */
 
25
 
 
26
#include "postgres.h"
 
27
 
 
28
#include "access/heapam.h"
 
29
#include "executor/executor.h"
 
30
#include "executor/nodeUnique.h"
 
31
 
 
32
 
 
33
/* ----------------------------------------------------------------
 
34
 *              ExecUnique
 
35
 *
 
36
 *              This is a very simple node which filters out duplicate
 
37
 *              tuples from a stream of sorted tuples from a subplan.
 
38
 * ----------------------------------------------------------------
 
39
 */
 
40
TupleTableSlot *                                /* return: a tuple or NULL */
 
41
ExecUnique(UniqueState *node)
 
42
{
 
43
        Unique     *plannode = (Unique *) node->ps.plan;
 
44
        TupleTableSlot *resultTupleSlot;
 
45
        TupleTableSlot *slot;
 
46
        PlanState  *outerPlan;
 
47
        TupleDesc       tupDesc;
 
48
 
 
49
        /*
 
50
         * get information from the node
 
51
         */
 
52
        outerPlan = outerPlanState(node);
 
53
        resultTupleSlot = node->ps.ps_ResultTupleSlot;
 
54
        tupDesc = ExecGetResultType(&node->ps);
 
55
 
 
56
        /*
 
57
         * now loop, returning only non-duplicate tuples. We assume that the
 
58
         * tuples arrive in sorted order so we can detect duplicates easily.
 
59
         *
 
60
         * We return the first tuple from each group of duplicates (or the last
 
61
         * tuple of each group, when moving backwards).  At either end of the
 
62
         * subplan, clear priorTuple so that we correctly return the
 
63
         * first/last tuple when reversing direction.
 
64
         */
 
65
        for (;;)
 
66
        {
 
67
                /*
 
68
                 * fetch a tuple from the outer subplan
 
69
                 */
 
70
                slot = ExecProcNode(outerPlan);
 
71
                if (TupIsNull(slot))
 
72
                {
 
73
                        /* end of subplan; reset in case we change direction */
 
74
                        if (node->priorTuple != NULL)
 
75
                                heap_freetuple(node->priorTuple);
 
76
                        node->priorTuple = NULL;
 
77
                        return NULL;
 
78
                }
 
79
 
 
80
                /*
 
81
                 * Always return the first/last tuple from the subplan.
 
82
                 */
 
83
                if (node->priorTuple == NULL)
 
84
                        break;
 
85
 
 
86
                /*
 
87
                 * Else test if the new tuple and the previously returned tuple
 
88
                 * match.  If so then we loop back and fetch another new tuple
 
89
                 * from the subplan.
 
90
                 */
 
91
                if (!execTuplesMatch(slot->val, node->priorTuple,
 
92
                                                         tupDesc,
 
93
                                                         plannode->numCols, plannode->uniqColIdx,
 
94
                                                         node->eqfunctions,
 
95
                                                         node->tempContext))
 
96
                        break;
 
97
        }
 
98
 
 
99
        /*
 
100
         * We have a new tuple different from the previous saved tuple (if
 
101
         * any). Save it and return it.  We must copy it because the source
 
102
         * subplan won't guarantee that this source tuple is still accessible
 
103
         * after fetching the next source tuple.
 
104
         *
 
105
         * Note that we manage the copy ourselves.      We can't rely on the result
 
106
         * tuple slot to maintain the tuple reference because our caller may
 
107
         * replace the slot contents with a different tuple.  We assume that
 
108
         * the caller will no longer be interested in the current tuple after
 
109
         * he next calls us.
 
110
         *
 
111
         * tgl 3/2004: the above concern is no longer valid; junkfilters used to
 
112
         * modify their input's return slot but don't anymore, and I don't
 
113
         * think anyplace else does either.  Not worth changing this code
 
114
         * though.
 
115
         */
 
116
        if (node->priorTuple != NULL)
 
117
                heap_freetuple(node->priorTuple);
 
118
        node->priorTuple = heap_copytuple(slot->val);
 
119
 
 
120
        ExecStoreTuple(node->priorTuple,
 
121
                                   resultTupleSlot,
 
122
                                   InvalidBuffer,
 
123
                                   false);              /* tuple does not belong to slot */
 
124
 
 
125
        return resultTupleSlot;
 
126
}
 
127
 
 
128
/* ----------------------------------------------------------------
 
129
 *              ExecInitUnique
 
130
 *
 
131
 *              This initializes the unique node state structures and
 
132
 *              the node's subplan.
 
133
 * ----------------------------------------------------------------
 
134
 */
 
135
UniqueState *
 
136
ExecInitUnique(Unique *node, EState *estate)
 
137
{
 
138
        UniqueState *uniquestate;
 
139
 
 
140
        /*
 
141
         * create state structure
 
142
         */
 
143
        uniquestate = makeNode(UniqueState);
 
144
        uniquestate->ps.plan = (Plan *) node;
 
145
        uniquestate->ps.state = estate;
 
146
 
 
147
        uniquestate->priorTuple = NULL;
 
148
 
 
149
        /*
 
150
         * Miscellaneous initialization
 
151
         *
 
152
         * Unique nodes have no ExprContext initialization because they never
 
153
         * call ExecQual or ExecProject.  But they do need a per-tuple memory
 
154
         * context anyway for calling execTuplesMatch.
 
155
         */
 
156
        uniquestate->tempContext =
 
157
                AllocSetContextCreate(CurrentMemoryContext,
 
158
                                                          "Unique",
 
159
                                                          ALLOCSET_DEFAULT_MINSIZE,
 
160
                                                          ALLOCSET_DEFAULT_INITSIZE,
 
161
                                                          ALLOCSET_DEFAULT_MAXSIZE);
 
162
 
 
163
#define UNIQUE_NSLOTS 1
 
164
 
 
165
        /*
 
166
         * Tuple table initialization
 
167
         */
 
168
        ExecInitResultTupleSlot(estate, &uniquestate->ps);
 
169
 
 
170
        /*
 
171
         * then initialize outer plan
 
172
         */
 
173
        outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate);
 
174
 
 
175
        /*
 
176
         * unique nodes do no projections, so initialize projection info for
 
177
         * this node appropriately
 
178
         */
 
179
        ExecAssignResultTypeFromOuterPlan(&uniquestate->ps);
 
180
        uniquestate->ps.ps_ProjInfo = NULL;
 
181
 
 
182
        /*
 
183
         * Precompute fmgr lookup data for inner loop
 
184
         */
 
185
        uniquestate->eqfunctions =
 
186
                execTuplesMatchPrepare(ExecGetResultType(&uniquestate->ps),
 
187
                                                           node->numCols,
 
188
                                                           node->uniqColIdx);
 
189
 
 
190
        return uniquestate;
 
191
}
 
192
 
 
193
int
 
194
ExecCountSlotsUnique(Unique *node)
 
195
{
 
196
        return ExecCountSlotsNode(outerPlan(node)) +
 
197
                ExecCountSlotsNode(innerPlan(node)) +
 
198
                UNIQUE_NSLOTS;
 
199
}
 
200
 
 
201
/* ----------------------------------------------------------------
 
202
 *              ExecEndUnique
 
203
 *
 
204
 *              This shuts down the subplan and frees resources allocated
 
205
 *              to this node.
 
206
 * ----------------------------------------------------------------
 
207
 */
 
208
void
 
209
ExecEndUnique(UniqueState *node)
 
210
{
 
211
        /* clean up tuple table */
 
212
        ExecClearTuple(node->ps.ps_ResultTupleSlot);
 
213
 
 
214
        MemoryContextDelete(node->tempContext);
 
215
 
 
216
        ExecEndNode(outerPlanState(node));
 
217
}
 
218
 
 
219
 
 
220
void
 
221
ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt)
 
222
{
 
223
        ExecClearTuple(node->ps.ps_ResultTupleSlot);
 
224
        if (node->priorTuple != NULL)
 
225
        {
 
226
                heap_freetuple(node->priorTuple);
 
227
                node->priorTuple = NULL;
 
228
        }
 
229
 
 
230
        /*
 
231
         * if chgParam of subnode is not null then plan will be re-scanned by
 
232
         * first ExecProcNode.
 
233
         */
 
234
        if (((PlanState *) node)->lefttree->chgParam == NULL)
 
235
                ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
 
236
}