aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/xact.c12
-rw-r--r--src/backend/bootstrap/bootparse.y4
-rw-r--r--src/backend/catalog/heap.c196
-rw-r--r--src/backend/catalog/index.c7
-rw-r--r--src/backend/commands/explain.c5
-rw-r--r--src/backend/executor/execAmi.c97
-rw-r--r--src/backend/executor/nodeMaterial.c277
-rw-r--r--src/backend/nodes/copyfuncs.c45
-rw-r--r--src/backend/nodes/freefuncs.c39
-rw-r--r--src/backend/nodes/outfuncs.c43
-rw-r--r--src/backend/nodes/print.c8
-rw-r--r--src/backend/nodes/readfuncs.c40
-rw-r--r--src/backend/optimizer/path/costsize.c43
-rw-r--r--src/backend/optimizer/plan/createplan.c238
-rw-r--r--src/backend/optimizer/plan/planner.c31
-rw-r--r--src/backend/optimizer/plan/subselect.c6
-rw-r--r--src/backend/optimizer/util/relnode.c26
-rw-r--r--src/backend/utils/adt/chunk.c3
-rw-r--r--src/backend/utils/cache/relcache.c14
-rw-r--r--src/backend/utils/sort/Makefile4
-rw-r--r--src/backend/utils/sort/tuplestore.c685
-rw-r--r--src/include/access/heapam.h6
-rw-r--r--src/include/catalog/heap.h11
-rw-r--r--src/include/executor/executor.h3
-rw-r--r--src/include/executor/nodeMaterial.h9
-rw-r--r--src/include/nodes/execnodes.h11
-rw-r--r--src/include/nodes/nodes.h10
-rw-r--r--src/include/nodes/plannodes.h25
-rw-r--r--src/include/optimizer/internal.h54
-rw-r--r--src/include/optimizer/planmain.h9
-rw-r--r--src/include/utils/rel.h3
-rw-r--r--src/include/utils/tuplestore.h60
32 files changed, 1066 insertions, 958 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index cd20e231ecb..d6551cc9c9c 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 d7a1d9de899..0a6f9d55ace 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 451eb7f7de2..7aeec8adb08 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
@@ -311,12 +286,6 @@ heap_create(char *relname,
}
/* ----------------
- * 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 b18ae9af64a..5b8e005c5f6 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 d51053c20a1..25915fe42bd 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 ed20aec5a87..ff3fa0b6ed1 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 4348f89ccc9..1d5c9042489 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -8,42 +8,37 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.30 2000/03/02 04:06:39 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.31 2000/06/18 22:44:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
- * ExecMaterial - generate a temporary relation
- * ExecInitMaterial - initialize node and subnodes..
+ * ExecMaterial - materialize the result of a subplan
+ * ExecInitMaterial - initialize node and subnodes
* ExecEndMaterial - shutdown node and subnodes
*
*/
#include "postgres.h"
-
-#include "access/heapam.h"
-#include "catalog/heap.h"
#include "executor/executor.h"
#include "executor/nodeMaterial.h"
-#include "optimizer/internal.h"
+#include "miscadmin.h"
+#include "utils/tuplestore.h"
/* ----------------------------------------------------------------
* ExecMaterial
*
* The first time this is called, ExecMaterial retrieves tuples
- * from this node's outer subplan and inserts them into a temporary
- * relation. After this is done, a flag is set indicating that
- * the subplan has been materialized. Once the relation is
- * materialized, the first tuple is then returned. Successive
- * calls to ExecMaterial return successive tuples from the temp
- * relation.
+ * from this node's outer subplan and inserts them into a tuplestore
+ * (a temporary tuple storage structure). The first tuple is then
+ * returned. Successive calls to ExecMaterial return successive
+ * tuples from the tuplestore.
*
* Initial State:
*
- * ExecMaterial assumes the temporary relation has been
- * created and opened by ExecInitMaterial during the prior
- * InitPlan() phase.
+ * matstate->tuplestorestate is initially NULL, indicating we
+ * haven't yet collected the results of the subplan.
*
* ----------------------------------------------------------------
*/
@@ -52,13 +47,11 @@ ExecMaterial(Material *node)
{
EState *estate;
MaterialState *matstate;
- Plan *outerNode;
ScanDirection dir;
- Relation tempRelation;
- Relation currentRelation;
- HeapScanDesc currentScanDesc;
+ Tuplestorestate *tuplestorestate;
HeapTuple heapTuple;
TupleTableSlot *slot;
+ bool should_free;
/* ----------------
* get state info from node
@@ -67,42 +60,42 @@ ExecMaterial(Material *node)
matstate = node->matstate;
estate = node->plan.state;
dir = estate->es_direction;
+ tuplestorestate = (Tuplestorestate *) matstate->tuplestorestate;
/* ----------------
- * the first time we call this, we retrieve all tuples
- * from the subplan into a temporary relation and then
- * we sort the relation. Subsequent calls return tuples
- * from the temporary relation.
+ * If first time through, read all tuples from outer plan and
+ * pass them to tuplestore.c.
+ * Subsequent calls just fetch tuples from tuplestore.
* ----------------
*/
- if (matstate->mat_Flag == false)
+ if (tuplestorestate == NULL)
{
+ Plan *outerNode;
+
/* ----------------
- * set all relations to be scanned in the forward direction
- * while creating the temporary relation.
+ * Want to scan subplan in the forward direction while creating
+ * the stored data. (Does setting my direction actually affect
+ * the subplan? I bet this is useless code...)
* ----------------
*/
estate->es_direction = ForwardScanDirection;
/* ----------------
- * if we couldn't create the temp relation then
- * we print a warning and return NULL.
+ * Initialize tuplestore module.
* ----------------
*/
- tempRelation = matstate->mat_TempRelation;
- if (tempRelation == NULL)
- {
- elog(DEBUG, "ExecMaterial: temp relation is NULL! aborting...");
- return NULL;
- }
+ tuplestorestate = tuplestore_begin_heap(true, /* randomAccess */
+ SortMem);
+
+ matstate->tuplestorestate = (void *) tuplestorestate;
/* ----------------
- * retrieve tuples from the subplan and
- * insert them in the temporary relation
+ * Scan the subplan and feed all the tuples to tuplestore.
* ----------------
*/
outerNode = outerPlan((Plan *) node);
+
for (;;)
{
slot = ExecProcNode(outerNode, (Plan *) node);
@@ -110,63 +103,34 @@ ExecMaterial(Material *node)
if (TupIsNull(slot))
break;
- heap_insert(tempRelation, slot->val);
-
+ tuplestore_puttuple(tuplestorestate, (void *) slot->val);
ExecClearTuple(slot);
}
/* ----------------
- * restore to user specified direction
+ * Complete the store.
* ----------------
*/
- estate->es_direction = dir;
+ tuplestore_donestoring(tuplestorestate);
/* ----------------
- * now initialize the scan descriptor to scan the
- * sorted relation and update the sortstate information
- * ----------------
- */
- currentRelation = tempRelation;
- currentScanDesc = heap_beginscan(currentRelation, /* relation */
- ScanDirectionIsBackward(dir),
- SnapshotSelf, /* seeself */
- 0, /* num scan keys */
- NULL); /* scan keys */
- matstate->csstate.css_currentRelation = currentRelation;
- matstate->csstate.css_currentScanDesc = currentScanDesc;
-
- ExecAssignScanType(&matstate->csstate,
- RelationGetDescr(currentRelation));
-
- /* ----------------
- * finally set the sorted flag to true
+ * restore to user specified direction
* ----------------
*/
- matstate->mat_Flag = true;
+ estate->es_direction = dir;
}
/* ----------------
- * at this point we know we have a sorted relation so
- * we perform a simple scan on it with amgetnext()..
- * ----------------
- */
- currentScanDesc = matstate->csstate.css_currentScanDesc;
-
- heapTuple = heap_getnext(currentScanDesc, ScanDirectionIsBackward(dir));
-
- /* ----------------
- * put the tuple into the scan tuple slot and return the slot.
- * Note: since the tuple is really a pointer to a page, we don't want
- * to call pfree() on it..
+ * Get the first or next tuple from tuplestore.
+ * Returns NULL if no more tuples.
* ----------------
*/
- slot = (TupleTableSlot *) matstate->csstate.css_ScanTupleSlot;
-
- return ExecStoreTuple(heapTuple, /* tuple to store */
- slot, /* slot to store in */
- currentScanDesc->rs_cbuf, /* buffer for this tuple */
- false); /* don't pfree this pointer */
+ slot = (TupleTableSlot *) matstate->csstate.cstate.cs_ResultTupleSlot;
+ heapTuple = tuplestore_getheaptuple(tuplestorestate,
+ ScanDirectionIsForward(dir),
+ &should_free);
+ return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
}
/* ----------------------------------------------------------------
@@ -178,10 +142,6 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent)
{
MaterialState *matstate;
Plan *outerPlan;
- TupleDesc tupType;
- Relation tempDesc;
-
- /* int len; */
/* ----------------
* assign the node's execution state
@@ -194,8 +154,7 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent)
* ----------------
*/
matstate = makeNode(MaterialState);
- matstate->mat_Flag = false;
- matstate->mat_TempRelation = NULL;
+ matstate->tuplestorestate = NULL;
node->matstate = matstate;
/* ----------------
@@ -214,8 +173,12 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent)
#define MATERIAL_NSLOTS 1
/* ----------------
* tuple table initialization
+ *
+ * material nodes only return tuples from their materialized
+ * relation.
* ----------------
*/
+ ExecInitResultTupleSlot(estate, &matstate->csstate.cstate);
ExecInitScanTupleSlot(estate, &matstate->csstate);
/* ----------------
@@ -226,52 +189,14 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent)
ExecInitNode(outerPlan, estate, (Plan *) node);
/* ----------------
- * initialize matstate information
- * ----------------
- */
- matstate->mat_Flag = false;
-
- /* ----------------
* initialize tuple type. no need to initialize projection
* info because this node doesn't do projections.
* ----------------
*/
+ ExecAssignResultTypeFromOuterPlan((Plan *) node, &matstate->csstate.cstate);
ExecAssignScanTypeFromOuterPlan((Plan *) node, &matstate->csstate);
matstate->csstate.cstate.cs_ProjInfo = NULL;
- /* ----------------
- * get type information needed for ExecCreatR
- * ----------------
- */
- tupType = ExecGetScanType(&matstate->csstate);
-
- /* ----------------
- * ExecCreatR wants its second argument to be an object id of
- * a relation in the range table or a _NONAME_RELATION_ID
- * indicating that the relation is not in the range table.
- *
- * In the second case ExecCreatR creates a temp relation.
- * (currently this is the only case we support -cim 10/16/89)
- * ----------------
- */
- /* ----------------
- * create the temporary relation
- * ----------------
- */
- tempDesc = ExecCreatR(tupType, _NONAME_RELATION_ID_);
-
- /* ----------------
- * save the relation descriptor in the sortstate
- * ----------------
- */
- matstate->mat_TempRelation = tempDesc;
- matstate->csstate.css_currentRelation = NULL;
-
- /* ----------------
- * return relation oid of temporary relation in a list
- * (someday -- for now we return LispTrue... cim 10/12/89)
- * ----------------
- */
return TRUE;
}
@@ -285,16 +210,12 @@ ExecCountSlotsMaterial(Material *node)
/* ----------------------------------------------------------------
* ExecEndMaterial
- *
- * old comments
- * destroys the temporary relation.
* ----------------------------------------------------------------
*/
void
ExecEndMaterial(Material *node)
{
MaterialState *matstate;
- Relation tempRelation;
Plan *outerPlan;
/* ----------------
@@ -302,14 +223,6 @@ ExecEndMaterial(Material *node)
* ----------------
*/
matstate = node->matstate;
- tempRelation = matstate->mat_TempRelation;
-
- /* ----------------
- * shut down the scan, but don't close the temp relation
- * ----------------
- */
- matstate->csstate.css_currentRelation = NULL;
- ExecCloseR((Plan *) node);
/* ----------------
* shut down the subplan
@@ -325,88 +238,92 @@ ExecEndMaterial(Material *node)
ExecClearTuple(matstate->csstate.css_ScanTupleSlot);
/* ----------------
- * delete the temp relation
+ * Release tuplestore resources
* ----------------
*/
- if (tempRelation != NULL)
- heap_drop(tempRelation);
+ if (matstate->tuplestorestate != NULL)
+ tuplestore_end((Tuplestorestate *) matstate->tuplestorestate);
+ matstate->tuplestorestate = NULL;
}
/* ----------------------------------------------------------------
- * ExecMaterialReScan
+ * ExecMaterialMarkPos
*
- * Rescans the temporary relation.
+ * Calls tuplestore to save the current position in the stored file.
* ----------------------------------------------------------------
*/
void
-ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent)
+ExecMaterialMarkPos(Material *node)
{
- MaterialState *matstate = node->matstate;
+ MaterialState *matstate = node->matstate;
- if (matstate->mat_Flag == false)
+ /* ----------------
+ * if we haven't materialized yet, just return.
+ * ----------------
+ */
+ if (!matstate->tuplestorestate)
return;
- matstate->csstate.css_currentScanDesc = ExecReScanR(matstate->csstate.css_currentRelation,
- matstate->csstate.css_currentScanDesc,
- node->plan.state->es_direction, 0, NULL);
-
+ tuplestore_markpos((Tuplestorestate *) matstate->tuplestorestate);
}
-#ifdef NOT_USED /* not used */
/* ----------------------------------------------------------------
- * ExecMaterialMarkPos
+ * ExecMaterialRestrPos
+ *
+ * Calls tuplestore to restore the last saved file position.
* ----------------------------------------------------------------
*/
-List /* nothing of interest */
-ExecMaterialMarkPos(Material node)
+void
+ExecMaterialRestrPos(Material *node)
{
- MaterialState matstate;
- HeapScanDesc scan;
+ MaterialState *matstate = node->matstate;
/* ----------------
- * if we haven't materialized yet, just return NIL.
+ * if we haven't materialized yet, just return.
* ----------------
*/
- matstate = get_matstate(node);
- if (get_mat_Flag(matstate) == false)
- return NIL;
+ if (!matstate->tuplestorestate)
+ return;
/* ----------------
- * XXX access methods don't return positions yet so
- * for now we return NIL. It's possible that
- * they will never return positions for all I know -cim 10/16/89
+ * restore the scan to the previously marked position
* ----------------
*/
- scan = get_css_currentScanDesc((CommonScanState) matstate);
- heap_markpos(scan);
-
- return NIL;
+ tuplestore_restorepos((Tuplestorestate *) matstate->tuplestorestate);
}
/* ----------------------------------------------------------------
- * ExecMaterialRestrPos
+ * ExecMaterialReScan
+ *
+ * Rescans the materialized relation.
* ----------------------------------------------------------------
*/
void
-ExecMaterialRestrPos(Material node)
+ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent)
{
- MaterialState matstate;
- HeapScanDesc scan;
+ MaterialState *matstate = node->matstate;
- /* ----------------
- * if we haven't materialized yet, just return.
- * ----------------
+ /*
+ * If we haven't materialized yet, just return. If outerplan' chgParam is
+ * not NULL then it will be re-scanned by ExecProcNode, else - no
+ * reason to re-scan it at all.
*/
- matstate = get_matstate(node);
- if (get_mat_Flag(matstate) == false)
+ if (!matstate->tuplestorestate)
return;
- /* ----------------
- * restore the scan to the previously marked position
- * ----------------
+ ExecClearTuple(matstate->csstate.cstate.cs_ResultTupleSlot);
+
+ /*
+ * If subnode is to be rescanned then we forget previous stored results;
+ * we have to re-read the subplan and re-store.
+ *
+ * Otherwise we can just rewind and rescan the stored output.
*/
- scan = get_css_currentScanDesc((CommonScanState) matstate);
- heap_restrpos(scan);
+ if (((Plan *) node)->lefttree->chgParam != NULL)
+ {
+ tuplestore_end((Tuplestorestate *) matstate->tuplestorestate);
+ matstate->tuplestorestate = NULL;
+ }
+ else
+ tuplestore_rescan((Tuplestorestate *) matstate->tuplestorestate);
}
-
-#endif
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index e146661fb84..fba792cc845 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 $
*
*-------------------------------------------------------------------------
*/
@@ -415,41 +415,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 59e2ac1154e..3353a82d9d7 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 $
*
*-------------------------------------------------------------------------
*/
@@ -306,37 +306,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 78585425624..b9830edc22f 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 8d3cd8d2a7b..104735cf6f6 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 99d25696ced..f872d952d03 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
@@ -556,37 +556,9 @@ _readTidScan()
}
/* ----------------
- * _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 b718f8fea18..0f26dc78722 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 015b6b2b10a..4915133d0a6 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,
@@ -959,72 +958,6 @@ switch_outer(List *clauses)
}
/*
- * 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 fdb7be92447..49d400dee9d 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 87e508ef8f7..cd624fb111d 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 da7059ce915..070fabf7669 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 1d8ec1aec8e..55776769493 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 4fe3e35b1e8..93375a7c158 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 f0e56ace0a8..2ae96894b92 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 00000000000..b1eb56cc2a0
--- /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 dae57528c71..9880d2aa321 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 468eef4d3df..c59509e1529 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 6d196eb5a2c..703c907e127 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 1daf0bd0afe..b99d54b78d8 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 ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent);
-
-#ifdef NOT_USED
-extern List ExecMaterialMarkPos(Material *node);
+extern void ExecMaterialMarkPos(Material *node);
extern void ExecMaterialRestrPos(Material *node);
+extern void ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent);
-#endif
#endif /* NODEMATERIAL_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 044cee23eab..a74f16348d2 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 5d049dadfb2..3be48317789 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 1cab6e03fc0..37006e621f4 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 e9b0c8e4bc1..00000000000
--- 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 e76ba201449..6c16364f67e 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 2a585c0e7ea..901020611ac 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 00000000000..702d3b73c91
--- /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 */