88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.52 2006/02/2804:10:27 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.53 2006/02/2805:48:44 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -58,9 +58,9 @@ ExecMaterial(MaterialState *node)
5858tuplestorestate = (Tuplestorestate * )node -> tuplestorestate ;
5959
6060/*
61- * If first time through,initialize the tuplestore.
61+ * If first time through,and we need a tuplestore, initialize it .
6262 */
63- if (tuplestorestate == NULL )
63+ if (tuplestorestate == NULL && node -> randomAccess )
6464{
6565tuplestorestate = tuplestore_begin_heap (true, false,work_mem );
6666
@@ -71,7 +71,8 @@ ExecMaterial(MaterialState *node)
7171 * If we are not at the end of the tuplestore, or are going backwards, try
7272 * to fetch a tuple from tuplestore.
7373 */
74- eof_tuplestore = tuplestore_ateof (tuplestorestate );
74+ eof_tuplestore = (tuplestorestate == NULL )||
75+ tuplestore_ateof (tuplestorestate );
7576
7677if (!forward && eof_tuplestore )
7778{
@@ -135,7 +136,8 @@ ExecMaterial(MaterialState *node)
135136 * tuplestore is certainly in EOF state, its read position will move
136137 * forward over the added tuple. This is what we want.
137138 */
138- tuplestore_puttuple (tuplestorestate , (void * )heapTuple );
139+ if (tuplestorestate )
140+ tuplestore_puttuple (tuplestorestate , (void * )heapTuple );
139141}
140142
141143/*
@@ -165,8 +167,18 @@ ExecInitMaterial(Material *node, EState *estate, int eflags)
165167matstate -> ss .ps .plan = (Plan * )node ;
166168matstate -> ss .ps .state = estate ;
167169
168- matstate -> tuplestorestate = NULL ;
170+ /*
171+ * We must have random access to the subplan output to do backward scan
172+ * or mark/restore. We also prefer to materialize the subplan output
173+ * if we might be called on to rewind and replay it many times.
174+ * However, if none of these cases apply, we can skip storing the data.
175+ */
176+ matstate -> randomAccess = (eflags & (EXEC_FLAG_REWIND |
177+ EXEC_FLAG_BACKWARD |
178+ EXEC_FLAG_MARK ))!= 0 ;
179+
169180matstate -> eof_underlying = false;
181+ matstate -> tuplestorestate = NULL ;
170182
171183/*
172184 * Miscellaneous initialization
@@ -249,6 +261,8 @@ ExecEndMaterial(MaterialState *node)
249261void
250262ExecMaterialMarkPos (MaterialState * node )
251263{
264+ Assert (node -> randomAccess );
265+
252266/*
253267 * if we haven't materialized yet, just return.
254268 */
@@ -267,6 +281,8 @@ ExecMaterialMarkPos(MaterialState *node)
267281void
268282ExecMaterialRestrPos (MaterialState * node )
269283{
284+ Assert (node -> randomAccess );
285+
270286/*
271287 * if we haven't materialized yet, just return.
272288 */
@@ -288,29 +304,44 @@ ExecMaterialRestrPos(MaterialState *node)
288304void
289305ExecMaterialReScan (MaterialState * node ,ExprContext * exprCtxt )
290306{
291- /*
292- * If we haven't materialized yet, just return. If outerplan' chgParam is
293- * not NULL then it will be re-scanned by ExecProcNode, else - no reason
294- * to re-scan it at all.
295- */
296- if (!node -> tuplestorestate )
297- return ;
298-
299307ExecClearTuple (node -> ss .ps .ps_ResultTupleSlot );
300308
301- /*
302- * If subnode is to be rescanned then we forget previous stored results;
303- * we have to re-read the subplan and re-store.
304- *
305- * Otherwise we can just rewind and rescan the stored output. The state of
306- * the subnode does not change.
307- */
308- if (((PlanState * )node )-> lefttree -> chgParam != NULL )
309+ if (node -> randomAccess )
309310{
310- tuplestore_end ((Tuplestorestate * )node -> tuplestorestate );
311- node -> tuplestorestate = NULL ;
312- node -> eof_underlying = false;
311+ /*
312+ * If we haven't materialized yet, just return. If outerplan' chgParam
313+ * is not NULL then it will be re-scanned by ExecProcNode, else - no
314+ * reason to re-scan it at all.
315+ */
316+ if (!node -> tuplestorestate )
317+ return ;
318+
319+ /*
320+ * If subnode is to be rescanned then we forget previous stored
321+ * results; we have to re-read the subplan and re-store.
322+ *
323+ * Otherwise we can just rewind and rescan the stored output. The
324+ * state of the subnode does not change.
325+ */
326+ if (((PlanState * )node )-> lefttree -> chgParam != NULL )
327+ {
328+ tuplestore_end ((Tuplestorestate * )node -> tuplestorestate );
329+ node -> tuplestorestate = NULL ;
330+ node -> eof_underlying = false;
331+ }
332+ else
333+ tuplestore_rescan ((Tuplestorestate * )node -> tuplestorestate );
313334}
314335else
315- tuplestore_rescan ((Tuplestorestate * )node -> tuplestorestate );
336+ {
337+ /* In this case we are just passing on the subquery's output */
338+
339+ /*
340+ * if chgParam of subnode is not null then plan will be re-scanned by
341+ * first ExecProcNode.
342+ */
343+ if (((PlanState * )node )-> lefttree -> chgParam == NULL )
344+ ExecReScan (((PlanState * )node )-> lefttree ,exprCtxt );
345+ node -> eof_underlying = false;
346+ }
316347}