diff options
Diffstat (limited to 'src/backend/catalog/heap.c')
-rw-r--r-- | src/backend/catalog/heap.c | 346 |
1 files changed, 197 insertions, 149 deletions
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index bc897c5965c..eef7dbea0c5 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -7,7 +7,8 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.70 1998/12/15 12:45:40 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.71 1999/02/02 03:44:08 momjian Exp $ + * * * INTERFACE ROUTINES * heap_create() - Create an uncataloged heap relation @@ -26,6 +27,7 @@ *------------------------------------------------------------------------- */ #include "postgres.h" +#include "miscadmin.h" #include "access/heapam.h" #include "catalog/catalog.h" @@ -41,7 +43,6 @@ #include "catalog/pg_type.h" #include "commands/trigger.h" #include "fmgr.h" -#include "miscadmin.h" #include "nodes/plannodes.h" #include "optimizer/tlist.h" #include "parser/parse_expr.h" @@ -53,11 +54,13 @@ #include "storage/lmgr.h" #include "storage/smgr.h" #include "tcop/tcopprot.h" +#include "utils/catcache.h" #include "utils/builtins.h" #include "utils/mcxt.h" #include "utils/relcache.h" #include "utils/syscache.h" #include "utils/tqual.h" +#include "utils/temprel.h" #ifndef HAVE_MEMMOVE #include <regex/utils.h> @@ -65,18 +68,17 @@ #include <string.h> #endif -static void AddPgRelationTuple(Relation pg_class_desc, +static void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, unsigned natts, - char relkind); -static void AddToTempRelList(Relation r); -static void DeletePgAttributeTuples(Relation rel); -static void DeletePgRelationTuple(Relation rel); -static void DeletePgTypeTuple(Relation rel); -static int RelationAlreadyExists(Relation pg_class_desc, char *relname); + 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 RemoveFromTempRelList(Relation r); -static void addNewRelationType(char *typeName, Oid new_rel_oid); +static void RemoveFromNoNameRelList(Relation r); +static void AddNewRelationType(char *typeName, Oid new_rel_oid); static void StoreConstraints(Relation rel); static void RemoveConstraints(Relation rel); @@ -167,35 +169,34 @@ static TempRelList *tempRels = NULL; * * * if heap_create is called with "" as the name, then heap_create will create - * a temporary name "temp_$RELOID" for the relation + * a temporary name "pg_noname.$PID.$SEQUENCE" for the relation * ---------------------------------------------------------------- */ Relation -heap_create(char *name, - TupleDesc tupDesc) +heap_create(char *relname, + TupleDesc tupDesc, + bool isnoname, + bool istemp) { unsigned i; Oid relid; Relation rel; int len; bool nailme = false; - char *relname = name; - char tempname[NAMEDATALEN]; - int isTemp = 0; int natts = tupDesc->natts; - -/* Form_pg_attribute *att = tupDesc->attrs; */ - + static unsigned int uniqueId = 0; + extern GlobalMemory CacheCxt; MemoryContext oldcxt; + /* ---------------- * sanity checks * ---------------- */ AssertArg(natts > 0); - if (IsSystemRelationName(relname) && IsNormalProcessingMode()) + if (relname && IsSystemRelationName(relname) && IsNormalProcessingMode()) { elog(ERROR, "Illegal class name: %s -- pg_ is reserved for system catalogs", @@ -218,22 +219,22 @@ heap_create(char *name, * descriptor follows. * ---------------- */ - if (!strcmp(RelationRelationName, relname)) + if (relname && !strcmp(RelationRelationName, relname)) { relid = RelOid_pg_class; nailme = true; } - else if (!strcmp(AttributeRelationName, relname)) + else if (relname && !strcmp(AttributeRelationName, relname)) { relid = RelOid_pg_attribute; nailme = true; } - else if (!strcmp(ProcedureRelationName, relname)) + else if (relname && !strcmp(ProcedureRelationName, relname)) { relid = RelOid_pg_proc; nailme = true; } - else if (!strcmp(TypeRelationName, relname)) + else if (relname && !strcmp(TypeRelationName, relname)) { relid = RelOid_pg_type; nailme = true; @@ -241,14 +242,21 @@ heap_create(char *name, else { relid = newoid(); + } - if (name[0] == '\0') - { - snprintf(tempname, NAMEDATALEN, "temp_%d", relid); - Assert(strlen(tempname) < NAMEDATALEN); - relname = tempname; - isTemp = 1; - } + 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", + (int) MyProcPid, uniqueId++); } /* ---------------- @@ -262,17 +270,12 @@ heap_create(char *name, rel = (Relation) palloc(len); MemSet((char *) rel, 0, len); - /* ---------- - create a new tuple descriptor from the one passed in + /* + * create a new tuple descriptor from the one passed in */ rel->rd_att = CreateTupleDescCopyConstr(tupDesc); /* ---------------- - * initialize the fields of our new relation descriptor - * ---------------- - */ - - /* ---------------- * nail the reldesc if this is a bootstrap create reln and * we may need it in the cache later on in the bootstrap * process so we don't ever want it kicked out. e.g. pg_attribute!!! @@ -285,8 +288,11 @@ heap_create(char *name, rel->rd_rel = (Form_pg_class) palloc(sizeof *rel->rd_rel); - MemSet((char *) rel->rd_rel, 0, - sizeof *rel->rd_rel); + /* ---------------- + * initialize the fields of our new relation descriptor + * ---------------- + */ + MemSet((char *) rel->rd_rel, 0, sizeof *rel->rd_rel); namestrcpy(&(rel->rd_rel->relname), relname); rel->rd_rel->relkind = RELKIND_UNCATALOGED; rel->rd_rel->relnatts = natts; @@ -305,31 +311,30 @@ heap_create(char *name, } /* ---------------- - * remember if this is a temp relation + * remember if this is a noname relation * ---------------- */ - - rel->rd_istemp = isTemp; + rel->rd_isnoname = isnoname; /* ---------------- * have the storage manager create the relation. * ---------------- */ - rel->rd_tmpunlinked = TRUE; /* change once table is created */ + rel->rd_nonameunlinked = TRUE; /* change once table is created */ rel->rd_fd = (File) smgrcreate(DEFAULT_SMGR, rel); - rel->rd_tmpunlinked = FALSE; + rel->rd_nonameunlinked = FALSE; RelationRegisterRelation(rel); MemoryContextSwitchTo(oldcxt); /* - * add all temporary relations to the tempRels list so they can be + * add all noname relations to the tempRels list so they can be * properly disposed of at the end of transaction */ - if (isTemp) - AddToTempRelList(rel); + if (isnoname) + AddToNoNameRelList(rel); return rel; } @@ -343,7 +348,7 @@ heap_create(char *name, * 1) CheckAttributeNames() is used to make certain the tuple * descriptor contains a valid set of attribute names * - * 2) pg_class is opened and RelationAlreadyExists() + * 2) pg_class is opened and RelationFindRelid() * preforms a scan to ensure that no relation with the * same name already exists. * @@ -356,7 +361,7 @@ heap_create(char *name, * 5) AddNewAttributeTuples() is called to register the * new relation's schema in pg_attribute. * - * 6) AddPgRelationTuple() is called to register the + * 6) AddNewRelationTuple() is called to register the * relation itself in the catalogs. * * 7) StoreConstraints is called () - vadim 08/22/97 @@ -456,71 +461,78 @@ CheckAttributeNames(TupleDesc tupdesc) } /* -------------------------------- - * RelationAlreadyExists + * RelnameFindRelid * * this preforms a scan of pg_class to ensure that - * no relation with the same name already exists. The caller - * has to open pg_class and pass an open descriptor. + * no relation with the same name already exists. * -------------------------------- */ -static int -RelationAlreadyExists(Relation pg_class_desc, char *relname) +Oid +RelnameFindRelid(char *relname) { - ScanKeyData key; - HeapScanDesc pg_class_scan; - HeapTuple tup; + HeapTuple tuple; + Oid relid; /* * If this is not bootstrap (initdb) time, use the catalog index on * pg_class. */ - if (!IsBootstrapProcessingMode()) { - tup = SearchSysCacheTuple(RELNAME, + tuple = SearchSysCacheTuple(RELNAME, PointerGetDatum(relname), 0, 0, 0); - if (HeapTupleIsValid(tup)) - return true; + if (HeapTupleIsValid(tuple)) + relid = tuple->t_data->t_oid; else - return false; + relid = InvalidOid; } + else + { + Relation pg_class_desc; + ScanKeyData key; + HeapScanDesc pg_class_scan; + + pg_class_desc = heap_openr(RelationRelationName); + + /* ---------------- + * At bootstrap time, we have to do this the hard way. Form the + * scan key. + * ---------------- + */ + ScanKeyEntryInitialize(&key, + 0, + (AttrNumber) Anum_pg_class_relname, + (RegProcedure) F_NAMEEQ, + (Datum) relname); + + /* ---------------- + * begin the scan + * ---------------- + */ + pg_class_scan = heap_beginscan(pg_class_desc, + 0, + SnapshotNow, + 1, + &key); + + /* ---------------- + * get a tuple. if the tuple is NULL then it means we + * didn't find an existing relation. + * ---------------- + */ + tuple = heap_getnext(pg_class_scan, 0); + + if (HeapTupleIsValid(tuple)) + relid = tuple->t_data->t_oid; + else + relid = InvalidOid; - /* ---------------- - * At bootstrap time, we have to do this the hard way. Form the - * scan key. - * ---------------- - */ - ScanKeyEntryInitialize(&key, - 0, - (AttrNumber) Anum_pg_class_relname, - (RegProcedure) F_NAMEEQ, - (Datum) relname); - - /* ---------------- - * begin the scan - * ---------------- - */ - pg_class_scan = heap_beginscan(pg_class_desc, - 0, - SnapshotNow, - 1, - &key); - - /* ---------------- - * get a tuple. if the tuple is NULL then it means we - * didn't find an existing relation. - * ---------------- - */ - tup = heap_getnext(pg_class_scan, 0); - - /* ---------------- - * end the scan and return existance of relation. - * ---------------- - */ - heap_endscan(pg_class_scan); + heap_endscan(pg_class_scan); - return HeapTupleIsValid(tup); + heap_close(pg_class_desc); + } + return relid; } /* -------------------------------- @@ -583,6 +595,7 @@ AddNewAttributeTuples(Oid new_rel_oid, (char *) *dpp); heap_insert(rel, tup); + if (hasindex) CatalogIndexInsert(idescs, Num_pg_attr_indices, rel, tup); @@ -623,18 +636,19 @@ AddNewAttributeTuples(Oid new_rel_oid, } /* -------------------------------- - * AddPgRelationTuple + * AddNewRelationTuple * * this registers the new relation in the catalogs by * adding a tuple to pg_class. * -------------------------------- */ static void -AddPgRelationTuple(Relation pg_class_desc, +AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, unsigned natts, - char relkind) + char relkind, + char *temp_relname) { Form_pg_class new_rel_reltup; HeapTuple tup; @@ -679,9 +693,11 @@ AddPgRelationTuple(Relation pg_class_desc, heap_insert(pg_class_desc, tup); + if (temp_relname) + create_temp_relation(temp_relname, tup); + if (!isBootstrap) { - /* * First, open the catalog indices and insert index tuples for the * new relation. @@ -690,23 +706,22 @@ AddPgRelationTuple(Relation pg_class_desc, CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs); CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class_desc, tup); CatalogCloseIndices(Num_pg_class_indices, idescs); - /* now restore processing mode */ SetProcessingMode(NormalProcessing); } - + pfree(tup); } /* -------------------------------- - * addNewRelationType - + * AddNewRelationType - * * define a complex type corresponding to the new relation * -------------------------------- */ static void -addNewRelationType(char *typeName, Oid new_rel_oid) +AddNewRelationType(char *typeName, Oid new_rel_oid) { Oid new_type_oid; @@ -745,38 +760,55 @@ addNewRelationType(char *typeName, Oid new_rel_oid) Oid heap_create_with_catalog(char *relname, TupleDesc tupdesc, - char relkind) + char relkind, + bool istemp) { Relation pg_class_desc; Relation new_rel_desc; Oid new_rel_oid; - int natts = tupdesc->natts; - + char *temp_relname = NULL; + /* ---------------- * sanity checks * ---------------- */ - AssertState(IsNormalProcessingMode() || IsBootstrapProcessingMode()); + Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode()); if (natts == 0 || natts > MaxHeapAttributeNumber) elog(ERROR, "amcreate: from 1 to %d attributes must be specified", - MaxHeapAttributeNumber); + MaxHeapAttributeNumber); CheckAttributeNames(tupdesc); - /* ---------------- - * open pg_class and see that the relation doesn't - * already exist. - * ---------------- - */ - pg_class_desc = heap_openr(RelationRelationName); + /* temp tables can mask non-temp tables */ + if ((!istemp && RelnameFindRelid(relname)) || + (istemp && get_temp_rel_by_name(relname) != NULL)) + elog(ERROR, "%s relation already exists", relname); - if (RelationAlreadyExists(pg_class_desc, relname)) + /* invalidate cache so non-temp table is masked by temp */ + if (istemp) { - heap_close(pg_class_desc); - elog(ERROR, "%s relation already exists", relname); - } + Oid relid = RelnameFindRelid(relname); + if (relid != InvalidOid) + { + /* + * This is heavy-handed, but appears necessary bjm 1999/02/01 + * SystemCacheRelationFlushed(relid) is not enough either. + */ + RelationForgetRelation(relid); + ResetSystemCache(); + } + } + + /* save user relation name because heap_create changes it */ + if (istemp) + { + temp_relname = pstrdup(relname); /* save original value */ + relname = palloc(NAMEDATALEN); + strcpy(relname, temp_relname); /* heap_create will change this */ + } + /* ---------------- * ok, relation does not already exist so now we * create an uncataloged relation and pull its relation oid @@ -784,9 +816,11 @@ heap_create_with_catalog(char *relname, * * Note: The call to heap_create() does all the "real" work * of creating the disk file for the relation. + * This changes relname for noname and temp tables. * ---------------- */ - new_rel_desc = heap_create(relname, tupdesc); + new_rel_desc = heap_create(relname, tupdesc, false, istemp); + new_rel_oid = new_rel_desc->rd_att->attrs[0]->attrelid; /* ---------------- @@ -794,7 +828,7 @@ heap_create_with_catalog(char *relname, * we add a new system type corresponding to the new relation. * ---------------- */ - addNewRelationType(relname, new_rel_oid); + AddNewRelationType(relname, new_rel_oid); /* ---------------- * now add tuples to pg_attribute for the attributes in @@ -807,14 +841,23 @@ heap_create_with_catalog(char *relname, * now update the information in pg_class. * ---------------- */ - AddPgRelationTuple(pg_class_desc, + pg_class_desc = heap_openr(RelationRelationName); + + AddNewRelationTuple(pg_class_desc, new_rel_desc, new_rel_oid, natts, - relkind); + relkind, + temp_relname); StoreConstraints(new_rel_desc); + if (istemp) + { + pfree(relname); + pfree(temp_relname); + } + /* ---------------- * ok, the relation has been cataloged, so close our relations * and return the oid of the newly created relation. @@ -990,12 +1033,12 @@ RelationRemoveIndexes(Relation relation) } /* -------------------------------- - * DeletePgRelationTuple + * DeleteRelationTuple * * -------------------------------- */ static void -DeletePgRelationTuple(Relation rel) +DeleteRelationTuple(Relation rel) { Relation pg_class_desc; HeapTuple tup; @@ -1012,7 +1055,7 @@ DeletePgRelationTuple(Relation rel) if (!HeapTupleIsValid(tup)) { heap_close(pg_class_desc); - elog(ERROR, "DeletePgRelationTuple: %s relation nonexistent", + elog(ERROR, "DeleteRelationTuple: %s relation nonexistent", &rel->rd_rel->relname); } @@ -1027,12 +1070,12 @@ DeletePgRelationTuple(Relation rel) } /* -------------------------------- - * DeletePgAttributeTuples + * DeleteAttributeTuples * * -------------------------------- */ static void -DeletePgAttributeTuples(Relation rel) +DeleteAttributeTuples(Relation rel) { Relation pg_attribute_desc; HeapTuple tup; @@ -1073,7 +1116,7 @@ DeletePgAttributeTuples(Relation rel) } /* -------------------------------- - * DeletePgTypeTuple + * DeleteTypeTuple * * If the user attempts to destroy a relation and there * exists attributes in other relations of type @@ -1082,7 +1125,7 @@ DeletePgAttributeTuples(Relation rel) * -------------------------------- */ static void -DeletePgTypeTuple(Relation rel) +DeleteTypeTuple(Relation rel) { Relation pg_type_desc; HeapScanDesc pg_type_scan; @@ -1127,7 +1170,7 @@ DeletePgTypeTuple(Relation rel) { heap_endscan(pg_type_scan); heap_close(pg_type_desc); - elog(ERROR, "DeletePgTypeTuple: %s type nonexistent", + elog(ERROR, "DeleteTypeTuple: %s type nonexistent", &rel->rd_rel->relname); } @@ -1171,7 +1214,7 @@ DeletePgTypeTuple(Relation rel) heap_endscan(pg_attribute_scan); heap_close(pg_attribute_desc); - elog(ERROR, "DeletePgTypeTuple: att of type %s exists in relation %d", + elog(ERROR, "DeleteTypeTuple: att of type %s exists in relation %d", &rel->rd_rel->relname, relid); } heap_endscan(pg_attribute_scan); @@ -1199,6 +1242,7 @@ heap_destroy_with_catalog(char *relname) { Relation rel; Oid rid; + bool istemp = (get_temp_rel_by_name(relname) != NULL); /* ---------------- * first open the relation. if the relation does exist, @@ -1216,7 +1260,8 @@ heap_destroy_with_catalog(char *relname) * prevent deletion of system relations * ---------------- */ - if (IsSystemRelationName(RelationGetRelationName(rel)->data)) + /* allow temp of pg_class? Guess so. */ + if (!istemp && IsSystemRelationName(RelationGetRelationName(rel)->data)) elog(ERROR, "amdestroy: cannot destroy %s relation", &rel->rd_rel->relname); @@ -1248,22 +1293,26 @@ heap_destroy_with_catalog(char *relname) * delete attribute tuples * ---------------- */ - DeletePgAttributeTuples(rel); + DeleteAttributeTuples(rel); + if (istemp) + remove_temp_relation(rid); + /* ---------------- * delete type tuple. here we want to see the effects * of the deletions we just did, so we use setheapoverride(). * ---------------- */ setheapoverride(true); - DeletePgTypeTuple(rel); + DeleteTypeTuple(rel); setheapoverride(false); /* ---------------- * delete relation tuple * ---------------- */ - DeletePgRelationTuple(rel); + /* must delete fake tuple in cache */ + DeleteRelationTuple(rel); /* * release dirty buffers of this relation @@ -1283,16 +1332,15 @@ heap_destroy_with_catalog(char *relname) * unlink the relation and finish up. * ---------------- */ - if (!(rel->rd_istemp) || !(rel->rd_tmpunlinked)) + if (!(rel->rd_isnoname) || !(rel->rd_nonameunlinked)) smgrunlink(DEFAULT_SMGR, rel); - rel->rd_tmpunlinked = TRUE; + rel->rd_nonameunlinked = TRUE; UnlockRelation(rel, AccessExclusiveLock); heap_close(rel); - /* ok - flush the relation from the relcache */ RelationForgetRelation(rid); } @@ -1306,11 +1354,11 @@ void heap_destroy(Relation rel) { ReleaseRelationBuffers(rel); - if (!(rel->rd_istemp) || !(rel->rd_tmpunlinked)) + if (!(rel->rd_isnoname) || !(rel->rd_nonameunlinked)) smgrunlink(DEFAULT_SMGR, rel); - rel->rd_tmpunlinked = TRUE; + rel->rd_nonameunlinked = TRUE; heap_close(rel); - RemoveFromTempRelList(rel); + RemoveFromNoNameRelList(rel); } @@ -1336,7 +1384,7 @@ heap_destroy(Relation rel) */ void -InitTempRelList(void) +InitNoNameRelList(void) { if (tempRels) { @@ -1356,10 +1404,10 @@ InitTempRelList(void) MODIFIES the global variable tempRels we don't really remove it, just mark it as NULL - and DestroyTempRels will look for NULLs + and DestroyNoNameRels will look for NULLs */ static void -RemoveFromTempRelList(Relation r) +RemoveFromNoNameRelList(Relation r) { int i; @@ -1382,7 +1430,7 @@ RemoveFromTempRelList(Relation r) MODIFIES the global variable tempRels */ static void -AddToTempRelList(Relation r) +AddToNoNameRelList(Relation r) { if (!tempRels) return; @@ -1401,7 +1449,7 @@ AddToTempRelList(Relation r) go through the tempRels list and destroy each of the relations */ void -DestroyTempRels(void) +DestroyNoNameRels(void) { int i; Relation rel; |