Reimplement nodeMaterial to use a temporary BufFile (or even memory, if the

materialized tupleset is small enough) instead of a temporary relation.
This was something I was thinking of doing anyway for performance, and Jan
says he needs it for TOAST because he doesn't want to cope with toasting
noname relations.  With this change, the 'noname table' support in heap.c
is dead code, and I have accordingly removed it.  Also clean up 'noname'
plan handling in planner --- nonames are either sort or materialize plans,
and it seems less confusing to handle them separately under those names.
This commit is contained in:
Tom Lane 2000-06-18 22:44:35 +00:00
parent 2c0edb3c86
commit 1ee26b7764
32 changed files with 1090 additions and 982 deletions

View File

@ -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();

View File

@ -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");
}

View File

@ -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.

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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);
}
/*

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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"

View File

@ -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())

View File

@ -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

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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;
/* ---------------------

View File

@ -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))

View File

@ -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 */

View File

@ -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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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 */