aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execQual.c9
-rw-r--r--src/backend/executor/nodeMaterial.c129
2 files changed, 79 insertions, 59 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 968617c39a9..a1c1fdd8ad3 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.125 2003/02/16 02:30:37 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.126 2003/03/09 02:19:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1107,13 +1107,6 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
first_time = false;
}
- /* If we have a locally-created tupstore, close it up */
- if (tupstore)
- {
- MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
- tuplestore_donestoring(tupstore);
- }
-
MemoryContextSwitchTo(callerContext);
/* The returned pointers are those in rsinfo */
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index a1725901a7c..2566851dccc 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.40 2002/12/15 16:17:46 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.41 2003/03/09 02:19:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,6 +21,7 @@
*/
#include "postgres.h"
+#include "access/heapam.h"
#include "executor/executor.h"
#include "executor/nodeMaterial.h"
#include "miscadmin.h"
@@ -29,16 +30,10 @@
/* ----------------------------------------------------------------
* ExecMaterial
*
- * The first time this is called, ExecMaterial retrieves tuples
- * from this node's outer subplan and inserts them into a tuplestore
- * (a temporary tuple storage structure). The first tuple is then
- * returned. Successive calls to ExecMaterial return successive
- * tuples from the tuplestore.
- *
- * Initial State:
- *
- * matstate->tuplestorestate is initially NULL, indicating we
- * haven't yet collected the results of the subplan.
+ * As long as we are at the end of the data collected in the tuplestore,
+ * we collect one new row from the subplan on each call, and stash it
+ * aside in the tuplestore before returning it. The tuplestore is
+ * only read if we are asked to scan backwards, rescan, or mark/restore.
*
* ----------------------------------------------------------------
*/
@@ -47,79 +42,106 @@ ExecMaterial(MaterialState *node)
{
EState *estate;
ScanDirection dir;
+ bool forward;
Tuplestorestate *tuplestorestate;
- HeapTuple heapTuple;
+ HeapTuple heapTuple = NULL;
+ bool should_free = false;
+ bool eof_tuplestore;
TupleTableSlot *slot;
- bool should_free;
/*
* get state info from node
*/
estate = node->ss.ps.state;
dir = estate->es_direction;
+ forward = ScanDirectionIsForward(dir);
tuplestorestate = (Tuplestorestate *) node->tuplestorestate;
/*
- * If first time through, read all tuples from outer plan and pass
- * them to tuplestore.c. Subsequent calls just fetch tuples from
- * tuplestore.
+ * If first time through, initialize the tuplestore.
*/
-
if (tuplestorestate == NULL)
{
- PlanState *outerNode;
-
- /*
- * Want to scan subplan in the forward direction while creating
- * the stored data. (Does setting my direction actually affect
- * the subplan? I bet this is useless code...)
- */
- estate->es_direction = ForwardScanDirection;
-
- /*
- * Initialize tuplestore module.
- */
tuplestorestate = tuplestore_begin_heap(true, /* randomAccess */
SortMem);
node->tuplestorestate = (void *) tuplestorestate;
+ }
- /*
- * Scan the subplan and feed all the tuples to tuplestore.
- */
- outerNode = outerPlanState(node);
+ /*
+ * If we are not at the end of the tuplestore, or are going backwards,
+ * try to fetch a tuple from tuplestore.
+ */
+ eof_tuplestore = tuplestore_ateof(tuplestorestate);
- for (;;)
+ if (!forward && eof_tuplestore)
+ {
+ if (!node->eof_underlying)
{
- slot = ExecProcNode(outerNode);
+ /*
+ * When reversing direction at tuplestore EOF, the first
+ * getheaptuple call will fetch the last-added tuple; but
+ * we want to return the one before that, if possible.
+ * So do an extra fetch.
+ */
+ heapTuple = tuplestore_getheaptuple(tuplestorestate,
+ forward,
+ &should_free);
+ if (heapTuple == NULL)
+ return NULL; /* the tuplestore must be empty */
+ if (should_free)
+ heap_freetuple(heapTuple);
+ }
+ eof_tuplestore = false;
+ }
- if (TupIsNull(slot))
- break;
+ if (!eof_tuplestore)
+ {
+ heapTuple = tuplestore_getheaptuple(tuplestorestate,
+ forward,
+ &should_free);
+ if (heapTuple == NULL && forward)
+ eof_tuplestore = true;
+ }
- tuplestore_puttuple(tuplestorestate, (void *) slot->val);
- ExecClearTuple(slot);
- }
+ /*
+ * If necessary, try to fetch another row from the subplan.
+ *
+ * Note: the eof_underlying state variable exists to short-circuit
+ * further subplan calls. It's not optional, unfortunately, because
+ * some plan node types are not robust about being called again when
+ * they've already returned NULL.
+ */
+ if (eof_tuplestore && !node->eof_underlying)
+ {
+ PlanState *outerNode;
+ TupleTableSlot *outerslot;
/*
- * Complete the store.
+ * We can only get here with forward==true, so no need to worry
+ * about which direction the subplan will go.
*/
- tuplestore_donestoring(tuplestorestate);
-
+ outerNode = outerPlanState(node);
+ outerslot = ExecProcNode(outerNode);
+ if (TupIsNull(outerslot))
+ {
+ node->eof_underlying = true;
+ return NULL;
+ }
+ heapTuple = outerslot->val;
+ should_free = false;
/*
- * restore to user specified direction
+ * Append returned tuple to tuplestore, too. NOTE: because the
+ * tuplestore is certainly in EOF state, its read position will move
+ * forward over the added tuple. This is what we want.
*/
- estate->es_direction = dir;
+ tuplestore_puttuple(tuplestorestate, (void *) heapTuple);
}
/*
- * Get the first or next tuple from tuplestore. Returns NULL if no
- * more tuples.
+ * Return the obtained tuple.
*/
slot = (TupleTableSlot *) node->ss.ps.ps_ResultTupleSlot;
- heapTuple = tuplestore_getheaptuple(tuplestorestate,
- ScanDirectionIsForward(dir),
- &should_free);
-
return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
}
@@ -141,6 +163,7 @@ ExecInitMaterial(Material *node, EState *estate)
matstate->ss.ps.state = estate;
matstate->tuplestorestate = NULL;
+ matstate->eof_underlying = false;
/*
* Miscellaneous initialization
@@ -272,12 +295,16 @@ ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt)
* results; we have to re-read the subplan and re-store.
*
* Otherwise we can just rewind and rescan the stored output.
+ * The state of the subnode does not change.
*/
if (((PlanState *) node)->lefttree->chgParam != NULL)
{
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
node->tuplestorestate = NULL;
+ node->eof_underlying = false;
}
else
+ {
tuplestore_rescan((Tuplestorestate *) node->tuplestorestate);
+ }
}