~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/executor/nodeSetOp.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
 * nodeSetOp.c
 
4
 *        Routines to handle INTERSECT and EXCEPT selection
 
5
 *
 
6
 * The input of a SetOp node consists of tuples from two relations,
 
7
 * which have been combined into one dataset and sorted on all the nonjunk
 
8
 * attributes.  In addition there is a junk attribute that shows which
 
9
 * relation each tuple came from.  The SetOp node scans each group of
 
10
 * identical tuples to determine how many came from each input relation.
 
11
 * Then it is a simple matter to emit the output demanded by the SQL spec
 
12
 * for INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL.
 
13
 *
 
14
 * This node type is not used for UNION or UNION ALL, since those can be
 
15
 * implemented more cheaply (there's no need for the junk attribute to
 
16
 * identify the source relation).
 
17
 *
 
18
 *
 
19
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
20
 * Portions Copyright (c) 1994, Regents of the University of California
 
21
 *
 
22
 *
 
23
 * IDENTIFICATION
 
24
 *        $PostgreSQL: pgsql/src/backend/executor/nodeSetOp.c,v 1.15 2004-12-31 21:59:45 pgsql Exp $
 
25
 *
 
26
 *-------------------------------------------------------------------------
 
27
 */
 
28
/*
 
29
 * INTERFACE ROUTINES
 
30
 *              ExecSetOp               - filter input to generate INTERSECT/EXCEPT results
 
31
 *              ExecInitSetOp   - initialize node and subnodes..
 
32
 *              ExecEndSetOp    - shutdown node and subnodes
 
33
 */
 
34
 
 
35
#include "postgres.h"
 
36
 
 
37
#include "access/heapam.h"
 
38
#include "executor/executor.h"
 
39
#include "executor/nodeSetOp.h"
 
40
 
 
41
 
 
42
/* ----------------------------------------------------------------
 
43
 *              ExecSetOp
 
44
 * ----------------------------------------------------------------
 
45
 */
 
46
TupleTableSlot *                                /* return: a tuple or NULL */
 
47
ExecSetOp(SetOpState *node)
 
