diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index cd20e231ec..d6551cc9c9 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.66 2000/06/08 22:36:54 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.67 2000/06/18 22:43:51 tgl Exp $ * * NOTES * Transaction aborts can now occur two ways: @@ -878,14 +878,6 @@ StartTransaction() AtStart_Locks(); AtStart_Memory(); - /* -------------- - initialize temporary relations list - the tempRelList is a list of temporary relations that - are created in the course of the transactions - they need to be destroyed properly at the end of the transactions - */ - InitNoNameRelList(); - /* ---------------- * Tell the trigger manager to we're starting a transaction * ---------------- @@ -960,7 +952,6 @@ CommitTransaction() AtCommit_Notify(); CloseSequences(); - DropNoNameRels(); AtEOXact_portals(); RecordTransactionCommit(); @@ -1056,7 +1047,6 @@ AbortTransaction() CommonSpecialPortalClose(); RecordTransactionAbort(); RelationPurgeLocalRelation(false); - DropNoNameRels(); invalidate_temp_relations(); AtEOXact_nbtree(); AtAbort_Cache(); diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y index d7a1d9de89..0a6f9d55ac 100644 --- a/src/backend/bootstrap/bootparse.y +++ b/src/backend/bootstrap/bootparse.y @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.29 2000/01/26 05:56:07 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.30 2000/06/18 22:43:51 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -166,7 +166,7 @@ Boot_CreateStmt: puts("creating bootstrap relation"); tupdesc = CreateTupleDesc(numattr,attrtypes); reldesc = heap_create(LexIDStr($3), tupdesc, - false, false, true); + false, true); if (DebugMode) puts("bootstrap relation created ok"); } diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 451eb7f7de..7aeec8adb0 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.132 2000/06/17 23:41:31 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.133 2000/06/18 22:43:55 tgl Exp $ * * * INTERFACE ROUTINES @@ -70,14 +70,11 @@ static void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, int natts, char relkind, char *temp_relname); -static void AddToNoNameRelList(Relation r); - static void DeleteAttributeTuples(Relation rel); static void DeleteRelationTuple(Relation rel); static void DeleteTypeTuple(Relation rel); static void RelationRemoveIndexes(Relation relation); static void RelationRemoveInheritance(Relation relation); -static void RemoveFromNoNameRelList(Relation r); static void AddNewRelationType(char *typeName, Oid new_rel_oid); static void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin, bool updatePgAttribute); @@ -141,22 +138,6 @@ static Form_pg_attribute HeapAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6}; * ---------------------------------------------------------------- */ -/* the tempRelList holds - the list of temporary uncatalogued relations that are created. - these relations should be destroyed at the end of transactions -*/ -typedef struct tempRelList -{ - Relation *rels; /* array of relation descriptors */ - int num; /* number of temporary relations */ - int size; /* size of space allocated for the rels - * array */ -} TempRelList; - -#define NONAME_REL_LIST_SIZE 32 - -static TempRelList *tempRels = NULL; - /* ---------------------------------------------------------------- * heap_create - Create an uncataloged heap relation @@ -170,15 +151,16 @@ static TempRelList *tempRels = NULL; * Eventually, must place information about this temporary relation * into the transaction context block. * + * NOTE: if istemp is TRUE then heap_create will overwrite relname with + * the unique "real" name chosen for the temp relation. * - * if heap_create is called with "" as the name, then heap_create will create - * a temporary name "pg_noname.$PID.$SEQUENCE" for the relation + * If storage_create is TRUE then heap_storage_create is called here, + * else caller must call heap_storage_create later. * ---------------------------------------------------------------- */ Relation heap_create(char *relname, TupleDesc tupDesc, - bool isnoname, bool istemp, bool storage_create) { @@ -245,18 +227,11 @@ heap_create(char *relname, else relid = newoid(); - if (isnoname) - { - Assert(!relname); - relname = palloc(NAMEDATALEN); - snprintf(relname, NAMEDATALEN, "pg_noname.%d.%u", - (int) MyProcPid, uniqueId++); - } - if (istemp) { - /* replace relname of caller */ - snprintf(relname, NAMEDATALEN, "pg_temp.%d.%u", MyProcPid, uniqueId++); + /* replace relname of caller with a unique name for a temp relation */ + snprintf(relname, NAMEDATALEN, "pg_temp.%d.%u", + (int) MyProcPid, uniqueId++); } /* ---------------- @@ -268,7 +243,7 @@ heap_create(char *relname, rel = (Relation) palloc(len); MemSet((char *) rel, 0, len); rel->rd_fd = -1; /* table is not open */ - rel->rd_unlinked = TRUE; /* table is not created yet */ + rel->rd_unlinked = true; /* table is not created yet */ /* * create a new tuple descriptor from the one passed in @@ -310,12 +285,6 @@ heap_create(char *relname, rel->rd_rel->reltype = relid; } - /* ---------------- - * remember if this is a noname relation - * ---------------- - */ - rel->rd_isnoname = isnoname; - /* ---------------- * have the storage manager create the relation. * ---------------- @@ -329,13 +298,6 @@ heap_create(char *relname, MemoryContextSwitchTo(oldcxt); - /* - * add all noname relations to the tempRels list so they can be - * properly disposed of at the end of transaction - */ - if (isnoname) - AddToNoNameRelList(rel); - return rel; } @@ -347,7 +309,7 @@ heap_storage_create(Relation rel) if (rel->rd_unlinked) { rel->rd_fd = (File) smgrcreate(DEFAULT_SMGR, rel); - rel->rd_unlinked = FALSE; + rel->rd_unlinked = false; smgrcall = true; } return smgrcall; @@ -810,7 +772,7 @@ heap_create_with_catalog(char *relname, * get_temp_rel_by_username() couldn't check the simultaneous * creation. Uniqueness will be really checked by unique * indexes of system tables but we couldn't check it here. - * We have to pospone to create the disk file for this + * We have to postpone creating the disk file for this * relation. * Another boolean parameter "storage_create" was added * to heap_create() function. If the parameter is false @@ -821,12 +783,12 @@ heap_create_with_catalog(char *relname, * relation descriptor. * * Note: The call to heap_create() changes relname for - * noname and temp tables. + * temp tables; it becomes the true physical relname. * The call to heap_storage_create() does all the "real" * work of creating the disk file for the relation. * ---------------- */ - new_rel_desc = heap_create(relname, tupdesc, false, istemp, false); + new_rel_desc = heap_create(relname, tupdesc, istemp, false); new_rel_oid = new_rel_desc->rd_att->attrs[0]->attrelid; @@ -1546,10 +1508,9 @@ heap_drop_with_catalog(const char *relname) * unlink the relation's physical file and finish up. * ---------------- */ - if (!(rel->rd_isnoname) || !(rel->rd_unlinked)) + if (! rel->rd_unlinked) smgrunlink(DEFAULT_SMGR, rel); - - rel->rd_unlinked = TRUE; + rel->rd_unlinked = true; /* * Close relcache entry, but *keep* AccessExclusiveLock on the @@ -1568,133 +1529,6 @@ heap_drop_with_catalog(const char *relname) remove_temp_relation(rid); } -/* - * heap_drop - * destroy and close temporary relations - * - */ - -void -heap_drop(Relation rel) -{ - Oid rid = RelationGetRelid(rel); - - ReleaseRelationBuffers(rel); - if (!(rel->rd_isnoname) || !(rel->rd_unlinked)) - smgrunlink(DEFAULT_SMGR, rel); - rel->rd_unlinked = TRUE; - heap_close(rel, NoLock); - RemoveFromNoNameRelList(rel); - RelationForgetRelation(rid); -} - - -/************************************************************** - functions to deal with the list of temporary relations -**************************************************************/ - -/* -------------- - InitTempRellist(): - - initialize temporary relations list - the tempRelList is a list of temporary relations that - are created in the course of the transactions - they need to be destroyed properly at the end of the transactions - - MODIFIES the global variable tempRels - - >> NOTE << - - malloc is used instead of palloc because we KNOW when we are - going to free these things. Keeps us away from the memory context - hairyness - -*/ -void -InitNoNameRelList(void) -{ - if (tempRels) - { - free(tempRels->rels); - free(tempRels); - } - - tempRels = (TempRelList *) malloc(sizeof(TempRelList)); - tempRels->size = NONAME_REL_LIST_SIZE; - tempRels->rels = (Relation *) malloc(sizeof(Relation) * tempRels->size); - MemSet(tempRels->rels, 0, sizeof(Relation) * tempRels->size); - tempRels->num = 0; -} - -/* - removes a relation from the TempRelList - - MODIFIES the global variable tempRels - we don't really remove it, just mark it as NULL - and DropNoNameRels will look for NULLs -*/ -static void -RemoveFromNoNameRelList(Relation r) -{ - int i; - - if (!tempRels) - return; - - for (i = 0; i < tempRels->num; i++) - { - if (tempRels->rels[i] == r) - { - tempRels->rels[i] = NULL; - break; - } - } -} - -/* - add a temporary relation to the TempRelList - - MODIFIES the global variable tempRels -*/ -static void -AddToNoNameRelList(Relation r) -{ - if (!tempRels) - return; - - if (tempRels->num == tempRels->size) - { - tempRels->size += NONAME_REL_LIST_SIZE; - tempRels->rels = realloc(tempRels->rels, - sizeof(Relation) * tempRels->size); - } - tempRels->rels[tempRels->num] = r; - tempRels->num++; -} - -/* - go through the tempRels list and destroy each of the relations -*/ -void -DropNoNameRels(void) -{ - int i; - Relation rel; - - if (!tempRels) - return; - - for (i = 0; i < tempRels->num; i++) - { - rel = tempRels->rels[i]; - /* rel may be NULL if it has been removed from the list already */ - if (rel) - heap_drop(rel); - } - free(tempRels->rels); - free(tempRels); - tempRels = NULL; -} /* * Store a default expression for column attnum of relation rel. diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index b18ae9af64..5b8e005c5f 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.118 2000/06/17 23:41:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.119 2000/06/18 22:43:55 tgl Exp $ * * * INTERFACE ROUTINES @@ -976,7 +976,6 @@ index_create(char *heapRelationName, /* ---------------- * get heap relation oid and open the heap relation - * XXX ADD INDEXING * ---------------- */ heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp); @@ -1012,8 +1011,8 @@ index_create(char *heapRelationName, * create the index relation * ---------------- */ - indexRelation = heap_create(indexRelationName, - indexTupDesc, false, istemp, false); + indexRelation = heap_create(indexRelationName, indexTupDesc, + istemp, false); /* ---------------- * construct the index relation descriptor diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index d51053c20a..25915fe42b 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -5,7 +5,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994-5, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.56 2000/04/12 17:14:58 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.57 2000/06/18 22:43:58 tgl Exp $ * */ @@ -176,9 +176,6 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es) case T_IndexScan: pname = "Index Scan"; break; - case T_Noname: - pname = "Noname Scan"; - break; case T_Material: pname = "Materialize"; break; diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c index ed20aec5a8..ff3fa0b6ed 100644 --- a/src/backend/executor/execAmi.c +++ b/src/backend/executor/execAmi.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: execAmi.c,v 1.47 2000/06/15 04:09:50 momjian Exp $ + * $Id: execAmi.c,v 1.48 2000/06/18 22:44:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,13 +17,9 @@ * ExecBeginScan \ / ambeginscan * ExecCloseR \ / amclose * ExecInsert \ executor interface / aminsert - * ExecReScanNode / to access methods \ amrescan - * ExecReScanR / \ amrescan - * ExecMarkPos / \ ammarkpos - * ExecRestrPos / \ amrestpos - * - * ExecCreatR function to create temporary relations - * + * ExecReScanR / to access methods \ amrescan + * ExecMarkPos / \ ammarkpos + * ExecRestrPos / \ amrestpos */ #include "postgres.h" @@ -49,7 +45,6 @@ #include "executor/nodeSort.h" #include "executor/nodeSubplan.h" #include "executor/nodeUnique.h" -#include "optimizer/internal.h" static Pointer ExecBeginScan(Relation relation, int nkeys, ScanKey skeys, bool isindex, ScanDirection dir, Snapshot snapshot); @@ -170,7 +165,6 @@ ExecBeginScan(Relation relation, if (scanDesc == NULL) elog(DEBUG, "ExecBeginScan: scanDesc = NULL, heap_beginscan failed."); - return scanDesc; } @@ -179,9 +173,6 @@ ExecBeginScan(Relation relation, * * closes the relation and scan descriptor for a scan or sort * node. Also closes index relations and scans for index scans. - * - * old comments - * closes the relation indicated in 'relID' * ---------------------------------------------------------------- */ void @@ -206,10 +197,6 @@ ExecCloseR(Plan *node) state = ((IndexScan *) node)->scan.scanstate; break; - case T_Material: - state = &(((Material *) node)->matstate->csstate); - break; - case T_Sort: state = &(((Sort *) node)->sortstate->csstate); break; @@ -223,7 +210,7 @@ ExecCloseR(Plan *node) break; default: - elog(DEBUG, "ExecCloseR: not a scan, material, or sort node!"); + elog(DEBUG, "ExecCloseR: not a scan or sort node!"); return; } @@ -423,7 +410,7 @@ ExecMarkPos(Plan *node) { switch (nodeTag(node)) { - case T_SeqScan: + case T_SeqScan: ExecSeqMarkPos((SeqScan *) node); break; @@ -431,6 +418,10 @@ ExecMarkPos(Plan *node) ExecIndexMarkPos((IndexScan *) node); break; + case T_Material: + ExecMaterialMarkPos((Material *) node); + break; + case T_Sort: ExecSortMarkPos((Sort *) node); break; @@ -457,7 +448,7 @@ ExecRestrPos(Plan *node) { switch (nodeTag(node)) { - case T_SeqScan: + case T_SeqScan: ExecSeqRestrPos((SeqScan *) node); return; @@ -465,6 +456,10 @@ ExecRestrPos(Plan *node) ExecIndexRestrPos((IndexScan *) node); return; + case T_Material: + ExecMaterialRestrPos((Material *) node); + return; + case T_Sort: ExecSortRestrPos((Sort *) node); return; @@ -474,65 +469,3 @@ ExecRestrPos(Plan *node) return; } } - -/* ---------------------------------------------------------------- - * ExecCreatR - * - * old comments - * Creates a relation. - * - * Parameters: - * attrType -- type information on the attributes. - * accessMtd -- access methods used to access the created relation. - * relation -- optional. Either an index to the range table or - * negative number indicating a temporary relation. - * A temporary relation is assume if this field is absent. - * ---------------------------------------------------------------- - */ - -Relation -ExecCreatR(TupleDesc tupType, - Oid relationOid) -{ - Relation relDesc; - - EU3_printf("ExecCreatR: %s type=%d oid=%u\n", - "entering: ", tupType, relationOid); - CXT1_printf("ExecCreatR: context is %d\n", CurrentMemoryContext); - - relDesc = NULL; - - if (relationOid == _NONAME_RELATION_ID_) - { - /* ---------------- - * create a temporary relation - * (currently the planner always puts a _NONAME_RELATION_ID - * in the relation argument so we expect this to be the case although - * it's possible that someday we'll get the name from - * from the range table.. -cim 10/12/89) - * ---------------- - */ - - /* - * heap_create creates a name if the argument to heap_create is - * '\0 ' - */ - relDesc = heap_create(NULL, tupType, true, false, true); - } - else - { - /* ---------------- - * use a relation from the range table - * ---------------- - */ - elog(DEBUG, "ExecCreatR: %s", - "stuff using range table id's is not functional"); - } - - if (relDesc == NULL) - elog(DEBUG, "ExecCreatR: failed to create relation."); - - EU1_printf("ExecCreatR: returning relDesc=%d\n", relDesc); - - return relDesc; -} diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c index 4348f89ccc..1d5c904248 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); } + /* ---------------- + * Complete the store. + * ---------------- + */ + tuplestore_donestoring(tuplestorestate); + /* ---------------- * restore to user specified direction * ---------------- */ estate->es_direction = dir; - - /* ---------------- - * 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 - * ---------------- - */ - matstate->mat_Flag = true; } /* ---------------- - * at this point we know we have a sorted relation so - * we perform a simple scan on it with amgetnext().. + * Get the first or next tuple from tuplestore. + * Returns NULL if no more tuples. * ---------------- */ - 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.. - * ---------------- - */ - 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); /* ---------------- @@ -225,53 +188,15 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent) outerPlan = outerPlan((Plan *) node); 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,17 +238,64 @@ 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; +} + +/* ---------------------------------------------------------------- + * ExecMaterialMarkPos + * + * Calls tuplestore to save the current position in the stored file. + * ---------------------------------------------------------------- + */ +void +ExecMaterialMarkPos(Material *node) +{ + MaterialState *matstate = node->matstate; + + /* ---------------- + * if we haven't materialized yet, just return. + * ---------------- + */ + if (!matstate->tuplestorestate) + return; + + tuplestore_markpos((Tuplestorestate *) matstate->tuplestorestate); +} + +/* ---------------------------------------------------------------- + * ExecMaterialRestrPos + * + * Calls tuplestore to restore the last saved file position. + * ---------------------------------------------------------------- + */ +void +ExecMaterialRestrPos(Material *node) +{ + MaterialState *matstate = node->matstate; + + /* ---------------- + * if we haven't materialized yet, just return. + * ---------------- + */ + if (!matstate->tuplestorestate) + return; + + /* ---------------- + * restore the scan to the previously marked position + * ---------------- + */ + tuplestore_restorepos((Tuplestorestate *) matstate->tuplestorestate); } /* ---------------------------------------------------------------- * ExecMaterialReScan * - * Rescans the temporary relation. + * Rescans the materialized relation. * ---------------------------------------------------------------- */ void @@ -343,70 +303,27 @@ ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent) { MaterialState *matstate = node->matstate; - if (matstate->mat_Flag == 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 (!matstate->tuplestorestate) return; - matstate->csstate.css_currentScanDesc = ExecReScanR(matstate->csstate.css_currentRelation, - matstate->csstate.css_currentScanDesc, - node->plan.state->es_direction, 0, NULL); + 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. + */ + if (((Plan *) node)->lefttree->chgParam != NULL) + { + tuplestore_end((Tuplestorestate *) matstate->tuplestorestate); + matstate->tuplestorestate = NULL; + } + else + tuplestore_rescan((Tuplestorestate *) matstate->tuplestorestate); } - -#ifdef NOT_USED /* not used */ -/* ---------------------------------------------------------------- - * ExecMaterialMarkPos - * ---------------------------------------------------------------- - */ -List /* nothing of interest */ -ExecMaterialMarkPos(Material node) -{ - MaterialState matstate; - HeapScanDesc scan; - - /* ---------------- - * if we haven't materialized yet, just return NIL. - * ---------------- - */ - matstate = get_matstate(node); - if (get_mat_Flag(matstate) == false) - return NIL; - - /* ---------------- - * 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 - * ---------------- - */ - scan = get_css_currentScanDesc((CommonScanState) matstate); - heap_markpos(scan); - - return NIL; -} - -/* ---------------------------------------------------------------- - * ExecMaterialRestrPos - * ---------------------------------------------------------------- - */ -void -ExecMaterialRestrPos(Material node) -{ - MaterialState matstate; - HeapScanDesc scan; - - /* ---------------- - * if we haven't materialized yet, just return. - * ---------------- - */ - matstate = get_matstate(node); - if (get_mat_Flag(matstate) == false) - return; - - /* ---------------- - * restore the scan to the previously marked position - * ---------------- - */ - scan = get_css_currentScanDesc((CommonScanState) matstate); - heap_restrpos(scan); -} - -#endif diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index e146661fb8..fba792cc84 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.113 2000/04/12 17:15:16 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.114 2000/06/18 22:44:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -414,41 +414,6 @@ _copyHashJoin(HashJoin *from) } -/* ---------------- - * CopyNonameFields - * - * This function copies the fields of the Noname node. It is used by - * all the copy functions for classes which inherit from Noname. - * ---------------- - */ -static void -CopyNonameFields(Noname *from, Noname *newnode) -{ - newnode->nonameid = from->nonameid; - newnode->keycount = from->keycount; - return; -} - - -/* ---------------- - * _copyNoname - * ---------------- - */ -static Noname * -_copyNoname(Noname *from) -{ - Noname *newnode = makeNode(Noname); - - /* ---------------- - * copy node superclass fields - * ---------------- - */ - CopyPlanFields((Plan *) from, (Plan *) newnode); - CopyNonameFields(from, newnode); - - return newnode; -} - /* ---------------- * _copyMaterial * ---------------- @@ -463,7 +428,6 @@ _copyMaterial(Material *from) * ---------------- */ CopyPlanFields((Plan *) from, (Plan *) newnode); - CopyNonameFields((Noname *) from, (Noname *) newnode); return newnode; } @@ -483,7 +447,8 @@ _copySort(Sort *from) * ---------------- */ CopyPlanFields((Plan *) from, (Plan *) newnode); - CopyNonameFields((Noname *) from, (Noname *) newnode); + + newnode->keycount = from->keycount; return newnode; } @@ -552,7 +517,6 @@ _copyUnique(Unique *from) * ---------------- */ CopyPlanFields((Plan *) from, (Plan *) newnode); - CopyNonameFields((Noname *) from, (Noname *) newnode); /* ---------------- * copy remainder of node @@ -1695,9 +1659,6 @@ copyObject(void *from) case T_HashJoin: retval = _copyHashJoin(from); break; - case T_Noname: - retval = _copyNoname(from); - break; case T_Material: retval = _copyMaterial(from); break; diff --git a/src/backend/nodes/freefuncs.c b/src/backend/nodes/freefuncs.c index 59e2ac1154..3353a82d9d 100644 --- a/src/backend/nodes/freefuncs.c +++ b/src/backend/nodes/freefuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.41 2000/05/28 17:55:57 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.42 2000/06/18 22:44:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -305,37 +305,6 @@ _freeHashJoin(HashJoin *node) } -/* ---------------- - * FreeNonameFields - * - * This function frees the fields of the Noname node. It is used by - * all the free functions for classes which inherit node Noname. - * ---------------- - */ -static void -FreeNonameFields(Noname *node) -{ - return; -} - - -/* ---------------- - * _freeNoname - * ---------------- - */ -static void -_freeNoname(Noname *node) -{ - /* ---------------- - * free node superclass fields - * ---------------- - */ - FreePlanFields((Plan *) node); - FreeNonameFields(node); - - pfree(node); -} - /* ---------------- * _freeMaterial * ---------------- @@ -348,7 +317,6 @@ _freeMaterial(Material *node) * ---------------- */ FreePlanFields((Plan *) node); - FreeNonameFields((Noname *) node); pfree(node); } @@ -366,7 +334,6 @@ _freeSort(Sort *node) * ---------------- */ FreePlanFields((Plan *) node); - FreeNonameFields((Noname *) node); pfree(node); } @@ -421,7 +388,6 @@ _freeUnique(Unique *node) * ---------------- */ FreePlanFields((Plan *) node); - FreeNonameFields((Noname *) node); /* ---------------- * free remainder of node @@ -1194,9 +1160,6 @@ freeObject(void *node) case T_HashJoin: _freeHashJoin(node); break; - case T_Noname: - _freeNoname(node); - break; case T_Material: _freeMaterial(node); break; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 7858542562..b9830edc22 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.119 2000/06/16 05:27:02 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.120 2000/06/18 22:44:05 tgl Exp $ * * NOTES * Every (plan) node in POSTGRES has an associated "out" routine which @@ -531,51 +531,29 @@ _outTidScan(StringInfo str, TidScan *node) } /* - * Noname is a subclass of Plan - */ -static void -_outNoname(StringInfo str, Noname *node) -{ - appendStringInfo(str, " NONAME "); - _outPlanInfo(str, (Plan *) node); - - appendStringInfo(str, " :nonameid %u :keycount %d ", - node->nonameid, - node->keycount); -} - -/* - * Material is a subclass of Noname + * Material is a subclass of Plan */ static void _outMaterial(StringInfo str, Material *node) { appendStringInfo(str, " MATERIAL "); _outPlanInfo(str, (Plan *) node); - - appendStringInfo(str, " :nonameid %u :keycount %d ", - node->nonameid, - node->keycount); } /* - * Sort is a subclass of Noname + * Sort is a subclass of Plan */ static void _outSort(StringInfo str, Sort *node) { appendStringInfo(str, " SORT "); _outPlanInfo(str, (Plan *) node); - - appendStringInfo(str, " :nonameid %u :keycount %d ", - node->nonameid, - node->keycount); + appendStringInfo(str, " :keycount %d ", node->keycount); } static void _outAgg(StringInfo str, Agg *node) { - appendStringInfo(str, " AGG "); _outPlanInfo(str, (Plan *) node); } @@ -592,9 +570,6 @@ _outGroup(StringInfo str, Group *node) node->tuplePerGroup ? "true" : "false"); } -/* - * For some reason, unique is a subclass of Noname. - */ static void _outUnique(StringInfo str, Unique *node) { @@ -603,17 +578,14 @@ _outUnique(StringInfo str, Unique *node) appendStringInfo(str, " UNIQUE "); _outPlanInfo(str, (Plan *) node); - appendStringInfo(str, " :nonameid %u :keycount %d :numCols %d :uniqColIdx ", - node->nonameid, - node->keycount, + appendStringInfo(str, " :numCols %d :uniqColIdx ", node->numCols); - for (i = 0; i < node->numCols; i++) appendStringInfo(str, "%d ", (int) node->uniqColIdx[i]); } /* - * Hash is a subclass of Noname + * Hash is a subclass of Plan */ static void _outHash(StringInfo str, Hash *node) @@ -1502,9 +1474,6 @@ _outNode(StringInfo str, void *obj) case T_TidScan: _outTidScan(str, obj); break; - case T_Noname: - _outNoname(str, obj); - break; case T_Material: _outMaterial(str, obj); break; diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c index 8d3cd8d2a7..104735cf6f 100644 --- a/src/backend/nodes/print.c +++ b/src/backend/nodes/print.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.38 2000/04/12 17:15:16 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.39 2000/06/18 22:44:05 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -315,9 +315,6 @@ plannode_type(Plan *p) case T_HashJoin: return "HASHJOIN"; break; - case T_Noname: - return "NONAME"; - break; case T_Material: return "MATERIAL"; break; @@ -333,9 +330,6 @@ plannode_type(Plan *p) case T_Hash: return "HASH"; break; - case T_Choose: - return "CHOOSE"; - break; case T_Group: return "GROUP"; break; diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 99d25696ce..f872d952d0 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.90 2000/06/16 05:27:03 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.91 2000/06/18 22:44:05 tgl Exp $ * * NOTES * Most of the read functions for plan nodes are tested. (In fact, they @@ -555,38 +555,10 @@ _readTidScan() return local_node; } -/* ---------------- - * _readNoname - * - * Noname is a subclass of Plan - * ---------------- - */ -static Noname * -_readNoname() -{ - Noname *local_node; - char *token; - int length; - - local_node = makeNode(Noname); - - _getPlan((Plan *) local_node); - - token = lsptok(NULL, &length); /* eat :nonameid */ - token = lsptok(NULL, &length); /* get nonameid */ - local_node->nonameid = atol(token); - - token = lsptok(NULL, &length); /* eat :keycount */ - token = lsptok(NULL, &length); /* get keycount */ - local_node->keycount = atoi(token); - - return local_node; -} - /* ---------------- * _readSort * - * Sort is a subclass of Noname + * Sort is a subclass of Plan * ---------------- */ static Sort * @@ -600,10 +572,6 @@ _readSort() _getPlan((Plan *) local_node); - token = lsptok(NULL, &length); /* eat :nonameid */ - token = lsptok(NULL, &length); /* get nonameid */ - local_node->nonameid = atol(token); - token = lsptok(NULL, &length); /* eat :keycount */ token = lsptok(NULL, &length); /* get keycount */ local_node->keycount = atoi(token); @@ -625,7 +593,7 @@ _readAgg() /* ---------------- * _readHash * - * Hash is a subclass of Noname + * Hash is a subclass of Plan * ---------------- */ static Hash * @@ -1853,8 +1821,6 @@ parsePlanString(void) return_value = _readIndexScan(); else if (length == 7 && strncmp(token, "TIDSCAN", length) == 0) return_value = _readTidScan(); - else if (length == 6 && strncmp(token, "NONAME", length) == 0) - return_value = _readNoname(); else if (length == 4 && strncmp(token, "SORT", length) == 0) return_value = _readSort(); else if (length == 6 && strncmp(token, "AGGREG", length) == 0) diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index b718f8fea1..0f26dc7872 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -42,7 +42,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.61 2000/05/31 00:28:22 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.62 2000/06/18 22:44:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -55,10 +55,15 @@ #include "miscadmin.h" #include "optimizer/clauses.h" #include "optimizer/cost.h" -#include "optimizer/internal.h" #include "utils/lsyscache.h" +/* + * The length of a variable-length field in bytes (stupid estimate...) + */ +#define _DEFAULT_ATTRIBUTE_WIDTH_ 12 + + #define LOG2(x) (log(x) / 0.693147180559945) #define LOG6(x) (log(x) / 1.79175946922805) @@ -114,29 +119,17 @@ cost_seqscan(Path *path, RelOptInfo *baserel) if (!enable_seqscan) startup_cost += disable_cost; - /* disk costs */ - if (lfirsti(baserel->relids) < 0) - { - - /* - * cost of sequentially scanning a materialized temporary relation - */ - run_cost += _NONAME_SCAN_COST_; - } - else - { - - /* - * The cost of reading a page sequentially is 1.0, by definition. - * Note that the Unix kernel will typically do some amount of - * read-ahead optimization, so that this cost is less than the - * true cost of reading a page from disk. We ignore that issue - * here, but must take it into account when estimating the cost of - * non-sequential accesses! - */ - run_cost += baserel->pages; /* sequential fetches with cost - * 1.0 */ - } + /* + * disk costs + * + * The cost of reading a page sequentially is 1.0, by definition. + * Note that the Unix kernel will typically do some amount of + * read-ahead optimization, so that this cost is less than the + * true cost of reading a page from disk. We ignore that issue + * here, but must take it into account when estimating the cost of + * non-sequential accesses! + */ + run_cost += baserel->pages; /* sequential fetches with cost 1.0 */ /* CPU costs */ cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost; diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 015b6b2b10..4915133d0a 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.92 2000/06/15 03:32:13 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.93 2000/06/18 22:44:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,7 +23,6 @@ #include "nodes/nodeFuncs.h" #include "optimizer/clauses.h" #include "optimizer/cost.h" -#include "optimizer/internal.h" #include "optimizer/paths.h" #include "optimizer/planmain.h" #include "optimizer/restrictinfo.h" @@ -34,7 +33,6 @@ static List *switch_outer(List *clauses); -static int set_tlist_sort_info(List *tlist, List *pathkeys); static Scan *create_scan_node(Query *root, Path *best_path, List *tlist); static Join *create_join_node(Query *root, JoinPath *best_path, List *tlist); static SeqScan *create_seqscan_node(Path *best_path, List *tlist, @@ -71,8 +69,6 @@ static HashJoin *make_hashjoin(List *tlist, List *qpqual, static Hash *make_hash(List *tlist, Var *hashkey, Plan *lefttree); static MergeJoin *make_mergejoin(List *tlist, List *qpqual, List *mergeclauses, Plan *righttree, Plan *lefttree); -static Material *make_material(List *tlist, Oid nonameid, Plan *lefttree, - int keycount); static void copy_path_costsize(Plan *dest, Path *src); static void copy_plan_costsize(Plan *dest, Plan *src); static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid); @@ -560,10 +556,12 @@ create_nestloop_node(NestPath *best_path, } else if (IsA(inner_node, TidScan)) { - List *inner_tideval = ((TidScan *) inner_node)->tideval; TidScan *innerscan = (TidScan *) inner_node; - ((TidScan *) inner_node)->tideval = join_references(inner_tideval, outer_tlist, inner_tlist, innerscan->scan.scanrelid); + innerscan->tideval = join_references(innerscan->tideval, + outer_tlist, + inner_tlist, + innerscan->scan.scanrelid); } else if (IsA_Join(inner_node)) { @@ -575,9 +573,8 @@ create_nestloop_node(NestPath *best_path, * join --- how can we estimate whether this is a good thing to * do? */ - inner_node = (Plan *) make_noname(inner_tlist, - NIL, - inner_node); + inner_node = (Plan *) make_material(inner_tlist, + inner_node); } join_node = make_nestloop(tlist, @@ -632,14 +629,16 @@ create_mergejoin_node(MergePath *best_path, * necessary. The sort cost was already accounted for in the path. */ if (best_path->outersortkeys) - outer_node = (Plan *) make_noname(outer_tlist, - best_path->outersortkeys, - outer_node); + outer_node = (Plan *) + make_sort_from_pathkeys(outer_tlist, + outer_node, + best_path->outersortkeys); if (best_path->innersortkeys) - inner_node = (Plan *) make_noname(inner_tlist, - best_path->innersortkeys, - inner_node); + inner_node = (Plan *) + make_sort_from_pathkeys(inner_tlist, + inner_node, + best_path->innersortkeys); join_node = make_mergejoin(tlist, qpqual, @@ -958,72 +957,6 @@ switch_outer(List *clauses) return t_list; } -/* - * set_tlist_sort_info - * Sets the reskey and reskeyop fields of resdom nodes in a target list - * for a sort node. - * - * 'tlist' is the target list (which is modified in-place). - * tlist's reskey fields must be clear to start with. - * 'pathkeys' is the desired pathkeys for the sort. NIL means no sort. - * - * Returns the number of sort keys assigned (which might be less than - * length(pathkeys)!) - */ -static int -set_tlist_sort_info(List *tlist, List *pathkeys) -{ - int keysassigned = 0; - List *i; - - foreach(i, pathkeys) - { - List *keysublist = (List *) lfirst(i); - PathKeyItem *pathkey = NULL; - Resdom *resdom = NULL; - List *j; - - /* - * We can sort by any one of the sort key items listed in this - * sublist. For now, we take the first one that corresponds to an - * available Var in the tlist. - * - * XXX if we have a choice, is there any way of figuring out which - * might be cheapest to execute? (For example, int4lt is likely - * much cheaper to execute than numericlt, but both might appear - * in the same pathkey sublist...) Not clear that we ever will - * have a choice in practice, so it may not matter. - */ - foreach(j, keysublist) - { - pathkey = lfirst(j); - Assert(IsA(pathkey, PathKeyItem)); - resdom = tlist_member(pathkey->key, tlist); - if (resdom) - break; - } - if (!resdom) - elog(ERROR, "set_tlist_sort_info: cannot find tlist item to sort"); - - /* - * The resdom might be already marked as a sort key, if the - * pathkeys contain duplicate entries. (This can happen in - * scenarios where multiple mergejoinable clauses mention the same - * var, for example.) In that case the current pathkey is - * essentially a no-op, because only one value can be seen within - * any subgroup where it would be consulted. We can ignore it. - */ - if (resdom->reskey == 0) - { - /* OK, mark it as a sort key and set the sort operator regproc */ - resdom->reskey = ++keysassigned; - resdom->reskeyop = get_opcode(pathkey->sortop); - } - } - - return keysassigned; -} - /* * Copy cost and size info from a Path node to the Plan node created from it. * The executor won't use this info, but it's needed by EXPLAIN. @@ -1078,50 +1011,7 @@ copy_plan_costsize(Plan *dest, Plan *src) * *****************************************************************************/ -/* - * make_noname - * Create plan node to sort or materialize relations into noname. - * - * 'tlist' is the target list of the scan to be sorted or materialized - * 'pathkeys' is the list of pathkeys by which the result is to be sorted - * (NIL implies no sort needed, just materialize it) - * 'subplan' is the node which yields input tuples - */ -Noname * -make_noname(List *tlist, - List *pathkeys, - Plan *subplan) -{ - List *noname_tlist; - int numsortkeys; - Plan *retval; - - /* Create a new target list for the noname, with sort keys set. */ - noname_tlist = new_unsorted_tlist(tlist); - numsortkeys = set_tlist_sort_info(noname_tlist, pathkeys); - - if (numsortkeys > 0) - { - /* need to sort */ - retval = (Plan *) make_sort(noname_tlist, - _NONAME_RELATION_ID_, - subplan, - numsortkeys); - } - else - { - /* no sort */ - retval = (Plan *) make_material(noname_tlist, - _NONAME_RELATION_ID_, - subplan, - 0); - } - - return (Noname *) retval; -} - - -static SeqScan * +static SeqScan * make_seqscan(List *qptlist, List *qpqual, Index scanrelid) @@ -1256,8 +1146,14 @@ make_mergejoin(List *tlist, return node; } +/* + * To use make_sort directly, you must already have marked the tlist + * with reskey and reskeyop information. The keys had better be + * non-redundant, too (ie, there had better be tlist items marked with + * each key number from 1 to keycount), or the executor will get confused! + */ Sort * -make_sort(List *tlist, Oid nonameid, Plan *lefttree, int keycount) +make_sort(List *tlist, Plan *lefttree, int keycount) { Sort *node = makeNode(Sort); Plan *plan = &node->plan; @@ -1272,17 +1168,84 @@ make_sort(List *tlist, Oid nonameid, Plan *lefttree, int keycount) plan->qual = NIL; plan->lefttree = lefttree; plan->righttree = NULL; - node->nonameid = nonameid; node->keycount = keycount; return node; } -static Material * -make_material(List *tlist, - Oid nonameid, - Plan *lefttree, - int keycount) +/* + * make_sort_from_pathkeys + * Create sort plan to sort according to given pathkeys + * + * 'tlist' is the target list of the input plan + * 'lefttree' is the node which yields input tuples + * 'pathkeys' is the list of pathkeys by which the result is to be sorted + * + * We must convert the pathkey information into reskey and reskeyop fields + * of resdom nodes in the sort plan's target list. + */ +Sort * +make_sort_from_pathkeys(List *tlist, Plan *lefttree, List *pathkeys) +{ + List *sort_tlist; + List *i; + int numsortkeys = 0; + + /* Create a new target list for the sort, with sort keys set. */ + sort_tlist = new_unsorted_tlist(tlist); + + foreach(i, pathkeys) + { + List *keysublist = (List *) lfirst(i); + PathKeyItem *pathkey = NULL; + Resdom *resdom = NULL; + List *j; + + /* + * We can sort by any one of the sort key items listed in this + * sublist. For now, we take the first one that corresponds to an + * available Var in the sort_tlist. + * + * XXX if we have a choice, is there any way of figuring out which + * might be cheapest to execute? (For example, int4lt is likely + * much cheaper to execute than numericlt, but both might appear + * in the same pathkey sublist...) Not clear that we ever will + * have a choice in practice, so it may not matter. + */ + foreach(j, keysublist) + { + pathkey = lfirst(j); + Assert(IsA(pathkey, PathKeyItem)); + resdom = tlist_member(pathkey->key, sort_tlist); + if (resdom) + break; + } + if (!resdom) + elog(ERROR, "make_sort_from_pathkeys: cannot find tlist item to sort"); + + /* + * The resdom might be already marked as a sort key, if the + * pathkeys contain duplicate entries. (This can happen in + * scenarios where multiple mergejoinable clauses mention the same + * var, for example.) In that case the current pathkey is + * essentially a no-op, because only one value can be seen within + * any subgroup where it would be consulted. We can ignore it. + */ + if (resdom->reskey == 0) + { + /* OK, mark it as a sort key and set the sort operator regproc */ + resdom->reskey = ++numsortkeys; + resdom->reskeyop = get_opcode(pathkey->sortop); + } + } + + Assert(numsortkeys > 0); + + return make_sort(sort_tlist, lefttree, numsortkeys); +} + +Material * +make_material(List *tlist, Plan *lefttree) { Material *node = makeNode(Material); Plan *plan = &node->plan; @@ -1291,8 +1254,9 @@ make_material(List *tlist, /* * For plausibility, make startup & total costs equal total cost of - * input plan; this only affects EXPLAIN display not decisions. XXX - * shouldn't we charge some additional cost for materialization? + * input plan; this only affects EXPLAIN display not decisions. + * + * XXX shouldn't we charge some additional cost for materialization? */ plan->startup_cost = plan->total_cost; plan->state = (EState *) NULL; @@ -1300,8 +1264,6 @@ make_material(List *tlist, plan->qual = NIL; plan->lefttree = lefttree; plan->righttree = NULL; - node->nonameid = nonameid; - node->keycount = keycount; return node; } @@ -1420,8 +1382,6 @@ make_unique(List *tlist, Plan *lefttree, List *distinctList) plan->qual = NIL; plan->lefttree = lefttree; plan->righttree = NULL; - node->nonameid = _NONAME_RELATION_ID_; - node->keycount = 0; /* * convert SortClause list into array of attr indexes, as wanted by diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index fdb7be9244..49d400dee9 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.83 2000/06/15 03:32:13 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.84 2000/06/18 22:44:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,7 +21,6 @@ #include "executor/executor.h" #include "nodes/makefuncs.h" #include "optimizer/clauses.h" -#include "optimizer/internal.h" #include "optimizer/paths.h" #include "optimizer/plancat.h" #include "optimizer/planmain.h" @@ -40,7 +39,7 @@ static List *make_subplanTargetList(Query *parse, List *tlist, static Plan *make_groupplan(List *group_tlist, bool tuplePerGroup, List *groupClause, AttrNumber *grpColIdx, bool is_presorted, Plan *subplan); -static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode); +static Plan *make_sortplan(List *tlist, Plan *plannode, List *sortcls); /***************************************************************************** * @@ -641,7 +640,8 @@ union_planner(Query *parse, if (parse->sortClause) { if (!pathkeys_contained_in(sort_pathkeys, current_pathkeys)) - result_plan = make_sortplan(tlist, parse->sortClause, result_plan); + result_plan = make_sortplan(tlist, result_plan, + parse->sortClause); } /* @@ -818,10 +818,9 @@ make_groupplan(List *group_tlist, } } - subplan = (Plan *) make_sort(sort_tlist, - _NONAME_RELATION_ID_, - subplan, - keyno); + Assert(keyno > 0); + + subplan = (Plan *) make_sort(sort_tlist, subplan, keyno); } return (Plan *) make_group(group_tlist, tuplePerGroup, numCols, @@ -833,9 +832,9 @@ make_groupplan(List *group_tlist, * Add a Sort node to implement an explicit ORDER BY clause. */ static Plan * -make_sortplan(List *tlist, List *sortcls, Plan *plannode) +make_sortplan(List *tlist, Plan *plannode, List *sortcls) { - List *temp_tlist; + List *sort_tlist; List *i; int keyno = 0; @@ -843,13 +842,12 @@ make_sortplan(List *tlist, List *sortcls, Plan *plannode) * First make a copy of the tlist so that we don't corrupt the * original. */ - - temp_tlist = new_unsorted_tlist(tlist); + sort_tlist = new_unsorted_tlist(tlist); foreach(i, sortcls) { SortClause *sortcl = (SortClause *) lfirst(i); - TargetEntry *tle = get_sortgroupclause_tle(sortcl, temp_tlist); + TargetEntry *tle = get_sortgroupclause_tle(sortcl, sort_tlist); Resdom *resdom = tle->resdom; /* @@ -865,10 +863,9 @@ make_sortplan(List *tlist, List *sortcls, Plan *plannode) } } - return (Plan *) make_sort(temp_tlist, - _NONAME_RELATION_ID_, - plannode, - keyno); + Assert(keyno > 0); + + return (Plan *) make_sort(sort_tlist, plannode, keyno); } /* diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 87e508ef8f..cd624fb111 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.37 2000/05/30 00:49:47 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.38 2000/06/18 22:44:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -363,9 +363,7 @@ make_subplan(SubLink *slink) } if (use_material) { - plan = (Plan *) make_noname(plan->targetlist, - NIL, - plan); + plan = (Plan *) make_material(plan->targetlist, plan); node->plan = plan; } } diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index da7059ce91..070fabf766 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -8,14 +8,13 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.26 2000/04/12 17:15:24 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.27 2000/06/18 22:44:12 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "optimizer/cost.h" -#include "optimizer/internal.h" #include "optimizer/joininfo.h" #include "optimizer/pathnode.h" #include "optimizer/plancat.h" @@ -76,26 +75,9 @@ get_base_rel(Query *root, int relid) rel->joininfo = NIL; rel->innerjoin = NIL; - if (relid < 0) - { - - /* - * If the relation is a materialized relation, assume constants - * for sizes. - */ - rel->pages = _NONAME_RELATION_PAGES_; - rel->tuples = _NONAME_RELATION_TUPLES_; - } - else - { - - /* - * Otherwise, retrieve relation statistics from the system - * catalogs. - */ - relation_info(root, relid, - &rel->indexed, &rel->pages, &rel->tuples); - } + /* Retrieve relation statistics from the system catalogs. */ + relation_info(root, relid, + &rel->indexed, &rel->pages, &rel->tuples); root->base_rel_list = lcons(rel, root->base_rel_list); diff --git a/src/backend/utils/adt/chunk.c b/src/backend/utils/adt/chunk.c index 1d8ec1aec8..5577676949 100644 --- a/src/backend/utils/adt/chunk.c +++ b/src/backend/utils/adt/chunk.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/chunk.c,v 1.27 2000/06/13 07:35:03 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/chunk.c,v 1.28 2000/06/18 22:44:13 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,7 +21,6 @@ #include "fmgr.h" #include "libpq/be-fsstubs.h" #include "libpq/libpq-fs.h" -#include "optimizer/internal.h" #include "utils/array.h" #include "utils/memutils.h" diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 4fe3e35b1e..93375a7c15 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.101 2000/06/17 21:48:55 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.102 2000/06/18 22:44:17 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1784,21 +1784,15 @@ RelationPurgeLocalRelation(bool xactCommitted) if (!xactCommitted) { - /* * remove the file if we abort. This is so that files for * tables created inside a transaction block get removed. */ - if (reln->rd_isnoname) + if (! reln->rd_unlinked) { - if (!(reln->rd_unlinked)) - { - smgrunlink(DEFAULT_SMGR, reln); - reln->rd_unlinked = TRUE; - } - } - else smgrunlink(DEFAULT_SMGR, reln); + reln->rd_unlinked = true; + } } if (!IsBootstrapProcessingMode()) diff --git a/src/backend/utils/sort/Makefile b/src/backend/utils/sort/Makefile index f0e56ace0a..2ae96894b9 100644 --- a/src/backend/utils/sort/Makefile +++ b/src/backend/utils/sort/Makefile @@ -4,14 +4,14 @@ # Makefile for utils/sort # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/utils/sort/Makefile,v 1.10 2000/05/29 05:45:40 tgl Exp $ +# $Header: /cvsroot/pgsql/src/backend/utils/sort/Makefile,v 1.11 2000/06/18 22:44:20 tgl Exp $ # #------------------------------------------------------------------------- SRCDIR = ../../.. include ../../../Makefile.global -OBJS = logtape.o tuplesort.o +OBJS = logtape.o tuplesort.o tuplestore.o all: SUBSYS.o diff --git a/src/backend/utils/sort/tuplestore.c b/src/backend/utils/sort/tuplestore.c new file mode 100644 index 0000000000..b1eb56cc2a --- /dev/null +++ b/src/backend/utils/sort/tuplestore.c @@ -0,0 +1,685 @@ +/*------------------------------------------------------------------------- + * + * tuplestore.c + * Generalized routines for temporary tuple storage. + * + * This module handles temporary storage of tuples for purposes such + * as Materialize nodes, hashjoin batch files, etc. It is essentially + * a dumbed-down version of tuplesort.c; it does no sorting of tuples + * but can only store a sequence of tuples and regurgitate it later. + * A temporary file is used to handle the data if it exceeds the + * space limit specified by the caller. + * + * The (approximate) amount of memory allowed to the tuplestore is specified + * in kilobytes by the caller. We absorb tuples and simply store them in an + * in-memory array as long as we haven't exceeded maxKBytes. If we reach the + * end of the input without exceeding maxKBytes, we just return tuples during + * the read phase by scanning the tuple array sequentially. If we do exceed + * maxKBytes, we dump all the tuples into a temp file and then read from that + * during the read phase. + * + * When the caller requests random access to the data, we write the temp file + * in a format that allows either forward or backward scan. + * + * + * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplestore.c,v 1.1 2000/06/18 22:44:20 tgl Exp $ + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/heapam.h" +#include "storage/buffile.h" +#include "utils/tuplestore.h" + +/* + * Possible states of a Tuplestore object. These denote the states that + * persist between calls of Tuplestore routines. + */ +typedef enum +{ + TSS_INITIAL, /* Loading tuples; still within memory + * limit */ + TSS_WRITEFILE, /* Loading tuples; writing to temp file */ + TSS_READMEM, /* Reading tuples; entirely in memory */ + TSS_READFILE /* Reading tuples from temp file */ +} TupStoreStatus; + +/* + * Private state of a Tuplestore operation. + */ +struct Tuplestorestate +{ + TupStoreStatus status; /* enumerated value as shown above */ + bool randomAccess; /* did caller request random access? */ + long availMem; /* remaining memory available, in bytes */ + BufFile *myfile; /* underlying file, or NULL if none */ + + /* + * These function pointers decouple the routines that must know what + * kind of tuple we are handling from the routines that don't need to + * know it. They are set up by the tuplestore_begin_xxx routines. + * + * (Although tuplestore.c currently only supports heap tuples, I've + * copied this part of tuplesort.c so that extension to other kinds + * of objects will be easy if it's ever needed.) + * + * Function to copy a supplied input tuple into palloc'd space. (NB: + * we assume that a single pfree() is enough to release the tuple + * later, so the representation must be "flat" in one palloc chunk.) + * state->availMem must be decreased by the amount of space used. + */ + void *(*copytup) (Tuplestorestate *state, void *tup); + + /* + * Function to write a stored tuple onto tape. The representation of + * the tuple on tape need not be the same as it is in memory; + * requirements on the tape representation are given below. After + * writing the tuple, pfree() it, and increase state->availMem by the + * amount of memory space thereby released. + */ + void (*writetup) (Tuplestorestate *state, void *tup); + + /* + * Function to read a stored tuple from tape back into memory. 'len' + * is the already-read length of the stored tuple. Create and return + * a palloc'd copy, and decrease state->availMem by the amount of + * memory space consumed. + */ + void *(*readtup) (Tuplestorestate *state, unsigned int len); + + /* + * This array holds pointers to tuples in memory if we are in state + * INITIAL or READMEM. In states WRITEFILE and READFILE it's not used. + */ + void **memtuples; /* array of pointers to palloc'd tuples */ + int memtupcount; /* number of tuples currently present */ + int memtupsize; /* allocated length of memtuples array */ + + /* + * These variables are used after completion of storing to keep track + * of the next tuple to return. (In the tape case, the tape's current + * read position is also critical state.) + */ + int current; /* array index (only used if READMEM) */ + bool eof_reached; /* reached EOF (needed for cursors) */ + + /* markpos_xxx holds marked position for mark and restore */ + int markpos_file; /* file# (only used if READFILE) */ + long markpos_offset; /* saved "current", or offset in tape file */ + bool markpos_eof; /* saved "eof_reached" */ +}; + +#define COPYTUP(state,tup) ((*(state)->copytup) (state, tup)) +#define WRITETUP(state,tup) ((*(state)->writetup) (state, tup)) +#define READTUP(state,len) ((*(state)->readtup) (state, len)) +#define LACKMEM(state) ((state)->availMem < 0) +#define USEMEM(state,amt) ((state)->availMem -= (amt)) +#define FREEMEM(state,amt) ((state)->availMem += (amt)) + +/*-------------------- + * + * NOTES about on-tape representation of tuples: + * + * We require the first "unsigned int" of a stored tuple to be the total size + * on-tape of the tuple, including itself (so it is never zero; an all-zero + * unsigned int is used to delimit runs). The remainder of the stored tuple + * may or may not match the in-memory representation of the tuple --- + * any conversion needed is the job of the writetup and readtup routines. + * + * If state->randomAccess is true, then the stored representation of the + * tuple must be followed by another "unsigned int" that is a copy of the + * length --- so the total tape space used is actually sizeof(unsigned int) + * more than the stored length value. This allows read-backwards. When + * randomAccess is not true, the write/read routines may omit the extra + * length word. + * + * writetup is expected to write both length words as well as the tuple + * data. When readtup is called, the tape is positioned just after the + * front length word; readtup must read the tuple data and advance past + * the back length word (if present). + * + * The write/read routines can make use of the tuple description data + * stored in the Tuplestorestate record, if needed. They are also expected + * to adjust state->availMem by the amount of memory space (not tape space!) + * released or consumed. There is no error return from either writetup + * or readtup; they should elog() on failure. + * + * + * NOTES about memory consumption calculations: + * + * We count space requested for tuples against the maxKBytes limit. + * Fixed-size space (primarily the BufFile I/O buffer) is not + * counted, nor do we count the variable-size memtuples array. + * (Even though that could grow pretty large, it should be small compared + * to the tuples proper, so this is not unreasonable.) + * + * The major deficiency in this approach is that it ignores palloc overhead. + * The memory space actually allocated for a palloc chunk is always more + * than the request size, and could be considerably more (as much as 2X + * larger, in the current aset.c implementation). So the space used could + * be considerably more than maxKBytes says. + * + * One way to fix this is to add a memory management function that, given + * a pointer to a palloc'd chunk, returns the actual space consumed by the + * chunk. This would be very easy in the current aset.c module, but I'm + * hesitant to do it because it might be unpleasant to support in future + * implementations of memory management. (For example, a direct + * implementation of palloc as malloc could not support such a function + * portably.) + * + * A cruder answer is just to apply a fudge factor, say by initializing + * availMem to only three-quarters of what maxKBytes indicates. This is + * probably the right answer if anyone complains that maxKBytes is not being + * obeyed very faithfully. + * + *-------------------- + */ + + +static Tuplestorestate *tuplestore_begin_common(bool randomAccess, + int maxKBytes); +static void dumptuples(Tuplestorestate *state); +static unsigned int getlen(Tuplestorestate *state, bool eofOK); +static void markrunend(Tuplestorestate *state); +static void *copytup_heap(Tuplestorestate *state, void *tup); +static void writetup_heap(Tuplestorestate *state, void *tup); +static void *readtup_heap(Tuplestorestate *state, unsigned int len); + + +/* + * tuplestore_begin_xxx + * + * Initialize for a tuple store operation. + * + * After calling tuplestore_begin, the caller should call tuplestore_puttuple + * zero or more times, then call tuplestore_donestoring when all the tuples + * have been supplied. After donestoring, retrieve the tuples in order + * by calling tuplestore_gettuple until it returns NULL. (If random + * access was requested, rescan, markpos, and restorepos can also be called.) + * Call tuplestore_end to terminate the operation and release memory/disk + * space. + */ + +static Tuplestorestate * +tuplestore_begin_common(bool randomAccess, int maxKBytes) +{ + Tuplestorestate *state; + + state = (Tuplestorestate *) palloc(sizeof(Tuplestorestate)); + + MemSet((char *) state, 0, sizeof(Tuplestorestate)); + + state->status = TSS_INITIAL; + state->randomAccess = randomAccess; + state->availMem = maxKBytes * 1024L; + state->myfile = NULL; + + state->memtupcount = 0; + if (maxKBytes > 0) + state->memtupsize = 1024; /* initial guess */ + else + state->memtupsize = 1; /* won't really need any space */ + state->memtuples = (void **) palloc(state->memtupsize * sizeof(void *)); + + return state; +} + +Tuplestorestate * +tuplestore_begin_heap(bool randomAccess, int maxKBytes) +{ + Tuplestorestate *state = tuplestore_begin_common(randomAccess, maxKBytes); + + state->copytup = copytup_heap; + state->writetup = writetup_heap; + state->readtup = readtup_heap; + + return state; +} + +/* + * tuplestore_end + * + * Release resources and clean up. + */ +void +tuplestore_end(Tuplestorestate *state) +{ + int i; + + if (state->myfile) + BufFileClose(state->myfile); + if (state->memtuples) + { + for (i = 0; i < state->memtupcount; i++) + pfree(state->memtuples[i]); + pfree(state->memtuples); + } +} + +/* + * Accept one tuple while collecting input data. + * + * Note that the input tuple is always copied; the caller need not save it. + */ +void +tuplestore_puttuple(Tuplestorestate *state, void *tuple) +{ + /* + * Copy the tuple. (Must do this even in WRITEFILE case.) + */ + tuple = COPYTUP(state, tuple); + + switch (state->status) + { + case TSS_INITIAL: + /* + * Stash the tuple in the in-memory array. + */ + if (state->memtupcount >= state->memtupsize) + { + /* Grow the array as needed. */ + state->memtupsize *= 2; + state->memtuples = (void **) + repalloc(state->memtuples, + state->memtupsize * sizeof(void *)); + } + state->memtuples[state->memtupcount++] = tuple; + + /* + * Done if we still fit in available memory. + */ + if (!LACKMEM(state)) + return; + + /* + * Nope; time to switch to tape-based operation. + */ + state->myfile = BufFileCreateTemp(); + state->status = TSS_WRITEFILE; + dumptuples(state); + break; + case TSS_WRITEFILE: + WRITETUP(state, tuple); + break; + default: + elog(ERROR, "tuplestore_puttuple: invalid state"); + break; + } +} + +/* + * All tuples have been provided; finish writing. + */ +void +tuplestore_donestoring(Tuplestorestate *state) +{ + switch (state->status) + { + case TSS_INITIAL: + /* + * We were able to accumulate all the tuples within the + * allowed amount of memory. Just set up to scan them. + */ + state->current = 0; + state->eof_reached = false; + state->markpos_offset = 0L; + state->markpos_eof = false; + state->status = TSS_READMEM; + break; + case TSS_WRITEFILE: + /* + * Write the EOF marker. + */ + markrunend(state); + /* + * Set up for reading from tape. + */ + if (BufFileSeek(state->myfile, 0, 0L, SEEK_SET) != 0) + elog(ERROR, "tuplestore_donestoring: seek(0) failed"); + state->eof_reached = false; + state->markpos_file = 0; + state->markpos_offset = 0L; + state->markpos_eof = false; + state->status = TSS_READFILE; + break; + default: + elog(ERROR, "tuplestore_donestoring: invalid state"); + break; + } +} + +/* + * Fetch the next tuple in either forward or back direction. + * Returns NULL if no more tuples. If should_free is set, the + * caller must pfree the returned tuple when done with it. + */ +void * +tuplestore_gettuple(Tuplestorestate *state, bool forward, + bool *should_free) +{ + unsigned int tuplen; + void *tup; + + switch (state->status) + { + case TSS_READMEM: + Assert(forward || state->randomAccess); + *should_free = false; + if (forward) + { + if (state->current < state->memtupcount) + return state->memtuples[state->current++]; + state->eof_reached = true; + return NULL; + } + else + { + if (state->current <= 0) + return NULL; + + /* + * if all tuples are fetched already then we return last + * tuple, else - tuple before last returned. + */ + if (state->eof_reached) + state->eof_reached = false; + else + { + state->current--; /* last returned tuple */ + if (state->current <= 0) + return NULL; + } + return state->memtuples[state->current - 1]; + } + break; + + case TSS_READFILE: + Assert(forward || state->randomAccess); + *should_free = true; + if (forward) + { + if (state->eof_reached) + return NULL; + if ((tuplen = getlen(state, true)) != 0) + { + tup = READTUP(state, tuplen); + return tup; + } + else + { + state->eof_reached = true; + return NULL; + } + } + + /* + * Backward. + * + * if all tuples are fetched already then we return last tuple, + * else - tuple before last returned. + */ + if (state->eof_reached) + { + + /* + * Seek position is pointing just past the zero tuplen at + * the end of file; back up to fetch last tuple's ending + * length word. If seek fails we must have a completely + * empty file. + */ + if (BufFileSeek(state->myfile, 0, + - (long) (2 * sizeof(unsigned int)), + SEEK_CUR) != 0) + return NULL; + state->eof_reached = false; + } + else + { + + /* + * Back up and fetch previously-returned tuple's ending + * length word. If seek fails, assume we are at start of + * file. + */ + if (BufFileSeek(state->myfile, 0, + - (long) sizeof(unsigned int), + SEEK_CUR) != 0) + return NULL; + tuplen = getlen(state, false); + + /* + * Back up to get ending length word of tuple before it. + */ + if (BufFileSeek(state->myfile, 0, + - (long) (tuplen + 2 * sizeof(unsigned int)), + SEEK_CUR) != 0) + { + + /* + * If that fails, presumably the prev tuple is the + * first in the file. Back up so that it becomes next + * to read in forward direction (not obviously right, + * but that is what in-memory case does). + */ + if (BufFileSeek(state->myfile, 0, + - (long) (tuplen + sizeof(unsigned int)), + SEEK_CUR) != 0) + elog(ERROR, "tuplestore_gettuple: bogus tuple len in backward scan"); + return NULL; + } + } + + tuplen = getlen(state, false); + + /* + * Now we have the length of the prior tuple, back up and read + * it. Note: READTUP expects we are positioned after the + * initial length word of the tuple, so back up to that point. + */ + if (BufFileSeek(state->myfile, 0, + - (long) tuplen, + SEEK_CUR) != 0) + elog(ERROR, "tuplestore_gettuple: bogus tuple len in backward scan"); + tup = READTUP(state, tuplen); + return tup; + + default: + elog(ERROR, "tuplestore_gettuple: invalid state"); + return NULL; /* keep compiler quiet */ + } +} + +/* + * dumptuples - remove tuples from memory and write to tape + */ +static void +dumptuples(Tuplestorestate *state) +{ + int i; + + for (i = 0; i < state->memtupcount; i++) + { + WRITETUP(state, state->memtuples[i]); + } + state->memtupcount = 0; +} + +/* + * tuplestore_rescan - rewind and replay the scan + */ +void +tuplestore_rescan(Tuplestorestate *state) +{ + Assert(state->randomAccess); + + switch (state->status) + { + case TSS_READMEM: + state->current = 0; + state->eof_reached = false; + state->markpos_offset = 0L; + state->markpos_eof = false; + break; + case TSS_READFILE: + if (BufFileSeek(state->myfile, 0, 0L, SEEK_SET) != 0) + elog(ERROR, "tuplestore_rescan: seek(0) failed"); + state->eof_reached = false; + state->markpos_file = 0; + state->markpos_offset = 0L; + state->markpos_eof = false; + break; + default: + elog(ERROR, "tuplestore_rescan: invalid state"); + break; + } +} + +/* + * tuplestore_markpos - saves current position in the tuple sequence + */ +void +tuplestore_markpos(Tuplestorestate *state) +{ + Assert(state->randomAccess); + + switch (state->status) + { + case TSS_READMEM: + state->markpos_offset = state->current; + state->markpos_eof = state->eof_reached; + break; + case TSS_READFILE: + BufFileTell(state->myfile, + &state->markpos_file, + &state->markpos_offset); + state->markpos_eof = state->eof_reached; + break; + default: + elog(ERROR, "tuplestore_markpos: invalid state"); + break; + } +} + +/* + * tuplestore_restorepos - restores current position in tuple sequence to + * last saved position + */ +void +tuplestore_restorepos(Tuplestorestate *state) +{ + Assert(state->randomAccess); + + switch (state->status) + { + case TSS_READMEM: + state->current = (int) state->markpos_offset; + state->eof_reached = state->markpos_eof; + break; + case TSS_READFILE: + if (BufFileSeek(state->myfile, + state->markpos_file, + state->markpos_offset, + SEEK_SET) != 0) + elog(ERROR, "tuplestore_restorepos failed"); + state->eof_reached = state->markpos_eof; + break; + default: + elog(ERROR, "tuplestore_restorepos: invalid state"); + break; + } +} + + +/* + * Tape interface routines + */ + +static unsigned int +getlen(Tuplestorestate *state, bool eofOK) +{ + unsigned int len; + + if (BufFileRead(state->myfile, (void *) &len, sizeof(len)) != sizeof(len)) + elog(ERROR, "tuplestore: unexpected end of tape"); + if (len == 0 && !eofOK) + elog(ERROR, "tuplestore: unexpected end of data"); + return len; +} + +static void +markrunend(Tuplestorestate *state) +{ + unsigned int len = 0; + + if (BufFileWrite(state->myfile, (void *) &len, sizeof(len)) != sizeof(len)) + elog(ERROR, "tuplestore: write failed"); +} + + +/* + * Routines specialized for HeapTuple case + */ + +static void * +copytup_heap(Tuplestorestate *state, void *tup) +{ + HeapTuple tuple = (HeapTuple) tup; + + USEMEM(state, HEAPTUPLESIZE + tuple->t_len); + return (void *) heap_copytuple(tuple); +} + +/* + * We don't bother to write the HeapTupleData part of the tuple. + */ + +static void +writetup_heap(Tuplestorestate *state, void *tup) +{ + HeapTuple tuple = (HeapTuple) tup; + unsigned int tuplen; + + tuplen = tuple->t_len + sizeof(tuplen); + if (BufFileWrite(state->myfile, (void *) &tuplen, + sizeof(tuplen)) != sizeof(tuplen)) + elog(ERROR, "tuplestore: write failed"); + if (BufFileWrite(state->myfile, (void *) tuple->t_data, + tuple->t_len) != (size_t) tuple->t_len) + elog(ERROR, "tuplestore: write failed"); + if (state->randomAccess) /* need trailing length word? */ + if (BufFileWrite(state->myfile, (void *) &tuplen, + sizeof(tuplen)) != sizeof(tuplen)) + elog(ERROR, "tuplestore: write failed"); + + FREEMEM(state, HEAPTUPLESIZE + tuple->t_len); + heap_freetuple(tuple); +} + +static void * +readtup_heap(Tuplestorestate *state, unsigned int len) +{ + unsigned int tuplen = len - sizeof(unsigned int) + HEAPTUPLESIZE; + HeapTuple tuple = (HeapTuple) palloc(tuplen); + + USEMEM(state, tuplen); + /* reconstruct the HeapTupleData portion */ + tuple->t_len = len - sizeof(unsigned int); + ItemPointerSetInvalid(&(tuple->t_self)); + tuple->t_datamcxt = CurrentMemoryContext; + tuple->t_data = (HeapTupleHeader) (((char *) tuple) + HEAPTUPLESIZE); + /* read in the tuple proper */ + if (BufFileRead(state->myfile, (void *) tuple->t_data, + tuple->t_len) != (size_t) tuple->t_len) + elog(ERROR, "tuplestore: unexpected end of data"); + if (state->randomAccess) /* need trailing length word? */ + if (BufFileRead(state->myfile, (void *) &tuplen, + sizeof(tuplen)) != sizeof(tuplen)) + elog(ERROR, "tuplestore: unexpected end of data"); + return (void *) tuple; +} diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index dae57528c7..9880d2aa32 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: heapam.h,v 1.52 2000/04/12 17:16:25 momjian Exp $ + * $Id: heapam.h,v 1.53 2000/06/18 22:44:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -242,9 +242,11 @@ extern HeapAccessStatistics heap_access_stats; /* in stats.c */ /* ---------------- * function prototypes for heap access method + * + * heap_create, heap_create_with_catalog, and heap_drop_with_catalog + * are declared in catalog/heap.h * ---------------- */ -/* heap_create, heap_creatr, and heap_destroy are declared in catalog/heap.h */ /* heapam.c */ diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index 468eef4d3d..c59509e152 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: heap.h,v 1.29 2000/04/12 17:16:27 momjian Exp $ + * $Id: heap.h,v 1.30 2000/06/18 22:44:25 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,8 +24,9 @@ typedef struct RawColumnDefault } RawColumnDefault; extern Oid RelnameFindRelid(const char *relname); -extern Relation heap_create(char *relname, TupleDesc att, - bool isnoname, bool istemp, bool storage_create); + +extern Relation heap_create(char *relname, TupleDesc tupDesc, + bool istemp, bool storage_create); extern bool heap_storage_create(Relation rel); extern Oid heap_create_with_catalog(char *relname, TupleDesc tupdesc, @@ -33,13 +34,9 @@ extern Oid heap_create_with_catalog(char *relname, TupleDesc tupdesc, extern void heap_drop_with_catalog(const char *relname); extern void heap_truncate(char *relname); -extern void heap_drop(Relation rel); extern void AddRelationRawConstraints(Relation rel, List *rawColDefaults, List *rawConstraints); -extern void InitNoNameRelList(void); -extern void DropNoNameRels(void); - #endif /* HEAP_H */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 6d196eb5a2..703c907e12 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: executor.h,v 1.44 2000/06/17 21:48:56 tgl Exp $ + * $Id: executor.h,v 1.45 2000/06/18 22:44:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -39,7 +39,6 @@ extern HeapScanDesc ExecReScanR(Relation relDesc, HeapScanDesc scanDesc, ScanDirection direction, int nkeys, ScanKey skeys); extern void ExecMarkPos(Plan *node); extern void ExecRestrPos(Plan *node); -extern Relation ExecCreatR(TupleDesc tupType, Oid relationOid); /* * prototypes from functions in execJunk.c diff --git a/src/include/executor/nodeMaterial.h b/src/include/executor/nodeMaterial.h index 1daf0bd0af..b99d54b78d 100644 --- a/src/include/executor/nodeMaterial.h +++ b/src/include/executor/nodeMaterial.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: nodeMaterial.h,v 1.12 2000/01/26 05:58:05 momjian Exp $ + * $Id: nodeMaterial.h,v 1.13 2000/06/18 22:44:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -20,11 +20,8 @@ extern TupleTableSlot *ExecMaterial(Material *node); extern bool ExecInitMaterial(Material *node, EState *estate, Plan *parent); extern int ExecCountSlotsMaterial(Material *node); extern void ExecEndMaterial(Material *node); +extern void ExecMaterialMarkPos(Material *node); +extern void ExecMaterialRestrPos(Material *node); extern void ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent); -#ifdef NOT_USED -extern List ExecMaterialMarkPos(Material *node); -extern void ExecMaterialRestrPos(Material *node); - -#endif #endif /* NODEMATERIAL_H */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 044cee23ea..a74f16348d 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: execnodes.h,v 1.41 2000/04/12 17:16:39 momjian Exp $ + * $Id: execnodes.h,v 1.42 2000/06/18 22:44:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -565,11 +565,9 @@ typedef struct HashJoinState * MaterialState information * * materialize nodes are used to materialize the results - * of a subplan into a temporary relation. + * of a subplan into a temporary file. * - * Flag indicated whether subplan has been materialized - * TempRelation temporary relation containing result of executing - * the subplan. + * tuplestorestate private state of tuplestore.c * * CommonScanState information * @@ -590,8 +588,7 @@ typedef struct HashJoinState typedef struct MaterialState { CommonScanState csstate; /* its first field is NodeTag */ - bool mat_Flag; - Relation mat_TempRelation; + void *tuplestorestate; } MaterialState; /* --------------------- diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 5d049dadfb..3be4831778 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: nodes.h,v 1.68 2000/05/29 01:59:12 tgl Exp $ + * $Id: nodes.h,v 1.69 2000/06/18 22:44:31 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -39,13 +39,13 @@ typedef enum NodeTag T_NestLoop, T_MergeJoin, T_HashJoin, - T_Noname, + T_Noname_XXX, /* not used anymore; this tag# is available */ T_Material, T_Sort, T_Agg, T_Unique, T_Hash, - T_Choose, + T_Choose_XXX, /* not used anymore; this tag# is available */ T_Group, T_SubPlan, T_TidScan, @@ -261,10 +261,6 @@ typedef struct Node (IsA(jp, Join) || IsA(jp, NestLoop) || \ IsA(jp, MergeJoin) || IsA(jp, HashJoin)) -#define IsA_Noname(t) \ - (IsA(t, Noname) || IsA(t, Material) || IsA(t, Sort) || \ - IsA(t, Unique)) - #define IsA_Value(t) \ (IsA(t, Integer) || IsA(t, Float) || IsA(t, String)) diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 1cab6e03fc..37006e621f 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: plannodes.h,v 1.39 2000/04/12 17:16:40 momjian Exp $ + * $Id: plannodes.h,v 1.40 2000/06/18 22:44:31 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -277,27 +277,13 @@ typedef struct Group GroupState *grpstate; } Group; -/* - * ========== - * Noname nodes - * ========== - */ -typedef struct Noname -{ - Plan plan; - Oid nonameid; - int keycount; -} Noname; - /* ---------------- * materialization node * ---------------- */ typedef struct Material { - Plan plan; /* noname node flattened out */ - Oid nonameid; - int keycount; + Plan plan; MaterialState *matstate; } Material; @@ -307,8 +293,7 @@ typedef struct Material */ typedef struct Sort { - Plan plan; /* noname node flattened out */ - Oid nonameid; + Plan plan; int keycount; SortState *sortstate; } Sort; @@ -319,9 +304,7 @@ typedef struct Sort */ typedef struct Unique { - Plan plan; /* noname node flattened out */ - Oid nonameid; - int keycount; + Plan plan; int numCols; /* number of columns to check for * uniqueness */ AttrNumber *uniqColIdx; /* indexes into the target list */ diff --git a/src/include/optimizer/internal.h b/src/include/optimizer/internal.h deleted file mode 100644 index e9b0c8e4bc..0000000000 --- a/src/include/optimizer/internal.h +++ /dev/null @@ -1,54 +0,0 @@ -/*------------------------------------------------------------------------- - * - * internal.h - * Definitions required throughout the query optimizer. - * - * - * Portions Copyright (c) 1996-2000, PostgreSQL, Inc - * Portions Copyright (c) 1994, Regents of the University of California - * - * $Id: internal.h,v 1.27 2000/06/15 03:32:51 momjian Exp $ - * - *------------------------------------------------------------------------- - */ -#ifndef INTERNAL_H -#define INTERNAL_H - -/* - * ---------- SHARED MACROS - * - * Macros common to modules for creating, accessing, and modifying - * query tree and query plan components. - * Shared with the executor. - * - */ - - -/* - * Size estimates - * - */ - -/* The cost of sequentially scanning a materialized temporary relation - */ -#define _NONAME_SCAN_COST_ 10 - -/* The number of pages and tuples in a materialized relation - */ -#define _NONAME_RELATION_PAGES_ 1 -#define _NONAME_RELATION_TUPLES_ 10 - -/* The length of a variable-length field in bytes (stupid estimate...) - */ -#define _DEFAULT_ATTRIBUTE_WIDTH_ 12 - -/* - * Flags and identifiers - * - */ - -/* Identifier for (sort) temp relations */ -/* used to be -1 */ -#define _NONAME_RELATION_ID_ InvalidOid - -#endif /* INTERNAL_H */ diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h index e76ba20144..6c16364f67 100644 --- a/src/include/optimizer/planmain.h +++ b/src/include/optimizer/planmain.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: planmain.h,v 1.41 2000/06/08 22:37:51 momjian Exp $ + * $Id: planmain.h,v 1.42 2000/06/18 22:44:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,12 +27,13 @@ extern Plan *query_planner(Query *root, List *tlist, List *qual, * prototypes for plan/createplan.c */ extern Plan *create_plan(Query *root, Path *best_path); -extern Sort *make_sort(List *tlist, Oid nonameid, Plan *lefttree, - int keycount); +extern Sort *make_sort(List *tlist, Plan *lefttree, int keycount); +extern Sort *make_sort_from_pathkeys(List *tlist, Plan *lefttree, + List *pathkeys); extern Agg *make_agg(List *tlist, List *qual, Plan *lefttree); extern Group *make_group(List *tlist, bool tuplePerGroup, int ngrp, AttrNumber *grpColIdx, Plan *lefttree); -extern Noname *make_noname(List *tlist, List *pathkeys, Plan *subplan); +extern Material *make_material(List *tlist, Plan *lefttree); extern Unique *make_unique(List *tlist, Plan *lefttree, List *distinctList); extern Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 2a585c0e7e..901020611a 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: rel.h,v 1.37 2000/06/17 21:49:02 tgl Exp $ + * $Id: rel.h,v 1.38 2000/06/18 22:44:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -90,7 +90,6 @@ typedef struct RelationData uint16 rd_refcnt; /* reference count */ bool rd_myxactonly; /* rel uses the local buffer mgr */ bool rd_isnailed; /* rel is nailed in cache */ - bool rd_isnoname; /* rel has no name */ bool rd_unlinked; /* rel already unlinked or not created yet */ bool rd_indexfound; /* true if rd_indexlist is valid */ Form_pg_am rd_am; /* AM tuple */ diff --git a/src/include/utils/tuplestore.h b/src/include/utils/tuplestore.h new file mode 100644 index 0000000000..702d3b73c9 --- /dev/null +++ b/src/include/utils/tuplestore.h @@ -0,0 +1,60 @@ +/*------------------------------------------------------------------------- + * + * tuplestore.h + * Generalized routines for temporary tuple storage. + * + * This module handles temporary storage of tuples for purposes such + * as Materialize nodes, hashjoin batch files, etc. It is essentially + * a dumbed-down version of tuplesort.c; it does no sorting of tuples + * but can only store a sequence of tuples and regurgitate it later. + * A temporary file is used to handle the data if it exceeds the + * space limit specified by the caller. + * + * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1994, Regents of the University of California + * + * $Id: tuplestore.h,v 1.1 2000/06/18 22:44:35 tgl Exp $ + * + *------------------------------------------------------------------------- + */ +#ifndef TUPLESTORE_H +#define TUPLESTORE_H + +#include "access/htup.h" + +/* Tuplestorestate is an opaque type whose details are not known outside + * tuplestore.c. + */ +typedef struct Tuplestorestate Tuplestorestate; + +/* + * Currently we only need to store HeapTuples, but it would be easy + * to support the same behavior for IndexTuples and/or bare Datums. + */ + +extern Tuplestorestate *tuplestore_begin_heap(bool randomAccess, + int maxKBytes); + +extern void tuplestore_puttuple(Tuplestorestate *state, void *tuple); + +extern void tuplestore_donestoring(Tuplestorestate *state); + +extern void *tuplestore_gettuple(Tuplestorestate *state, bool forward, + bool *should_free); + +#define tuplestore_getheaptuple(state, forward, should_free) \ + ((HeapTuple) tuplestore_gettuple(state, forward, should_free)) + +extern void tuplestore_end(Tuplestorestate *state); + +/* + * These routines may only be called if randomAccess was specified 'true'. + * Likewise, backwards scan in gettuple/getdatum is only allowed if + * randomAccess was specified. + */ + +extern void tuplestore_rescan(Tuplestorestate *state); +extern void tuplestore_markpos(Tuplestorestate *state); +extern void tuplestore_restorepos(Tuplestorestate *state); + +#endif /* TUPLESTORE_H */