diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2000-06-18 22:44:35 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2000-06-18 22:44:35 +0000 |
commit | 1ee26b776475155ad1fb00fa3ed0a93659ffadad (patch) | |
tree | 1f2c7a59a1fdf3fe3eb62cf5044c5c6c21f77d12 /src/backend/executor/nodeMaterial.c | |
parent | 2c0edb3c8677831d836fc44eb58ebecb73f747af (diff) | |
download | postgresql-1ee26b776475155ad1fb00fa3ed0a93659ffadad.tar.gz postgresql-1ee26b776475155ad1fb00fa3ed0a93659ffadad.zip |
Reimplement nodeMaterial to use a temporary BufFile (or even memory, if the
materialized tupleset is small enough) instead of a temporary relation.
This was something I was thinking of doing anyway for performance, and Jan
says he needs it for TOAST because he doesn't want to cope with toasting
noname relations. With this change, the 'noname table' support in heap.c
is dead code, and I have accordingly removed it. Also clean up 'noname'
plan handling in planner --- nonames are either sort or materialize plans,
and it seems less confusing to handle them separately under those names.
Diffstat (limited to 'src/backend/executor/nodeMaterial.c')
-rw-r--r-- | src/backend/executor/nodeMaterial.c | 277 |
1 files changed, 97 insertions, 180 deletions
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c index 4348f89ccc9..1d5c9042489 100644 --- a/src/backend/executor/nodeMaterial.c +++ b/src/backend/executor/nodeMaterial.c @@ -8,42 +8,37 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.30 2000/03/02 04:06:39 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.31 2000/06/18 22:44:03 tgl Exp $ * *------------------------------------------------------------------------- */ /* * INTERFACE ROUTINES - * ExecMaterial - generate a temporary relation - * ExecInitMaterial - initialize node and subnodes.. + * ExecMaterial - materialize the result of a subplan + * ExecInitMaterial - initialize node and subnodes * ExecEndMaterial - shutdown node and subnodes * */ #include "postgres.h" - -#include "access/heapam.h" -#include "catalog/heap.h" #include "executor/executor.h" #include "executor/nodeMaterial.h" -#include "optimizer/internal.h" +#include "miscadmin.h" +#include "utils/tuplestore.h" /* ---------------------------------------------------------------- * ExecMaterial * * The first time this is called, ExecMaterial retrieves tuples - * from this node's outer subplan and inserts them into a temporary - * relation. After this is done, a flag is set indicating that - * the subplan has been materialized. Once the relation is - * materialized, the first tuple is then returned. Successive - * calls to ExecMaterial return successive tuples from the temp - * relation. + * 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: * - * ExecMaterial assumes the temporary relation has been - * created and opened by ExecInitMaterial during the prior - * InitPlan() phase. + * matstate->tuplestorestate is initially NULL, indicating we + * haven't yet collected the results of the subplan. * * ---------------------------------------------------------------- */ @@ -52,13 +47,11 @@ ExecMaterial(Material *node) { EState *estate; MaterialState *matstate; - Plan *outerNode; ScanDirection dir; - Relation tempRelation; - Relation currentRelation; - HeapScanDesc currentScanDesc; + Tuplestorestate *tuplestorestate; HeapTuple heapTuple; TupleTableSlot *slot; + bool should_free; /* ---------------- * get state info from node @@ -67,42 +60,42 @@ ExecMaterial(Material *node) matstate = node->matstate; estate = node->plan.state; dir = estate->es_direction; + tuplestorestate = (Tuplestorestate *) matstate->tuplestorestate; /* ---------------- - * the first time we call this, we retrieve all tuples - * from the subplan into a temporary relation and then - * we sort the relation. Subsequent calls return tuples - * from the temporary relation. + * If first time through, read all tuples from outer plan and + * pass them to tuplestore.c. + * Subsequent calls just fetch tuples from tuplestore. * ---------------- */ - if (matstate->mat_Flag == false) + if (tuplestorestate == NULL) { + Plan *outerNode; + /* ---------------- - * set all relations to be scanned in the forward direction - * while creating the temporary relation. + * 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; /* ---------------- - * if we couldn't create the temp relation then - * we print a warning and return NULL. + * Initialize tuplestore module. * ---------------- */ - tempRelation = matstate->mat_TempRelation; - if (tempRelation == NULL) - { - elog(DEBUG, "ExecMaterial: temp relation is NULL! aborting..."); - return NULL; - } + tuplestorestate = tuplestore_begin_heap(true, /* randomAccess */ + SortMem); + + matstate->tuplestorestate = (void *) tuplestorestate; /* ---------------- - * retrieve tuples from the subplan and - * insert them in the temporary relation + * Scan the subplan and feed all the tuples to tuplestore. * ---------------- */ outerNode = outerPlan((Plan *) node); + for (;;) { slot = ExecProcNode(outerNode, (Plan *) node); @@ -110,63 +103,34 @@ ExecMaterial(Material *node) if (TupIsNull(slot)) break; - heap_insert(tempRelation, slot->val); - + tuplestore_puttuple(tuplestorestate, (void *) slot->val); ExecClearTuple(slot); } /* ---------------- - * restore to user specified direction + * Complete the store. * ---------------- */ - estate->es_direction = dir; + tuplestore_donestoring(tuplestorestate); /* ---------------- - * now initialize the scan descriptor to scan the - * sorted relation and update the sortstate information - * ---------------- - */ - currentRelation = tempRelation; - currentScanDesc = heap_beginscan(currentRelation, /* relation */ - ScanDirectionIsBackward(dir), - SnapshotSelf, /* seeself */ - 0, /* num scan keys */ - NULL); /* scan keys */ - matstate->csstate.css_currentRelation = currentRelation; - matstate->csstate.css_currentScanDesc = currentScanDesc; - - ExecAssignScanType(&matstate->csstate, - RelationGetDescr(currentRelation)); - - /* ---------------- - * finally set the sorted flag to true + * restore to user specified direction * ---------------- */ - matstate->mat_Flag = true; + estate->es_direction = dir; } /* ---------------- - * at this point we know we have a sorted relation so - * we perform a simple scan on it with amgetnext().. - * ---------------- - */ - currentScanDesc = matstate->csstate.css_currentScanDesc; - - heapTuple = heap_getnext(currentScanDesc, ScanDirectionIsBackward(dir)); - - /* ---------------- - * put the tuple into the scan tuple slot and return the slot. - * Note: since the tuple is really a pointer to a page, we don't want - * to call pfree() on it.. + * Get the first or next tuple from tuplestore. + * Returns NULL if no more tuples. * ---------------- */ - slot = (TupleTableSlot *) matstate->csstate.css_ScanTupleSlot; - - return ExecStoreTuple(heapTuple, /* tuple to store */ - slot, /* slot to store in */ - currentScanDesc->rs_cbuf, /* buffer for this tuple */ - false); /* don't pfree this pointer */ + slot = (TupleTableSlot *) matstate->csstate.cstate.cs_ResultTupleSlot; + heapTuple = tuplestore_getheaptuple(tuplestorestate, + ScanDirectionIsForward(dir), + &should_free); + return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free); } /* ---------------------------------------------------------------- @@ -178,10 +142,6 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent) { MaterialState *matstate; Plan *outerPlan; - TupleDesc tupType; - Relation tempDesc; - - /* int len; */ /* ---------------- * assign the node's execution state @@ -194,8 +154,7 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent) * ---------------- */ matstate = makeNode(MaterialState); - matstate->mat_Flag = false; - matstate->mat_TempRelation = NULL; + matstate->tuplestorestate = NULL; node->matstate = matstate; /* ---------------- @@ -214,8 +173,12 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent) #define MATERIAL_NSLOTS 1 /* ---------------- * tuple table initialization + * + * material nodes only return tuples from their materialized + * relation. * ---------------- */ + ExecInitResultTupleSlot(estate, &matstate->csstate.cstate); ExecInitScanTupleSlot(estate, &matstate->csstate); /* ---------------- @@ -226,52 +189,14 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent) ExecInitNode(outerPlan, estate, (Plan *) node); /* ---------------- - * initialize matstate information - * ---------------- - */ - matstate->mat_Flag = false; - - /* ---------------- * initialize tuple type. no need to initialize projection * info because this node doesn't do projections. * ---------------- */ + ExecAssignResultTypeFromOuterPlan((Plan *) node, &matstate->csstate.cstate); ExecAssignScanTypeFromOuterPlan((Plan *) node, &matstate->csstate); matstate->csstate.cstate.cs_ProjInfo = NULL; - /* ---------------- - * get type information needed for ExecCreatR - * ---------------- - */ - tupType = ExecGetScanType(&matstate->csstate); - - /* ---------------- - * ExecCreatR wants its second argument to be an object id of - * a relation in the range table or a _NONAME_RELATION_ID - * indicating that the relation is not in the range table. - * - * In the second case ExecCreatR creates a temp relation. - * (currently this is the only case we support -cim 10/16/89) - * ---------------- - */ - /* ---------------- - * create the temporary relation - * ---------------- - */ - tempDesc = ExecCreatR(tupType, _NONAME_RELATION_ID_); - - /* ---------------- - * save the relation descriptor in the sortstate - * ---------------- - */ - matstate->mat_TempRelation = tempDesc; - matstate->csstate.css_currentRelation = NULL; - - /* ---------------- - * return relation oid of temporary relation in a list - * (someday -- for now we return LispTrue... cim 10/12/89) - * ---------------- - */ return TRUE; } @@ -285,16 +210,12 @@ ExecCountSlotsMaterial(Material *node) /* ---------------------------------------------------------------- * ExecEndMaterial - * - * old comments - * destroys the temporary relation. * ---------------------------------------------------------------- */ void ExecEndMaterial(Material *node) { MaterialState *matstate; - Relation tempRelation; Plan *outerPlan; /* ---------------- @@ -302,14 +223,6 @@ ExecEndMaterial(Material *node) * ---------------- */ matstate = node->matstate; - tempRelation = matstate->mat_TempRelation; - - /* ---------------- - * shut down the scan, but don't close the temp relation - * ---------------- - */ - matstate->csstate.css_currentRelation = NULL; - ExecCloseR((Plan *) node); /* ---------------- * shut down the subplan @@ -325,88 +238,92 @@ ExecEndMaterial(Material *node) ExecClearTuple(matstate->csstate.css_ScanTupleSlot); /* ---------------- - * delete the temp relation + * Release tuplestore resources * ---------------- */ - if (tempRelation != NULL) - heap_drop(tempRelation); + if (matstate->tuplestorestate != NULL) + tuplestore_end((Tuplestorestate *) matstate->tuplestorestate); + matstate->tuplestorestate = NULL; } /* ---------------------------------------------------------------- - * ExecMaterialReScan + * ExecMaterialMarkPos * - * Rescans the temporary relation. + * Calls tuplestore to save the current position in the stored file. * ---------------------------------------------------------------- */ void -ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent) +ExecMaterialMarkPos(Material *node) { - MaterialState *matstate = node->matstate; + MaterialState *matstate = node->matstate; - if (matstate->mat_Flag == false) + /* ---------------- + * if we haven't materialized yet, just return. + * ---------------- + */ + if (!matstate->tuplestorestate) return; - matstate->csstate.css_currentScanDesc = ExecReScanR(matstate->csstate.css_currentRelation, - matstate->csstate.css_currentScanDesc, - node->plan.state->es_direction, 0, NULL); - + tuplestore_markpos((Tuplestorestate *) matstate->tuplestorestate); } -#ifdef NOT_USED /* not used */ /* ---------------------------------------------------------------- - * ExecMaterialMarkPos + * ExecMaterialRestrPos + * + * Calls tuplestore to restore the last saved file position. * ---------------------------------------------------------------- */ -List /* nothing of interest */ -ExecMaterialMarkPos(Material node) +void +ExecMaterialRestrPos(Material *node) { - MaterialState matstate; - HeapScanDesc scan; + MaterialState *matstate = node->matstate; /* ---------------- - * if we haven't materialized yet, just return NIL. + * if we haven't materialized yet, just return. * ---------------- */ - matstate = get_matstate(node); - if (get_mat_Flag(matstate) == false) - return NIL; + if (!matstate->tuplestorestate) + return; /* ---------------- - * XXX access methods don't return positions yet so - * for now we return NIL. It's possible that - * they will never return positions for all I know -cim 10/16/89 + * restore the scan to the previously marked position * ---------------- */ - scan = get_css_currentScanDesc((CommonScanState) matstate); - heap_markpos(scan); - - return NIL; + tuplestore_restorepos((Tuplestorestate *) matstate->tuplestorestate); } /* ---------------------------------------------------------------- - * ExecMaterialRestrPos + * ExecMaterialReScan + * + * Rescans the materialized relation. * ---------------------------------------------------------------- */ void -ExecMaterialRestrPos(Material node) +ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent) { - MaterialState matstate; - HeapScanDesc scan; + MaterialState *matstate = node->matstate; - /* ---------------- - * if we haven't materialized yet, just return. - * ---------------- + /* + * 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. */ - matstate = get_matstate(node); - if (get_mat_Flag(matstate) == false) + if (!matstate->tuplestorestate) return; - /* ---------------- - * restore the scan to the previously marked position - * ---------------- + ExecClearTuple(matstate->csstate.cstate.cs_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. */ - scan = get_css_currentScanDesc((CommonScanState) matstate); - heap_restrpos(scan); + if (((Plan *) node)->lefttree->chgParam != NULL) + { + tuplestore_end((Tuplestorestate *) matstate->tuplestorestate); + matstate->tuplestorestate = NULL; + } + else + tuplestore_rescan((Tuplestorestate *) matstate->tuplestorestate); } - -#endif |