48
{
 
49
        SetOp      *plannode = (SetOp *) node->ps.plan;
 
50
        TupleTableSlot *resultTupleSlot;
 
51
        PlanState  *outerPlan;
 
52
        TupleDesc       tupDesc;
 
53
 
 
54
        /*
 
55
         * get information from the node
 
56
         */
 
57
        outerPlan = outerPlanState(node);
 
58
        resultTupleSlot = node->ps.ps_ResultTupleSlot;
 
59
        tupDesc = ExecGetResultType(&node->ps);
 
60
 
 
61
        /*
 
62
         * If the previously-returned tuple needs to be returned more than
 
63
         * once, keep returning it.
 
64
         */
 
65
        if (node->numOutput > 0)
 
66
        {
 
67
                node->numOutput--;
 
68
                return resultTupleSlot;
 
69
        }
 
70
 
 
71
        /* Flag that we have no current tuple */
 
72
        ExecClearTuple(resultTupleSlot);
 
73
 
 
74
        /*
 
75
         * Absorb groups of duplicate tuples, counting them, and saving the
 
76
         * first of each group as a possible return value. At the end of each
 
77
         * group, decide whether to return anything.
 
78
         *
 
79
         * We assume that the tuples arrive in sorted order so we can detect
 
80
         * duplicates easily.
 
81
         */
 
82
        for (;;)
 
83
        {
 
84
                TupleTableSlot *inputTupleSlot;
 
85
                bool            endOfGroup;
 
86
 
 
87
                /*
 
88
                 * fetch a tuple from the outer subplan, unless we already did.
 
89
                 */
 
90
                if (node->ps.ps_OuterTupleSlot == NULL &&
 
91
                        !node->subplan_done)
 
92
                {
 
93
                        node->ps.ps_OuterTupleSlot =
 
94
                                ExecProcNode(outerPlan);
 
95
                        if (TupIsNull(node->ps.ps_OuterTupleSlot))
 
96
                                node->subplan_done = true;
 
97
                }
 
98
                inputTupleSlot = node->ps.ps_OuterTupleSlot;
 
99
 
 
100
                if (TupIsNull(resultTupleSlot))
 
101
                {
 
102
                        /*
 
103
                         * First of group: save a copy in result slot, and reset
 
104
                         * duplicate-counters for new group.
 
105
                         */
 
106
                        if (node->subplan_done)
 
107
                                return NULL;    /* no more tuples */
 
108
                        ExecStoreTuple(heap_copytuple(inputTupleSlot->val),
 
109
                                                   resultTupleSlot,
 
110
                                                   InvalidBuffer,
 
111
                                                   true);               /* free copied tuple at
 
112
                                                                                 * ExecClearTuple */
 
113
                        node->numLeft = 0;
 
114
                        node->numRight = 0;
 
115
                        endOfGroup = false;
 
116
                }
 
117
                else if (node->subplan_done)
 
118
                {
 
119
                        /*
 
120
                         * Reached end of input, so finish processing final group
 
121
                         */
 
122
                        endOfGroup = true;
 
123
                }
 
124
                else
 
125
                {
 
126
                        /*
 
127
                         * Else test if the new tuple and the previously saved tuple
 
128
                         * match.
 
129
                         */
 
130
                        if (execTuplesMatch(inputTupleSlot->val,
 
131
                                                                resultTupleSlot->val,
 
132
                                                                tupDesc,
 
133
                                                                plannode->numCols, plannode->dupColIdx,
 
134
                                                                node->eqfunctions,
 
135
                                                                node->tempContext))
 
136
                                endOfGroup = false;
 
137
                        else
 
138
                                endOfGroup = true;
 
139
                }
 
140
 
 
141
                if (endOfGroup)
 
142
                {
 
143
                        /*
 
144
                         * We've reached the end of the group containing resultTuple.
 
145
                         * Decide how many copies (if any) to emit.  This logic is
 
146
                         * straight from the SQL92 specification.
 
147
                         */
 
148
                        switch (plannode->cmd)
 
149
                        {
 
150
                                case SETOPCMD_INTERSECT:
 
151
                                        if (node->numLeft > 0 && node->numRight > 0)
 
152
                                                node->numOutput = 1;
 
153
                                        else
 
154
                                                node->numOutput = 0;
 
155
                                        break;
 
156
                                case SETOPCMD_INTERSECT_ALL:
 
157
                                        node->numOutput =
 
158
                                                (node->numLeft < node->numRight) ?
 
159
                                                node->numLeft : node->numRight;
 
160
                                        break;
 
161
                                case SETOPCMD_EXCEPT:
 
162
                                        if (node->numLeft > 0 && node->numRight == 0)
 
163
                                                node->numOutput = 1;
 
164
                                        else
 
165
                                                node->numOutput = 0;
 
166
                                        break;
 
167
                                case SETOPCMD_EXCEPT_ALL:
 
168
                                        node->numOutput =
 
169
                                                (node->numLeft < node->numRight) ?
 
170
                                                0 : (node->numLeft - node->numRight);
 
171
                                        break;
 
172
                                default:
 
173
                                        elog(ERROR, "unrecognized set op: %d",
 
174
                                                 (int) plannode->cmd);
 
175
                                        break;
 
176
                        }
 
177
                        /* Fall out of for-loop if we have tuples to emit */
 
178
                        if (node->numOutput > 0)
 
179
                                break;
 
180
                        /* Else flag that we have no current tuple, and loop around */
 
181
                        ExecClearTuple(resultTupleSlot);
 
182
                }
 
183
                else
 
184
                {
 
185
                        /*
 
186
                         * Current tuple is member of same group as resultTuple. Count
 
187
                         * it in the appropriate counter.
 
188
                         */
 
189
                        int                     flag;
 
190
                        bool            isNull;
 
191
 
 
192
                        flag = DatumGetInt32(heap_getattr(inputTupleSlot->val,
 
193
                                                                                          plannode->flagColIdx,
 
194
                                                                                          tupDesc,
 
195
                                                                                          &isNull));
 
196
                        Assert(!isNull);
 
197
                        if (flag)
 
198
                                node->numRight++;
 
199
                        else
 
200
                                node->numLeft++;
 
201
                        /* Set flag to fetch a new input tuple, and loop around */
 
202
                        node->ps.ps_OuterTupleSlot = NULL;
 
203
                }
 
204
        }
 
205
 
 
206
        /*
 
207
         * If we fall out of loop, then we need to emit at least one copy of
 
208
         * resultTuple.
 
209
         */
 
210
        Assert(node->numOutput > 0);
 
211
        node->numOutput--;
 
212
        return resultTupleSlot;
 
213
}
 
