diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c index 641fe3afc2..34e1b2538f 100644 --- a/src/backend/executor/nodeMaterial.c +++ b/src/backend/executor/nodeMaterial.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.52 2006/02/28 04:10:27 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.53 2006/02/28 05:48:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -58,9 +58,9 @@ ExecMaterial(MaterialState *node) tuplestorestate = (Tuplestorestate *) node->tuplestorestate; /* - * If first time through, initialize the tuplestore. + * If first time through, and we need a tuplestore, initialize it. */ - if (tuplestorestate == NULL) + if (tuplestorestate == NULL && node->randomAccess) { tuplestorestate = tuplestore_begin_heap(true, false, work_mem); @@ -71,7 +71,8 @@ ExecMaterial(MaterialState *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); + eof_tuplestore = (tuplestorestate == NULL) || + tuplestore_ateof(tuplestorestate); if (!forward && eof_tuplestore) { @@ -135,7 +136,8 @@ ExecMaterial(MaterialState *node) * tuplestore is certainly in EOF state, its read position will move * forward over the added tuple. This is what we want. */ - tuplestore_puttuple(tuplestorestate, (void *) heapTuple); + if (tuplestorestate) + tuplestore_puttuple(tuplestorestate, (void *) heapTuple); } /* @@ -165,8 +167,18 @@ ExecInitMaterial(Material *node, EState *estate, int eflags) matstate->ss.ps.plan = (Plan *) node; matstate->ss.ps.state = estate; - matstate->tuplestorestate = NULL; + /* + * We must have random access to the subplan output to do backward scan + * or mark/restore. We also prefer to materialize the subplan output + * if we might be called on to rewind and replay it many times. + * However, if none of these cases apply, we can skip storing the data. + */ + matstate->randomAccess = (eflags & (EXEC_FLAG_REWIND | + EXEC_FLAG_BACKWARD | + EXEC_FLAG_MARK)) != 0; + matstate->eof_underlying = false; + matstate->tuplestorestate = NULL; /* * Miscellaneous initialization @@ -249,6 +261,8 @@ ExecEndMaterial(MaterialState *node) void ExecMaterialMarkPos(MaterialState *node) { + Assert(node->randomAccess); + /* * if we haven't materialized yet, just return. */ @@ -267,6 +281,8 @@ ExecMaterialMarkPos(MaterialState *node) void ExecMaterialRestrPos(MaterialState *node) { + Assert(node->randomAccess); + /* * if we haven't materialized yet, just return. */ @@ -288,29 +304,44 @@ ExecMaterialRestrPos(MaterialState *node) void ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt) { - /* - * If we haven't materialized yet, just return. If outerplan' chgParam is - * not NULL then it will be re-scanned by ExecProcNode, else - no reason - * to re-scan it at all. - */ - if (!node->tuplestorestate) - return; - ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); - /* - * If subnode is to be rescanned then we forget previous stored 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) + if (node->randomAccess) { - tuplestore_end((Tuplestorestate *) node->tuplestorestate); - node->tuplestorestate = NULL; - node->eof_underlying = false; + /* + * If we haven't materialized yet, just return. If outerplan' chgParam + * is not NULL then it will be re-scanned by ExecProcNode, else - no + * reason to re-scan it at all. + */ + if (!node->tuplestorestate) + return; + + /* + * If subnode is to be rescanned then we forget previous stored + * 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); } else - tuplestore_rescan((Tuplestorestate *) node->tuplestorestate); + { + /* In this case we are just passing on the subquery's output */ + + /* + * if chgParam of subnode is not null then plan will be re-scanned by + * first ExecProcNode. + */ + if (((PlanState *) node)->lefttree->chgParam == NULL) + ExecReScan(((PlanState *) node)->lefttree, exprCtxt); + node->eof_underlying = false; + } } diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c index 367adbfbe2..f799c78218 100644 --- a/src/backend/executor/nodeSort.c +++ b/src/backend/executor/nodeSort.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeSort.c,v 1.54 2006/02/28 04:10:27 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeSort.c,v 1.55 2006/02/28 05:48:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -89,7 +89,7 @@ ExecSort(SortState *node) plannode->sortOperators, plannode->sortColIdx, work_mem, - true /* randomAccess */ ); + node->randomAccess); node->tuplesortstate = (void *) tuplesortstate; /* @@ -164,6 +164,15 @@ ExecInitSort(Sort *node, EState *estate, int eflags) sortstate->ss.ps.plan = (Plan *) node; sortstate->ss.ps.state = estate; + /* + * We must have random access to the sort output to do backward scan + * or mark/restore. We also prefer to materialize the sort output + * if we might be called on to rewind and replay it many times. + */ + sortstate->randomAccess = (eflags & (EXEC_FLAG_REWIND | + EXEC_FLAG_BACKWARD | + EXEC_FLAG_MARK)) != 0; + sortstate->sort_Done = false; sortstate->tuplesortstate = NULL; @@ -308,11 +317,18 @@ ExecReScanSort(SortState *node, ExprContext *exprCtxt) * * Otherwise we can just rewind and rescan the sorted output. */ - if (((PlanState *) node)->lefttree->chgParam != NULL) + if (((PlanState *) node)->lefttree->chgParam != NULL || + !node->randomAccess) { node->sort_Done = false; tuplesort_end((Tuplesortstate *) node->tuplesortstate); node->tuplesortstate = NULL; + /* + * if chgParam of subnode is not null then plan will be re-scanned by + * first ExecProcNode. + */ + if (((PlanState *) node)->lefttree->chgParam == NULL) + ExecReScan(((PlanState *) node)->lefttree, exprCtxt); } else tuplesort_rescan((Tuplesortstate *) node->tuplesortstate); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index d07dc57297..f277672a1c 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.147 2005/12/28 01:30:01 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.148 2006/02/28 05:48:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1185,8 +1185,9 @@ typedef struct HashJoinState typedef struct MaterialState { ScanState ss; /* its first field is NodeTag */ - void *tuplestorestate; /* private state of tuplestore.c */ + bool randomAccess; /* need random access to subplan output? */ bool eof_underlying; /* reached end of underlying plan? */ + void *tuplestorestate; /* private state of tuplestore.c */ } MaterialState; /* ---------------- @@ -1196,6 +1197,7 @@ typedef struct MaterialState typedef struct SortState { ScanState ss; /* its first field is NodeTag */ + bool randomAccess; /* need random access to sort output? */ bool sort_Done; /* sort completed yet? */ void *tuplesortstate; /* private state of tuplesort.c */ } SortState;