8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.40 2002/12/15 16:17:46 tgl Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.41 2003/03/09 02:19:13 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
21
21
*/
22
22
#include "postgres.h"
23
23
24
+ #include "access/heapam.h"
24
25
#include "executor/executor.h"
25
26
#include "executor/nodeMaterial.h"
26
27
#include "miscadmin.h"
29
30
/* ----------------------------------------------------------------
30
31
* ExecMaterial
31
32
*
32
- * The first time this is called, ExecMaterial retrieves tuples
33
- * from this node's outer subplan and inserts them into a tuplestore
34
- * (a temporary tuple storage structure). The first tuple is then
35
- * returned. Successive calls to ExecMaterial return successive
36
- * tuples from the tuplestore.
37
- *
38
- * Initial State:
39
- *
40
- * matstate->tuplestorestate is initially NULL, indicating we
41
- * haven't yet collected the results of the subplan.
33
+ * As long as we are at the end of the data collected in the tuplestore,
34
+ * we collect one new row from the subplan on each call, and stash it
35
+ * aside in the tuplestore before returning it. The tuplestore is
36
+ * only read if we are asked to scan backwards, rescan, or mark/restore.
42
37
*
43
38
* ----------------------------------------------------------------
44
39
*/
@@ -47,79 +42,106 @@ ExecMaterial(MaterialState *node)
47
42
{
48
43
EState * estate ;
49
44
ScanDirection dir ;
45
+ bool forward ;
50
46
Tuplestorestate * tuplestorestate ;
51
- HeapTuple heapTuple ;
47
+ HeapTuple heapTuple = NULL ;
48
+ bool should_free = false;
49
+ bool eof_tuplestore ;
52
50
TupleTableSlot * slot ;
53
- bool should_free ;
54
51
55
52
/*
56
53
* get state info from node
57
54
*/
58
55
estate = node -> ss .ps .state ;
59
56
dir = estate -> es_direction ;
57
+ forward = ScanDirectionIsForward (dir );
60
58
tuplestorestate = (Tuplestorestate * ) node -> tuplestorestate ;
61
59
62
60
/*
63
- * If first time through, read all tuples from outer plan and pass
64
- * them to tuplestore.c. Subsequent calls just fetch tuples from
65
- * tuplestore.
61
+ * If first time through, initialize the tuplestore.
66
62
*/
67
-
68
63
if (tuplestorestate == NULL )
69
64
{
70
- PlanState * outerNode ;
71
-
72
- /*
73
- * Want to scan subplan in the forward direction while creating
74
- * the stored data. (Does setting my direction actually affect
75
- * the subplan? I bet this is useless code...)
76
- */
77
- estate -> es_direction = ForwardScanDirection ;
78
-
79
- /*
80
- * Initialize tuplestore module.
81
- */
82
65
tuplestorestate = tuplestore_begin_heap (true, /* randomAccess */
83
66
SortMem );
84
67
85
68
node -> tuplestorestate = (void * ) tuplestorestate ;
69
+ }
86
70
87
- /*
88
- * Scan the subplan and feed all the tuples to tuplestore.
89
- */
90
- outerNode = outerPlanState (node );
71
+ /*
72
+ * If we are not at the end of the tuplestore, or are going backwards,
73
+ * try to fetch a tuple from tuplestore.
74
+ */
75
+ eof_tuplestore = tuplestore_ateof (tuplestorestate );
91
76
92
- for (;;)
77
+ if (!forward && eof_tuplestore )
78
+ {
79
+ if (!node -> eof_underlying )
93
80
{
94
- slot = ExecProcNode (outerNode );
81
+ /*
82
+ * When reversing direction at tuplestore EOF, the first
83
+ * getheaptuple call will fetch the last-added tuple; but
84
+ * we want to return the one before that, if possible.
85
+ * So do an extra fetch.
86
+ */
87
+ heapTuple = tuplestore_getheaptuple (tuplestorestate ,
88
+ forward ,
89
+ & should_free );
90
+ if (heapTuple == NULL )
91
+ return NULL ; /* the tuplestore must be empty */
92
+ if (should_free )
93
+ heap_freetuple (heapTuple );
94
+ }
95
+ eof_tuplestore = false;
96
+ }
95
97
96
- if (TupIsNull (slot ))
97
- break ;
98
+ if (!eof_tuplestore )
99
+ {
100
+ heapTuple = tuplestore_getheaptuple (tuplestorestate ,
101
+ forward ,
102
+ & should_free );
103
+ if (heapTuple == NULL && forward )
104
+ eof_tuplestore = true;
105
+ }
98
106
99
- tuplestore_puttuple (tuplestorestate , (void * ) slot -> val );
100
- ExecClearTuple (slot );
101
- }
107
+ /*
108
+ * If necessary, try to fetch another row from the subplan.
109
+ *
110
+ * Note: the eof_underlying state variable exists to short-circuit
111
+ * further subplan calls. It's not optional, unfortunately, because
112
+ * some plan node types are not robust about being called again when
113
+ * they've already returned NULL.
114
+ */
115
+ if (eof_tuplestore && !node -> eof_underlying )
116
+ {
117
+ PlanState * outerNode ;
118
+ TupleTableSlot * outerslot ;
102
119
103
120
/*
104
- * Complete the store.
121
+ * We can only get here with forward==true, so no need to worry
122
+ * about which direction the subplan will go.
105
123
*/
106
- tuplestore_donestoring (tuplestorestate );
107
-
124
+ outerNode = outerPlanState (node );
125
+ outerslot = ExecProcNode (outerNode );
126
+ if (TupIsNull (outerslot ))
127
+ {
128
+ node -> eof_underlying = true;
129
+ return NULL ;
130
+ }
131
+ heapTuple = outerslot -> val ;
132
+ should_free = false;
108
133
/*
109
- * restore to user specified direction
134
+ * Append returned tuple to tuplestore, too. NOTE: because the
135
+ * tuplestore is certainly in EOF state, its read position will move
136
+ * forward over the added tuple. This is what we want.
110
137
*/
111
- estate -> es_direction = dir ;
138
+ tuplestore_puttuple ( tuplestorestate , ( void * ) heapTuple ) ;
112
139
}
113
140
114
141
/*
115
- * Get the first or next tuple from tuplestore. Returns NULL if no
116
- * more tuples.
142
+ * Return the obtained tuple.
117
143
*/
118
144
slot = (TupleTableSlot * ) node -> ss .ps .ps_ResultTupleSlot ;
119
- heapTuple = tuplestore_getheaptuple (tuplestorestate ,
120
- ScanDirectionIsForward (dir ),
121
- & should_free );
122
-
123
145
return ExecStoreTuple (heapTuple , slot , InvalidBuffer , should_free );
124
146
}
125
147
@@ -141,6 +163,7 @@ ExecInitMaterial(Material *node, EState *estate)
141
163
matstate -> ss .ps .state = estate ;
142
164
143
165
matstate -> tuplestorestate = NULL ;
166
+ matstate -> eof_underlying = false;
144
167
145
168
/*
146
169
* Miscellaneous initialization
@@ -272,12 +295,16 @@ ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt)
272
295
* results; we have to re-read the subplan and re-store.
273
296
*
274
297
* Otherwise we can just rewind and rescan the stored output.
298
+ * The state of the subnode does not change.
275
299
*/
276
300
if (((PlanState * ) node )-> lefttree -> chgParam != NULL )
277
301
{
278
302
tuplestore_end ((Tuplestorestate * ) node -> tuplestorestate );
279
303
node -> tuplestorestate = NULL ;
304
+ node -> eof_underlying = false;
280
305
}
281
306
else
307
+ {
282
308
tuplestore_rescan ((Tuplestorestate * ) node -> tuplestorestate );
309
+ }
283
310
}
0 commit comments