214
 
 
215
/* ----------------------------------------------------------------
 
216
 *              ExecInitSetOp
 
217
 *
 
218
 *              This initializes the setop node state structures and
 
219
 *              the node's subplan.
 
220
 * ----------------------------------------------------------------
 
221
 */
 
222
SetOpState *
 
223
ExecInitSetOp(SetOp *node, EState *estate)
 
224
{
 
225
        SetOpState *setopstate;
 
226
 
 
227
        /*
 
228
         * create state structure
 
229
         */
 
230
        setopstate = makeNode(SetOpState);
 
231
        setopstate->ps.plan = (Plan *) node;
 
232
        setopstate->ps.state = estate;
 
233
 
 
234
        setopstate->ps.ps_OuterTupleSlot = NULL;
 
235
        setopstate->subplan_done = false;
 
236
        setopstate->numOutput = 0;
 
237
 
 
238
        /*
 
239
         * Miscellaneous initialization
 
240
         *
 
241
         * SetOp nodes have no ExprContext initialization because they never call
 
242
         * ExecQual or ExecProject.  But they do need a per-tuple memory
 
243
         * context anyway for calling execTuplesMatch.
 
244
         */
 
245
        setopstate->tempContext =
 
246
                AllocSetContextCreate(CurrentMemoryContext,
 
247
                                                          "SetOp",
 
248
                                                          ALLOCSET_DEFAULT_MINSIZE,
 
249
                                                          ALLOCSET_DEFAULT_INITSIZE,
 
250
                                                          ALLOCSET_DEFAULT_MAXSIZE);
 
251
 
 
252
#define SETOP_NSLOTS 1
 
253
 
 
254
        /*
 
255
         * Tuple table initialization
 
256
         */
 
257
        ExecInitResultTupleSlot(estate, &setopstate->ps);
 
258
 
 
259
        /*
 
260
         * then initialize outer plan
 
261
         */
 
262
        outerPlanState(setopstate) = ExecInitNode(outerPlan(node), estate);
 
263
 
 
264
        /*
 
265
         * setop nodes do no projections, so initialize projection info for
 
266
         * this node appropriately
 
267
         */
 
268
        ExecAssignResultTypeFromOuterPlan(&setopstate->ps);
 
269
        setopstate->ps.ps_ProjInfo = NULL;
 
270
 
 
271
        /*
 
272
         * Precompute fmgr lookup data for inner loop
 
273
         */
 
274
        setopstate->eqfunctions =
 
275
                execTuplesMatchPrepare(ExecGetResultType(&setopstate->ps),
 
276
                                                           node->numCols,
 
277
                                                           node->dupColIdx);
 
278
 
 
279
        return setopstate;
 
280
}
 
281
 
 
282
int
 
283
ExecCountSlotsSetOp(SetOp *node)
 
284
{
 
285
        return ExecCountSlotsNode(outerPlan(node)) +
 
286
                ExecCountSlotsNode(innerPlan(node)) +
 
287
                SETOP_NSLOTS;
 
288
}
 
289
 
 
290
/* ----------------------------------------------------------------
 
291
 *              ExecEndSetOp
 
292
 *
 
293
 *              This shuts down the subplan and frees resources allocated
 
294
 *              to this node.
 
295
 * ----------------------------------------------------------------
 
296
 */
 
297
void
 
298
ExecEndSetOp(SetOpState *node)
 
299
{
 
300
        /* clean up tuple table */
 
301
        ExecClearTuple(node->ps.ps_ResultTupleSlot);
 
302
        node->ps.ps_OuterTupleSlot = NULL;
 
303
 
 
304
        MemoryContextDelete(node->tempContext);
 
305
 
 
306
        ExecEndNode(outerPlanState(node));
 
307
}
 
308
 
 
309
 
 
310
void
 
311
ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt)
 
312
{
 
313
        ExecClearTuple(node->ps.ps_ResultTupleSlot);
 
314
        node->ps.ps_OuterTupleSlot = NULL;
 
315
        node->subplan_done = false;
 
316
        node->numOutput = 0;
 
317
 
 
318
        /*
 
319
         * if chgParam of subnode is not null then plan will be re-scanned by
 
320
         * first ExecProcNode.
 
321
         */
 
322
        if (((PlanState *) node)->lefttree->chgParam == NULL)
 
323
                ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
 
324
}