88 *
99 *
1010 * 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 $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
2121 */
2222#include "postgres.h"
2323
24+ #include "access/heapam.h"
2425#include "executor/executor.h"
2526#include "executor/nodeMaterial.h"
2627#include "miscadmin.h"
2930/* ----------------------------------------------------------------
3031 *ExecMaterial
3132 *
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.
4237 *
4338 * ----------------------------------------------------------------
4439 */
@@ -47,79 +42,106 @@ ExecMaterial(MaterialState *node)
4742{
4843EState * estate ;
4944ScanDirection dir ;
45+ bool forward ;
5046Tuplestorestate * tuplestorestate ;
51- HeapTuple heapTuple ;
47+ HeapTuple heapTuple = NULL ;
48+ bool should_free = false;
49+ bool eof_tuplestore ;
5250TupleTableSlot * slot ;
53- bool should_free ;
5451
5552/*
5653 * get state info from node
5754 */
5855estate = node -> ss .ps .state ;
5956dir = estate -> es_direction ;
57+ forward = ScanDirectionIsForward (dir );
6058tuplestorestate = (Tuplestorestate * )node -> tuplestorestate ;
6159
6260/*
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.
6662 */
67-
6863if (tuplestorestate == NULL )
6964{
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- */
8265tuplestorestate = tuplestore_begin_heap (true,/* randomAccess */
8366SortMem );
8467
8568node -> tuplestorestate = (void * )tuplestorestate ;
69+ }
8670
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 );
9176
92- for (;;)
77+ if (!forward && eof_tuplestore )
78+ {
79+ if (!node -> eof_underlying )
9380{
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+ }
9597
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+ }
98106
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 ;
102119
103120/*
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.
105123 */
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;
108133/*
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.
110137 */
111- estate -> es_direction = dir ;
138+ tuplestore_puttuple ( tuplestorestate , ( void * ) heapTuple ) ;
112139}
113140
114141/*
115- * Get the first or next tuple from tuplestore. Returns NULL if no
116- * more tuples.
142+ * Return the obtained tuple.
117143 */
118144slot = (TupleTableSlot * )node -> ss .ps .ps_ResultTupleSlot ;
119- heapTuple = tuplestore_getheaptuple (tuplestorestate ,
120- ScanDirectionIsForward (dir ),
121- & should_free );
122-
123145return ExecStoreTuple (heapTuple ,slot ,InvalidBuffer ,should_free );
124146}
125147
@@ -141,6 +163,7 @@ ExecInitMaterial(Material *node, EState *estate)
141163matstate -> ss .ps .state = estate ;
142164
143165matstate -> tuplestorestate = NULL ;
166+ matstate -> eof_underlying = false;
144167
145168/*
146169 * Miscellaneous initialization
@@ -272,12 +295,16 @@ ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt)
272295 * results; we have to re-read the subplan and re-store.
273296 *
274297 * Otherwise we can just rewind and rescan the stored output.
298+ * The state of the subnode does not change.
275299 */
276300if (((PlanState * )node )-> lefttree -> chgParam != NULL )
277301{
278302tuplestore_end ((Tuplestorestate * )node -> tuplestorestate );
279303node -> tuplestorestate = NULL ;
304+ node -> eof_underlying = false;
280305}
281306else
307+ {
282308tuplestore_rescan ((Tuplestorestate * )node -> tuplestorestate );
309+ }
283310}