mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 00:03:57 -04:00 
			
		
		
		
	Reimplement temp tables using schemas. The temp table map is history;
temp table entries in pg_class have the names the user would expect.
This commit is contained in:
		
							parent
							
								
									5f4745adf4
								
							
						
					
					
						commit
						3114102521
					
				| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.118 2002/03/15 19:20:29 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.119 2002/03/31 06:26:29 tgl Exp $ | ||||
|  * | ||||
|  * NOTES | ||||
|  *		Transaction aborts can now occur two ways: | ||||
| @ -178,10 +178,9 @@ | ||||
| #include "utils/portal.h" | ||||
| #include "utils/catcache.h" | ||||
| #include "utils/relcache.h" | ||||
| #include "utils/temprel.h" | ||||
| 
 | ||||
| #include "pgstat.h" | ||||
| 
 | ||||
| 
 | ||||
| extern bool SharedBufferChanged; | ||||
| 
 | ||||
| static void AbortTransaction(void); | ||||
| @ -999,7 +998,6 @@ CommitTransaction(void) | ||||
| 	 */ | ||||
| 
 | ||||
| 	RelationPurgeLocalRelation(true); | ||||
| 	AtEOXact_temp_relations(true); | ||||
| 	smgrDoPendingDeletes(true); | ||||
| 
 | ||||
| 	AtEOXact_SPI(); | ||||
| @ -1102,7 +1100,6 @@ AbortTransaction(void) | ||||
| 	} | ||||
| 
 | ||||
| 	RelationPurgeLocalRelation(false); | ||||
| 	AtEOXact_temp_relations(false); | ||||
| 	smgrDoPendingDeletes(false); | ||||
| 
 | ||||
| 	AtEOXact_SPI(); | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $Header: /cvsroot/pgsql/src/backend/access/transam/xlogutils.c,v 1.22 2002/03/02 21:39:20 momjian Exp $ | ||||
|  * $Header: /cvsroot/pgsql/src/backend/access/transam/xlogutils.c,v 1.23 2002/03/31 06:26:29 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -335,7 +335,7 @@ XLogOpenRelation(bool redo, RmgrId rmid, RelFileNode rnode) | ||||
| 	{ | ||||
| 		res = _xl_new_reldesc(); | ||||
| 
 | ||||
| 		sprintf(RelationGetPhysicalRelationName(&(res->reldata)), "%u", rnode.relNode); | ||||
| 		sprintf(RelationGetRelationName(&(res->reldata)), "%u", rnode.relNode); | ||||
| 
 | ||||
| 		/* unexisting DB id */ | ||||
| 		res->reldata.rd_lockInfo.lockRelId.dbId = RecoveryDb; | ||||
|  | ||||
| @ -9,7 +9,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.41 2002/03/26 19:15:16 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.42 2002/03/31 06:26:29 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -184,7 +184,7 @@ Boot_CreateStmt: | ||||
| 						reldesc = heap_create(LexIDStr($4), | ||||
| 											  PG_CATALOG_NAMESPACE, | ||||
| 											  tupdesc, | ||||
| 											  false, true, true); | ||||
| 											  true, true); | ||||
| 						reldesc->rd_rel->relhasoids = ! ($3); | ||||
| 						elog(DEBUG3, "bootstrap relation created"); | ||||
| 					} | ||||
| @ -199,7 +199,6 @@ Boot_CreateStmt: | ||||
| 													  tupdesc, | ||||
| 													  RELKIND_RELATION, | ||||
| 													  ! ($3), | ||||
| 													  false, | ||||
| 													  true); | ||||
| 						elog(DEBUG3, "relation created with oid %u", id); | ||||
| 					} | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.60 2002/03/29 19:05:59 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.61 2002/03/31 06:26:29 tgl Exp $ | ||||
|  * | ||||
|  * NOTES | ||||
|  *	  See acl.h. | ||||
| @ -40,7 +40,6 @@ | ||||
| #include "parser/parse_type.h" | ||||
| #include "utils/acl.h" | ||||
| #include "utils/syscache.h" | ||||
| #include "utils/temprel.h" | ||||
| 
 | ||||
| 
 | ||||
| static void ExecuteGrantStmt_Table(GrantStmt *stmt); | ||||
| @ -811,7 +810,6 @@ pg_class_aclcheck(Oid table_oid, Oid userid, AclMode mode) | ||||
| 	relname = NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname); | ||||
| 	if ((mode & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) && | ||||
| 		!allowSystemTableMods && IsSystemRelationName(relname) && | ||||
| 		!is_temp_relname(relname) && | ||||
| 		!usecatupd) | ||||
| 	{ | ||||
| #ifdef ACLDEBUG | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.193 2002/03/29 19:05:59 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.194 2002/03/31 06:26:29 tgl Exp $ | ||||
|  * | ||||
|  * | ||||
|  * INTERFACE ROUTINES | ||||
| @ -61,14 +61,12 @@ | ||||
| #include "utils/lsyscache.h" | ||||
| #include "utils/relcache.h" | ||||
| #include "utils/syscache.h" | ||||
| #include "utils/temprel.h" | ||||
| 
 | ||||
| 
 | ||||
| static void AddNewRelationTuple(Relation pg_class_desc, | ||||
| 					Relation new_rel_desc, | ||||
| 					Oid new_rel_oid, Oid new_type_oid, | ||||
| 					char relkind, bool relhasoids, | ||||
| 					char *temp_relname); | ||||
| 					char relkind, bool relhasoids); | ||||
| static void DeleteAttributeTuples(Relation rel); | ||||
| static void DeleteRelationTuple(Relation rel); | ||||
| static void DeleteTypeTuple(Relation rel); | ||||
| @ -205,34 +203,29 @@ SystemAttributeByName(const char *attname, bool relhasoids) | ||||
|  * | ||||
|  *		Remove the system relation specific code to elsewhere eventually. | ||||
|  * | ||||
|  * NOTE: if istemp is TRUE then heap_create will overwrite relname with | ||||
|  * the unique "real" name chosen for the temp 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, | ||||
| heap_create(const char *relname, | ||||
| 			Oid relnamespace, | ||||
| 			TupleDesc tupDesc, | ||||
| 			bool istemp, | ||||
| 			bool storage_create, | ||||
| 			bool allow_system_table_mods) | ||||
| { | ||||
| 	static unsigned int uniqueId = 0; | ||||
| 
 | ||||
| 	Oid			relid; | ||||
| 	Oid			dbid = MyDatabaseId; | ||||
| 	RelFileNode	rnode; | ||||
| 	bool		nailme = false; | ||||
| 	RelFileNode	rnode; | ||||
| 	Relation	rel; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * sanity checks | ||||
| 	 */ | ||||
| 	if (relname && !allow_system_table_mods && | ||||
| 		IsSystemRelationName(relname) && IsNormalProcessingMode()) | ||||
| 	if (!allow_system_table_mods && | ||||
| 		IsSystemRelationName(relname) && | ||||
| 		IsNormalProcessingMode()) | ||||
| 		elog(ERROR, "invalid relation name \"%s\"; " | ||||
| 			 "the 'pg_' name prefix is reserved for system catalogs", | ||||
| 			 relname); | ||||
| @ -291,16 +284,6 @@ heap_create(char *relname, | ||||
| 	else | ||||
| 		relid = newoid(); | ||||
| 
 | ||||
| 	if (istemp) | ||||
| 	{ | ||||
| 		/*
 | ||||
| 		 * replace relname of caller with a unique name for a temp | ||||
| 		 * relation | ||||
| 		 */ | ||||
| 		snprintf(relname, NAMEDATALEN, "%s_%d_%u", | ||||
| 				 PG_TEMP_REL_PREFIX, (int) MyProcPid, uniqueId++); | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * For now, the physical identifier of the relation is the same as the | ||||
| 	 * logical identifier. | ||||
| @ -528,8 +511,7 @@ AddNewRelationTuple(Relation pg_class_desc, | ||||
| 					Oid new_rel_oid, | ||||
| 					Oid new_type_oid, | ||||
| 					char relkind, | ||||
| 					bool relhasoids, | ||||
| 					char *temp_relname) | ||||
| 					bool relhasoids) | ||||
| { | ||||
| 	Form_pg_class new_rel_reltup; | ||||
| 	HeapTuple	tup; | ||||
| @ -599,9 +581,6 @@ AddNewRelationTuple(Relation pg_class_desc, | ||||
| 	 */ | ||||
| 	heap_insert(pg_class_desc, tup); | ||||
| 
 | ||||
| 	if (temp_relname) | ||||
| 		create_temp_relation(temp_relname, tup); | ||||
| 
 | ||||
| 	if (!IsIgnoringSystemIndexes()) | ||||
| 	{ | ||||
| 		/*
 | ||||
| @ -669,19 +648,17 @@ AddNewRelationType(const char *typeName, | ||||
|  * -------------------------------- | ||||
|  */ | ||||
| Oid | ||||
| heap_create_with_catalog(char *relname, | ||||
| heap_create_with_catalog(const char *relname, | ||||
| 						 Oid relnamespace, | ||||
| 						 TupleDesc tupdesc, | ||||
| 						 char relkind, | ||||
| 						 bool relhasoids, | ||||
| 						 bool istemp, | ||||
| 						 bool allow_system_table_mods) | ||||
| { | ||||
| 	Relation	pg_class_desc; | ||||
| 	Relation	new_rel_desc; | ||||
| 	Oid			new_rel_oid; | ||||
| 	Oid			new_type_oid; | ||||
| 	char	   *temp_relname = NULL; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * sanity checks | ||||
| @ -693,32 +670,17 @@ heap_create_with_catalog(char *relname, | ||||
| 
 | ||||
| 	CheckAttributeNames(tupdesc, relhasoids); | ||||
| 
 | ||||
| 	/* temp tables can mask non-temp tables */ | ||||
| 	if ((!istemp && get_relname_relid(relname, relnamespace)) || | ||||
| 		(istemp && is_temp_rel_name(relname))) | ||||
| 	if (get_relname_relid(relname, relnamespace)) | ||||
| 		elog(ERROR, "Relation '%s' already exists", relname); | ||||
| 
 | ||||
| 	if (istemp) | ||||
| 	{ | ||||
| 		/* save user relation name because heap_create changes it */ | ||||
| 		temp_relname = pstrdup(relname);		/* save original value */ | ||||
| 		relname = palloc(NAMEDATALEN); | ||||
| 		strcpy(relname, temp_relname);	/* heap_create will change this */ | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Tell heap_create not to create a physical file; we'll do that below | ||||
| 	 * after all our catalog updates are done.	(This isn't really | ||||
| 	 * necessary anymore, but we may as well avoid the cycles of creating | ||||
| 	 * and deleting the file in case we fail.) | ||||
| 	 * | ||||
| 	 * Note: The call to heap_create() changes relname for 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, relnamespace, tupdesc, | ||||
| 							   istemp, false, allow_system_table_mods); | ||||
| 							   false, allow_system_table_mods); | ||||
| 
 | ||||
| 	/* Fetch the relation OID assigned by heap_create */ | ||||
| 	new_rel_oid = new_rel_desc->rd_att->attrs[0]->attrelid; | ||||
| @ -740,8 +702,7 @@ heap_create_with_catalog(char *relname, | ||||
| 						new_rel_oid, | ||||
| 						new_type_oid, | ||||
| 						relkind, | ||||
| 						relhasoids, | ||||
| 						temp_relname); | ||||
| 						relhasoids); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * since defining a relation also defines a complex type, we add a new | ||||
| @ -780,12 +741,6 @@ heap_create_with_catalog(char *relname, | ||||
| 	heap_close(new_rel_desc, NoLock);	/* do not unlock till end of xact */ | ||||
| 	heap_close(pg_class_desc, RowExclusiveLock); | ||||
| 
 | ||||
| 	if (istemp) | ||||
| 	{ | ||||
| 		pfree(relname); | ||||
| 		pfree(temp_relname); | ||||
| 	} | ||||
| 
 | ||||
| 	return new_rel_oid; | ||||
| } | ||||
| 
 | ||||
| @ -1226,26 +1181,19 @@ heap_drop_with_catalog(Oid rid, | ||||
| { | ||||
| 	Relation	rel; | ||||
| 	Oid			toasttableOid; | ||||
| 	bool		has_toasttable; | ||||
| 	bool		istemp; | ||||
| 	int			i; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Open and lock the relation. | ||||
| 	 */ | ||||
| 	rel = heap_open(rid, AccessExclusiveLock); | ||||
| 	has_toasttable = rel->rd_rel->reltoastrelid != InvalidOid; | ||||
| 	toasttableOid = rel->rd_rel->reltoastrelid; | ||||
| 	istemp = is_temp_rel_name(RelationGetRelationName(rel)); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * prevent deletion of system relations | ||||
| 	 */ | ||||
| 	/* allow temp of pg_class? Guess so. */ | ||||
| 	if (!istemp && | ||||
| 		!allow_system_table_mods && | ||||
| 		IsSystemRelationName(RelationGetRelationName(rel)) && | ||||
| 		!is_temp_relname(RelationGetRelationName(rel))) | ||||
| 	if (!allow_system_table_mods && | ||||
| 		IsSystemRelationName(RelationGetRelationName(rel))) | ||||
| 		elog(ERROR, "System relation \"%s\" may not be dropped", | ||||
| 			 RelationGetRelationName(rel)); | ||||
| 
 | ||||
| @ -1319,11 +1267,8 @@ heap_drop_with_catalog(Oid rid, | ||||
| 	 */ | ||||
| 	RelationForgetRelation(rid); | ||||
| 
 | ||||
| 	/* and from the temp-table map */ | ||||
| 	if (istemp) | ||||
| 		remove_temp_rel_by_relid(rid); | ||||
| 
 | ||||
| 	if (has_toasttable) | ||||
| 	/* If it has a toast table, recurse to get rid of that too */ | ||||
| 	if (OidIsValid(toasttableOid)) | ||||
| 		heap_drop_with_catalog(toasttableOid, true); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.174 2002/03/26 19:15:28 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.175 2002/03/31 06:26:29 tgl Exp $ | ||||
|  * | ||||
|  * | ||||
|  * INTERFACE ROUTINES | ||||
| @ -33,6 +33,7 @@ | ||||
| #include "catalog/index.h" | ||||
| #include "catalog/indexing.h" | ||||
| #include "catalog/pg_index.h" | ||||
| #include "catalog/pg_namespace.h" | ||||
| #include "catalog/pg_opclass.h" | ||||
| #include "catalog/pg_proc.h" | ||||
| #include "catalog/pg_type.h" | ||||
| @ -51,7 +52,6 @@ | ||||
| #include "utils/lsyscache.h" | ||||
| #include "utils/relcache.h" | ||||
| #include "utils/syscache.h" | ||||
| #include "utils/temprel.h" | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
| @ -69,7 +69,7 @@ static TupleDesc ConstructTupleDescriptor(Relation heapRelation, | ||||
| 						 int numatts, AttrNumber *attNums, | ||||
| 						 Oid *classObjectId); | ||||
| static void ConstructIndexReldesc(Relation indexRelation, Oid amoid); | ||||
| static void UpdateRelationRelation(Relation indexRelation, char *temp_relname); | ||||
| static void UpdateRelationRelation(Relation indexRelation); | ||||
| static void InitializeAttributeOids(Relation indexRelation, | ||||
| 						int numatts, Oid indexoid); | ||||
| static void AppendAttributeTuples(Relation indexRelation, int numatts); | ||||
| @ -320,7 +320,8 @@ ConstructIndexReldesc(Relation indexRelation, Oid amoid) | ||||
| 	indexRelation->rd_rel->relowner = GetUserId(); | ||||
| 	indexRelation->rd_rel->relam = amoid; | ||||
| 	indexRelation->rd_rel->relisshared = | ||||
| 		IsSharedSystemRelationName(RelationGetPhysicalRelationName(indexRelation)); | ||||
| 		(RelationGetNamespace(indexRelation) == PG_CATALOG_NAMESPACE) && | ||||
| 		IsSharedSystemRelationName(RelationGetRelationName(indexRelation)); | ||||
| 	indexRelation->rd_rel->relkind = RELKIND_INDEX; | ||||
| 	indexRelation->rd_rel->relhasoids = false; | ||||
| } | ||||
| @ -330,7 +331,7 @@ ConstructIndexReldesc(Relation indexRelation, Oid amoid) | ||||
|  * ---------------------------------------------------------------- | ||||
|  */ | ||||
| static void | ||||
| UpdateRelationRelation(Relation indexRelation, char *temp_relname) | ||||
| UpdateRelationRelation(Relation indexRelation) | ||||
| { | ||||
| 	Relation	pg_class; | ||||
| 	HeapTuple	tuple; | ||||
| @ -350,16 +351,12 @@ UpdateRelationRelation(Relation indexRelation, char *temp_relname) | ||||
| 	tuple->t_data->t_oid = RelationGetRelid(indexRelation); | ||||
| 	heap_insert(pg_class, tuple); | ||||
| 
 | ||||
| 	if (temp_relname) | ||||
| 		create_temp_relation(temp_relname, tuple); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * During normal processing, we need to make sure that the system | ||||
| 	 * catalog indices are correct.  Bootstrap (initdb) time doesn't | ||||
| 	 * require this, because we make sure that the indices are correct | ||||
| 	 * just before exiting. | ||||
| 	 */ | ||||
| 
 | ||||
| 	if (!IsIgnoringSystemIndexes()) | ||||
| 	{ | ||||
| 		CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs); | ||||
| @ -555,11 +552,10 @@ UpdateIndexRelation(Oid indexoid, | ||||
|  */ | ||||
| Oid | ||||
| index_create(Oid heapRelationId, | ||||
| 			 char *indexRelationName, | ||||
| 			 const char *indexRelationName, | ||||
| 			 IndexInfo *indexInfo, | ||||
| 			 Oid accessMethodObjectId, | ||||
| 			 Oid *classObjectId, | ||||
| 			 bool istemp, | ||||
| 			 bool primary, | ||||
| 			 bool allow_system_table_mods) | ||||
| { | ||||
| @ -568,7 +564,6 @@ index_create(Oid heapRelationId, | ||||
| 	TupleDesc	indexTupDesc; | ||||
| 	Oid			namespaceId; | ||||
| 	Oid			indexoid; | ||||
| 	char	   *temp_relname = NULL; | ||||
| 
 | ||||
| 	SetReindexProcessing(false); | ||||
| 
 | ||||
| @ -591,8 +586,7 @@ index_create(Oid heapRelationId, | ||||
| 		IsNormalProcessingMode()) | ||||
| 		elog(ERROR, "User-defined indexes on system catalogs are not supported"); | ||||
| 
 | ||||
| 	if ((!istemp && get_relname_relid(indexRelationName, namespaceId)) || | ||||
| 		(istemp && is_temp_rel_name(indexRelationName))) | ||||
| 	if (get_relname_relid(indexRelationName, namespaceId)) | ||||
| 		elog(ERROR, "index named \"%s\" already exists", | ||||
| 			 indexRelationName); | ||||
| 
 | ||||
| @ -608,22 +602,14 @@ index_create(Oid heapRelationId, | ||||
| 											indexInfo->ii_KeyAttrNumbers, | ||||
| 												classObjectId); | ||||
| 
 | ||||
| 	if (istemp) | ||||
| 	{ | ||||
| 		/* save user relation name because heap_create changes it */ | ||||
| 		temp_relname = pstrdup(indexRelationName);		/* save original */ | ||||
| 		indexRelationName = palloc(NAMEDATALEN); | ||||
| 		strcpy(indexRelationName, temp_relname);		/* heap_create will
 | ||||
| 														 * change this */ | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * create the index relation | ||||
| 	 * create the index relation (but don't create storage yet) | ||||
| 	 */ | ||||
| 	indexRelation = heap_create(indexRelationName, | ||||
| 								namespaceId, | ||||
| 								indexTupDesc, | ||||
| 								istemp, false, allow_system_table_mods); | ||||
| 								false, | ||||
| 								allow_system_table_mods); | ||||
| 	indexoid = RelationGetRelid(indexRelation); | ||||
| 
 | ||||
| 	/*
 | ||||
| @ -645,7 +631,7 @@ index_create(Oid heapRelationId, | ||||
| 	 *	  (append RELATION tuple) | ||||
| 	 * ---------------- | ||||
| 	 */ | ||||
| 	UpdateRelationRelation(indexRelation, temp_relname); | ||||
| 	UpdateRelationRelation(indexRelation); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * We create the disk file for this relation here | ||||
| @ -835,9 +821,6 @@ index_drop(Oid indexId) | ||||
| 	heap_close(userHeapRelation, NoLock); | ||||
| 
 | ||||
| 	RelationForgetRelation(indexId); | ||||
| 
 | ||||
| 	/* if it's a temp index, clear the temp mapping table entry */ | ||||
| 	remove_temp_rel_by_relid(indexId); | ||||
| } | ||||
| 
 | ||||
| /* ----------------------------------------------------------------
 | ||||
|  | ||||
| @ -13,20 +13,86 @@ | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.3 2002/03/30 01:02:41 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.4 2002/03/31 06:26:30 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| #include "postgres.h" | ||||
| 
 | ||||
| #include "access/heapam.h" | ||||
| #include "access/xact.h" | ||||
| #include "catalog/catname.h" | ||||
| #include "catalog/heap.h" | ||||
| #include "catalog/namespace.h" | ||||
| #include "catalog/pg_inherits.h" | ||||
| #include "catalog/pg_namespace.h" | ||||
| #include "catalog/pg_shadow.h" | ||||
| #include "miscadmin.h" | ||||
| #include "nodes/makefuncs.h" | ||||
| #include "storage/backendid.h" | ||||
| #include "utils/fmgroids.h" | ||||
| #include "utils/lsyscache.h" | ||||
| #include "utils/syscache.h" | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * The namespace search path is a possibly-empty list of namespace OIDs. | ||||
|  * In addition to the explicit list, the TEMP table namespace is always | ||||
|  * implicitly searched first (if it's been initialized).  Also, the system | ||||
|  * catalog namespace is always searched.  If the system namespace is | ||||
|  * explicitly present in the path then it will be searched in the specified | ||||
|  * order; otherwise it will be searched after TEMP tables and *before* the | ||||
|  * explicit list.  (It might seem that the system namespace should be | ||||
|  * implicitly last, but this behavior appears to be required by SQL99. | ||||
|  * Also, this provides a way to search the system namespace first without | ||||
|  * thereby making it the default creation target namespace.) | ||||
|  * | ||||
|  * The default creation target namespace is kept equal to the first element | ||||
|  * of the explicit list, or is the system namespace if the list is empty. | ||||
|  * | ||||
|  * In bootstrap mode or a standalone backend, the default search path is | ||||
|  * empty, so that the system namespace is the only one searched or inserted | ||||
|  * into.  In multiuser mode, the default search path contains the PG_PUBLIC | ||||
|  * namespace, preceded by the user's own namespace if one exists. | ||||
|  */ | ||||
| 
 | ||||
| static List *namespaceSearchPath = NIL; | ||||
| 
 | ||||
| /* this flag must be updated correctly when namespaceSearchPath is changed */ | ||||
| static bool pathContainsSystemNamespace = false; | ||||
| 
 | ||||
| /* default place to create stuff */ | ||||
| static Oid	defaultCreationNamespace = PG_CATALOG_NAMESPACE; | ||||
| 
 | ||||
| /*
 | ||||
|  * myTempNamespace is InvalidOid until and unless a TEMP namespace is set up | ||||
|  * in a particular backend session (this happens when a CREATE TEMP TABLE | ||||
|  * command is first executed).  Thereafter it's the OID of the temp namespace. | ||||
|  */ | ||||
| static Oid	myTempNamespace = InvalidOid; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * Deletion ordering constraint item. | ||||
|  */ | ||||
| typedef struct DelConstraint | ||||
| { | ||||
| 	Oid			referencer;		/* table to delete first */ | ||||
| 	Oid			referencee;		/* table to delete second */ | ||||
| 	int			pred;			/* workspace for TopoSortRels */ | ||||
| 	struct DelConstraint *link;	/* workspace for TopoSortRels */ | ||||
| } DelConstraint; | ||||
| 
 | ||||
| 
 | ||||
| /* Local functions */ | ||||
| static Oid	GetTempTableNamespace(void); | ||||
| static void RemoveTempRelations(Oid tempNamespaceId); | ||||
| static List *FindTempRelations(Oid tempNamespaceId); | ||||
| static List *FindDeletionConstraints(List *relOids); | ||||
| static List *TopoSortRels(List *relOids, List *constraintList); | ||||
| static void RemoveTempRelationsCallback(void); | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * RangeVarGetRelid | ||||
|  *		Given a RangeVar describing an existing relation, | ||||
| @ -52,6 +118,7 @@ RangeVarGetRelid(const RangeVar *relation, bool failOK) | ||||
| 
 | ||||
| 	if (relation->schemaname) | ||||
| 	{ | ||||
| 		/* use exact schema given */ | ||||
| 		namespaceId = GetSysCacheOid(NAMESPACENAME, | ||||
| 									 CStringGetDatum(relation->schemaname), | ||||
| 									 0, 0, 0); | ||||
| @ -62,6 +129,7 @@ RangeVarGetRelid(const RangeVar *relation, bool failOK) | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		/* search the namespace path */ | ||||
| 		relId = RelnameGetRelid(relation->relname); | ||||
| 	} | ||||
| 
 | ||||
| @ -100,8 +168,20 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation) | ||||
| 			elog(ERROR, "Cross-database references are not implemented"); | ||||
| 	} | ||||
| 
 | ||||
| 	if (newRelation->istemp) | ||||
| 	{ | ||||
| 		/* TEMP tables are created in our backend-local temp namespace */ | ||||
| 		if (newRelation->schemaname) | ||||
| 			elog(ERROR, "TEMP tables may not specify a namespace"); | ||||
| 		/* Initialize temp namespace if first time through */ | ||||
| 		if (!OidIsValid(myTempNamespace)) | ||||
| 			myTempNamespace = GetTempTableNamespace(); | ||||
| 		return myTempNamespace; | ||||
| 	} | ||||
| 
 | ||||
| 	if (newRelation->schemaname) | ||||
| 	{ | ||||
| 		/* use exact schema given */ | ||||
| 		namespaceId = GetSysCacheOid(NAMESPACENAME, | ||||
| 									 CStringGetDatum(newRelation->schemaname), | ||||
| 									 0, 0, 0); | ||||
| @ -111,8 +191,8 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation) | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		/* XXX Wrong!  Need to get a default schema from somewhere */ | ||||
| 		namespaceId = PG_CATALOG_NAMESPACE; | ||||
| 		/* use the default creation namespace */ | ||||
| 		namespaceId = defaultCreationNamespace; | ||||
| 	} | ||||
| 
 | ||||
| 	return namespaceId; | ||||
| @ -126,23 +206,91 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation) | ||||
| Oid | ||||
| RelnameGetRelid(const char *relname) | ||||
| { | ||||
| 	/* XXX Wrong!  must search search path */ | ||||
| 	return get_relname_relid(relname, PG_CATALOG_NAMESPACE); | ||||
| 	Oid			relid; | ||||
| 	List	   *lptr; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If a TEMP-table namespace has been set up, it is implicitly first | ||||
| 	 * in the search path. | ||||
| 	 */ | ||||
| 	if (OidIsValid(myTempNamespace)) | ||||
| 	{ | ||||
| 		relid = get_relname_relid(relname, myTempNamespace); | ||||
| 		if (OidIsValid(relid)) | ||||
| 			return relid; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If system namespace is not in path, implicitly search it before path | ||||
| 	 */ | ||||
| 	if (!pathContainsSystemNamespace) | ||||
| 	{ | ||||
| 		relid = get_relname_relid(relname, PG_CATALOG_NAMESPACE); | ||||
| 		if (OidIsValid(relid)) | ||||
| 			return relid; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Else search the path | ||||
| 	 */ | ||||
| 	foreach(lptr, namespaceSearchPath) | ||||
| 	{ | ||||
| 		Oid			namespaceId = (Oid) lfirsti(lptr); | ||||
| 
 | ||||
| 		relid = get_relname_relid(relname, namespaceId); | ||||
| 		if (OidIsValid(relid)) | ||||
| 			return relid; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Not found in path */ | ||||
| 	return InvalidOid; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * TypenameGetTypid | ||||
|  *		Try to resolve an unqualified datatype name. | ||||
|  *		Returns OID if type found in search path, else InvalidOid. | ||||
|  * | ||||
|  * This is essentially the same as RelnameGetRelid, but we never search | ||||
|  * the TEMP table namespace --- there is no reason to refer to the types | ||||
|  * of temp tables, AFAICS. | ||||
|  */ | ||||
| Oid | ||||
| TypenameGetTypid(const char *typname) | ||||
| { | ||||
| 	/* XXX wrong, should use namespace search */ | ||||
| 	return GetSysCacheOid(TYPENAMENSP, | ||||
| 						  PointerGetDatum(typname), | ||||
| 						  ObjectIdGetDatum(PG_CATALOG_NAMESPACE), | ||||
| 						  0, 0); | ||||
| 	Oid			typid; | ||||
| 	List	   *lptr; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If system namespace is not in path, implicitly search it before path | ||||
| 	 */ | ||||
| 	if (!pathContainsSystemNamespace) | ||||
| 	{ | ||||
| 		typid = GetSysCacheOid(TYPENAMENSP, | ||||
| 							   PointerGetDatum(typname), | ||||
| 							   ObjectIdGetDatum(PG_CATALOG_NAMESPACE), | ||||
| 							   0, 0); | ||||
| 		if (OidIsValid(typid)) | ||||
| 			return typid; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Else search the path | ||||
| 	 */ | ||||
| 	foreach(lptr, namespaceSearchPath) | ||||
| 	{ | ||||
| 		Oid			namespaceId = (Oid) lfirsti(lptr); | ||||
| 
 | ||||
| 		typid = GetSysCacheOid(TYPENAMENSP, | ||||
| 							   PointerGetDatum(typname), | ||||
| 							   ObjectIdGetDatum(namespaceId), | ||||
| 							   0, 0); | ||||
| 		if (OidIsValid(typid)) | ||||
| 			return typid; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Not found in path */ | ||||
| 	return InvalidOid; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -150,6 +298,9 @@ TypenameGetTypid(const char *typname) | ||||
|  *		Given a possibly-qualified name for an object (in List-of-Values | ||||
|  *		format), determine what namespace the object should be created in. | ||||
|  *		Also extract and return the object name (last component of list). | ||||
|  * | ||||
|  * This is *not* used for tables.  Hence, the TEMP table namespace is | ||||
|  * never selected as the creation target. | ||||
|  */ | ||||
| Oid | ||||
| QualifiedNameGetCreationNamespace(List *names, char **objname_p) | ||||
| @ -186,6 +337,7 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p) | ||||
| 
 | ||||
| 	if (schemaname) | ||||
| 	{ | ||||
| 		/* use exact schema given */ | ||||
| 		namespaceId = GetSysCacheOid(NAMESPACENAME, | ||||
| 									 CStringGetDatum(schemaname), | ||||
| 									 0, 0, 0); | ||||
| @ -195,8 +347,8 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p) | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		/* XXX Wrong!  Need to get a default schema from somewhere */ | ||||
| 		namespaceId = PG_CATALOG_NAMESPACE; | ||||
| 		/* use the default creation namespace */ | ||||
| 		namespaceId = defaultCreationNamespace; | ||||
| 	} | ||||
| 
 | ||||
| 	*objname_p = objname; | ||||
| @ -233,3 +385,320 @@ makeRangeVarFromNameList(List *names) | ||||
| 
 | ||||
| 	return rel; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * isTempNamespace - is the given namespace my temporary-table namespace? | ||||
|  */ | ||||
| bool | ||||
| isTempNamespace(Oid namespaceId) | ||||
| { | ||||
| 	if (OidIsValid(myTempNamespace) && myTempNamespace == namespaceId) | ||||
| 		return true; | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * GetTempTableNamespace | ||||
|  *		Initialize temp table namespace on first use in a particular backend | ||||
|  */ | ||||
| static Oid | ||||
| GetTempTableNamespace(void) | ||||
| { | ||||
| 	char		namespaceName[NAMEDATALEN]; | ||||
| 	Oid			namespaceId; | ||||
| 
 | ||||
| 	snprintf(namespaceName, NAMEDATALEN, "pg_temp_%d", MyBackendId); | ||||
| 
 | ||||
| 	namespaceId = GetSysCacheOid(NAMESPACENAME, | ||||
| 								 CStringGetDatum(namespaceName), | ||||
| 								 0, 0, 0); | ||||
| 	if (!OidIsValid(namespaceId)) | ||||
| 	{ | ||||
| 		/*
 | ||||
| 		 * First use of this temp namespace in this database; create it. | ||||
| 		 * The temp namespaces are always owned by the superuser. | ||||
| 		 */ | ||||
| 		namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_USESYSID); | ||||
| 		/* Advance command counter to make namespace visible */ | ||||
| 		CommandCounterIncrement(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		/*
 | ||||
| 		 * If the namespace already exists, clean it out (in case the | ||||
| 		 * former owner crashed without doing so). | ||||
| 		 */ | ||||
| 		RemoveTempRelations(namespaceId); | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Register exit callback to clean out temp tables at backend shutdown. | ||||
| 	 */ | ||||
| 	on_shmem_exit(RemoveTempRelationsCallback, 0); | ||||
| 
 | ||||
| 	return namespaceId; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Remove all relations in the specified temp namespace. | ||||
|  * | ||||
|  * This is called at backend shutdown (if we made any temp relations). | ||||
|  * It is also called when we begin using a pre-existing temp namespace, | ||||
|  * in order to clean out any relations that might have been created by | ||||
|  * a crashed backend. | ||||
|  */ | ||||
| static void | ||||
| RemoveTempRelations(Oid tempNamespaceId) | ||||
| { | ||||
| 	List	   *tempRelList; | ||||
| 	List	   *constraintList; | ||||
| 	List	   *lptr; | ||||
| 
 | ||||
| 	/* Get a list of relations to delete */ | ||||
| 	tempRelList = FindTempRelations(tempNamespaceId); | ||||
| 
 | ||||
| 	if (tempRelList == NIL) | ||||
| 		return;					/* nothing to do */ | ||||
| 
 | ||||
| 	/* If more than one, sort them to respect any deletion-order constraints */ | ||||
| 	if (length(tempRelList) > 1) | ||||
| 	{ | ||||
| 		constraintList = FindDeletionConstraints(tempRelList); | ||||
| 		if (constraintList != NIL) | ||||
| 			tempRelList = TopoSortRels(tempRelList, constraintList); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Scan the list and delete all entries */ | ||||
| 	foreach(lptr, tempRelList) | ||||
| 	{ | ||||
| 		Oid			reloid = (Oid) lfirsti(lptr); | ||||
| 
 | ||||
| 		heap_drop_with_catalog(reloid, true); | ||||
| 		/*
 | ||||
| 		 * Advance cmd counter to make catalog changes visible, in case | ||||
| 		 * a later entry depends on this one. | ||||
| 		 */ | ||||
| 		CommandCounterIncrement(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Find all relations in the specified temp namespace. | ||||
|  * | ||||
|  * Returns a list of relation OIDs. | ||||
|  */ | ||||
| static List * | ||||
| FindTempRelations(Oid tempNamespaceId) | ||||
| { | ||||
| 	List	   *tempRelList = NIL; | ||||
| 	Relation	pgclass; | ||||
| 	HeapScanDesc scan; | ||||
| 	HeapTuple	tuple; | ||||
| 	ScanKeyData key; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Scan pg_class to find all the relations in the target namespace. | ||||
| 	 * Ignore indexes, though, on the assumption that they'll go away | ||||
| 	 * when their tables are deleted. | ||||
| 	 */ | ||||
| 	ScanKeyEntryInitialize(&key, 0x0, | ||||
| 						   Anum_pg_class_relnamespace, | ||||
| 						   F_OIDEQ, | ||||
| 						   ObjectIdGetDatum(tempNamespaceId)); | ||||
| 
 | ||||
| 	pgclass = heap_openr(RelationRelationName, AccessShareLock); | ||||
| 	scan = heap_beginscan(pgclass, false, SnapshotNow, 1, &key); | ||||
| 
 | ||||
| 	while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) | ||||
| 	{ | ||||
| 		switch (((Form_pg_class) GETSTRUCT(tuple))->relkind) | ||||
| 		{ | ||||
| 			case RELKIND_RELATION: | ||||
| 			case RELKIND_SEQUENCE: | ||||
| 			case RELKIND_VIEW: | ||||
| 				tempRelList = lconsi(tuple->t_data->t_oid, tempRelList); | ||||
| 				break; | ||||
| 			default: | ||||
| 				break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	heap_endscan(scan); | ||||
| 	heap_close(pgclass, AccessShareLock); | ||||
| 
 | ||||
| 	return tempRelList; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Find deletion-order constraints involving the given relation OIDs. | ||||
|  * | ||||
|  * Returns a list of DelConstraint objects. | ||||
|  */ | ||||
| static List * | ||||
| FindDeletionConstraints(List *relOids) | ||||
| { | ||||
| 	List	   *constraintList = NIL; | ||||
| 	Relation	inheritsrel; | ||||
| 	HeapScanDesc scan; | ||||
| 	HeapTuple	tuple; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Scan pg_inherits to find parents and children that are in the list. | ||||
| 	 */ | ||||
| 	inheritsrel = heap_openr(InheritsRelationName, AccessShareLock); | ||||
| 	scan = heap_beginscan(inheritsrel, 0, SnapshotNow, 0, NULL); | ||||
| 
 | ||||
| 	while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) | ||||
| 	{ | ||||
| 		Oid		inhrelid = ((Form_pg_inherits) GETSTRUCT(tuple))->inhrelid; | ||||
| 		Oid		inhparent = ((Form_pg_inherits) GETSTRUCT(tuple))->inhparent; | ||||
| 
 | ||||
| 		if (intMember(inhrelid, relOids) && intMember(inhparent, relOids)) | ||||
| 		{ | ||||
| 			DelConstraint  *item; | ||||
| 
 | ||||
| 			item = (DelConstraint *) palloc(sizeof(DelConstraint)); | ||||
| 			item->referencer = inhrelid; | ||||
| 			item->referencee = inhparent; | ||||
| 			constraintList = lcons(item, constraintList); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	heap_endscan(scan); | ||||
| 	heap_close(inheritsrel, AccessShareLock); | ||||
| 
 | ||||
| 	return constraintList; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * TopoSortRels -- topological sort of a list of rels to delete | ||||
|  * | ||||
|  * This is a lot simpler and slower than, for example, the topological sort | ||||
|  * algorithm shown in Knuth's Volume 1.  However, we are not likely to be | ||||
|  * working with more than a few constraints, so the apparent slowness of the | ||||
|  * algorithm won't really matter. | ||||
|  */ | ||||
| static List * | ||||
| TopoSortRels(List *relOids, List *constraintList) | ||||
| { | ||||
| 	int			queue_size = length(relOids); | ||||
| 	Oid		   *rels; | ||||
| 	int		   *beforeConstraints; | ||||
| 	DelConstraint **afterConstraints; | ||||
| 	List	   *resultList = NIL; | ||||
| 	List	   *lptr; | ||||
| 	int			i, | ||||
| 				j, | ||||
| 				k, | ||||
| 				last; | ||||
| 
 | ||||
| 	/* Allocate workspace */ | ||||
| 	rels = (Oid *) palloc(queue_size * sizeof(Oid)); | ||||
| 	beforeConstraints = (int *) palloc(queue_size * sizeof(int)); | ||||
| 	afterConstraints = (DelConstraint **) | ||||
| 		palloc(queue_size * sizeof(DelConstraint*)); | ||||
| 
 | ||||
| 	/* Build an array of the target relation OIDs */ | ||||
| 	i = 0; | ||||
| 	foreach(lptr, relOids) | ||||
| 	{ | ||||
| 		rels[i++] = (Oid) lfirsti(lptr); | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Scan the constraints, and for each rel in the array, generate a | ||||
| 	 * count of the number of constraints that say it must be before | ||||
| 	 * something else, plus a list of the constraints that say it must be | ||||
| 	 * after something else. The count for the j'th rel is stored in | ||||
| 	 * beforeConstraints[j], and the head of its list in | ||||
| 	 * afterConstraints[j].  Each constraint stores its list link in | ||||
| 	 * its link field (note any constraint will be in just one list). | ||||
| 	 * The array index for the before-rel of each constraint is | ||||
| 	 * remembered in the constraint's pred field. | ||||
| 	 */ | ||||
| 	MemSet(beforeConstraints, 0, queue_size * sizeof(int)); | ||||
| 	MemSet(afterConstraints, 0, queue_size * sizeof(DelConstraint*)); | ||||
| 	foreach(lptr, constraintList) | ||||
| 	{ | ||||
| 		DelConstraint  *constraint = (DelConstraint *) lfirst(lptr); | ||||
| 		Oid			rel; | ||||
| 
 | ||||
| 		/* Find the referencer rel in the array */ | ||||
| 		rel = constraint->referencer; | ||||
| 		for (j = queue_size; --j >= 0;) | ||||
| 		{ | ||||
| 			if (rels[j] == rel) | ||||
| 				break; | ||||
| 		} | ||||
| 		Assert(j >= 0);			/* should have found a match */ | ||||
| 		/* Find the referencee rel in the array */ | ||||
| 		rel = constraint->referencee; | ||||
| 		for (k = queue_size; --k >= 0;) | ||||
| 		{ | ||||
| 			if (rels[k] == rel) | ||||
| 				break; | ||||
| 		} | ||||
| 		Assert(k >= 0);			/* should have found a match */ | ||||
| 		beforeConstraints[j]++; /* referencer must come before */ | ||||
| 		/* add this constraint to list of after-constraints for referencee */ | ||||
| 		constraint->pred = j; | ||||
| 		constraint->link = afterConstraints[k]; | ||||
| 		afterConstraints[k] = constraint; | ||||
| 	} | ||||
| 	/*--------------------
 | ||||
| 	 * Now scan the rels array backwards.	At each step, output the | ||||
| 	 * last rel that has no remaining before-constraints, and decrease | ||||
| 	 * the beforeConstraints count of each of the rels it was constrained | ||||
| 	 * against.  (This is the right order since we are building the result | ||||
| 	 * list back-to-front.) | ||||
| 	 * i = counter for number of rels left to output | ||||
| 	 * j = search index for rels[] | ||||
| 	 * dc = temp for scanning constraint list for rel j | ||||
| 	 * last = last valid index in rels (avoid redundant searches) | ||||
| 	 *-------------------- | ||||
| 	 */ | ||||
| 	last = queue_size - 1; | ||||
| 	for (i = queue_size; --i >= 0;) | ||||
| 	{ | ||||
| 		DelConstraint  *dc; | ||||
| 
 | ||||
| 		/* Find next candidate to output */ | ||||
| 		while (rels[last] == InvalidOid) | ||||
| 			last--; | ||||
| 		for (j = last; j >= 0; j--) | ||||
| 		{ | ||||
| 			if (rels[j] != InvalidOid && beforeConstraints[j] == 0) | ||||
| 				break; | ||||
| 		} | ||||
| 		/* If no available candidate, topological sort fails */ | ||||
| 		if (j < 0) | ||||
| 			elog(ERROR, "TopoSortRels: failed to find a workable deletion ordering"); | ||||
| 		/* Output candidate, and mark it done by zeroing rels[] entry */ | ||||
| 		resultList = lconsi(rels[j], resultList); | ||||
| 		rels[j] = InvalidOid; | ||||
| 		/* Update beforeConstraints counts of its predecessors */ | ||||
| 		for (dc = afterConstraints[j]; dc; dc = dc->link) | ||||
| 			beforeConstraints[dc->pred]--; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Done */ | ||||
| 	return resultList; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Callback to remove temp relations at backend exit. | ||||
|  */ | ||||
| static void | ||||
| RemoveTempRelationsCallback(void) | ||||
| { | ||||
| 	if (OidIsValid(myTempNamespace)) /* should always be true */ | ||||
| 	{ | ||||
| 		/* Need to ensure we have a usable transaction. */ | ||||
| 		AbortOutOfAnyTransaction(); | ||||
| 		StartTransactionCommand(); | ||||
| 
 | ||||
| 		RemoveTempRelations(myTempNamespace); | ||||
| 
 | ||||
| 		CommitTransactionCommand(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_namespace.c,v 1.1 2002/03/22 21:34:44 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_namespace.c,v 1.2 2002/03/31 06:26:30 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -18,7 +18,6 @@ | ||||
| #include "catalog/catname.h" | ||||
| #include "catalog/indexing.h" | ||||
| #include "catalog/pg_namespace.h" | ||||
| #include "miscadmin.h" | ||||
| #include "utils/builtins.h" | ||||
| #include "utils/syscache.h" | ||||
| 
 | ||||
| @ -28,7 +27,7 @@ | ||||
|  * --------------- | ||||
|  */ | ||||
| Oid | ||||
| NamespaceCreate(const char *nspName) | ||||
| NamespaceCreate(const char *nspName, int32 ownerSysId) | ||||
| { | ||||
| 	Relation	nspdesc; | ||||
| 	HeapTuple	tup; | ||||
| @ -57,7 +56,7 @@ NamespaceCreate(const char *nspName) | ||||
| 	} | ||||
| 	namestrcpy(&nname, nspName); | ||||
| 	values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname); | ||||
| 	values[Anum_pg_namespace_nspowner - 1] = Int32GetDatum(GetUserId()); | ||||
| 	values[Anum_pg_namespace_nspowner - 1] = Int32GetDatum(ownerSysId); | ||||
| 	nulls[Anum_pg_namespace_nspacl - 1] = 'n'; | ||||
| 
 | ||||
| 	nspdesc = heap_openr(NamespaceRelationName, RowExclusiveLock); | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.75 2002/03/29 22:10:33 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.76 2002/03/31 06:26:30 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -35,12 +35,10 @@ | ||||
| #include "utils/builtins.h" | ||||
| #include "utils/lsyscache.h" | ||||
| #include "utils/syscache.h" | ||||
| #include "utils/temprel.h" | ||||
| 
 | ||||
| 
 | ||||
| static Oid	copy_heap(Oid OIDOldHeap, char *NewName, bool istemp); | ||||
| static void copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName, | ||||
| 					   bool istemp); | ||||
| static Oid	copy_heap(Oid OIDOldHeap, char *NewName); | ||||
| static void copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName); | ||||
| static void rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex); | ||||
| 
 | ||||
| /*
 | ||||
| @ -63,7 +61,6 @@ cluster(RangeVar *oldrelation, char *oldindexname) | ||||
| 				OIDNewHeap; | ||||
| 	Relation	OldHeap, | ||||
| 				OldIndex; | ||||
| 	bool		istemp; | ||||
| 	char		NewHeapName[NAMEDATALEN]; | ||||
| 	char		NewIndexName[NAMEDATALEN]; | ||||
| 	RangeVar   *NewHeap; | ||||
| @ -76,8 +73,6 @@ cluster(RangeVar *oldrelation, char *oldindexname) | ||||
| 	OldHeap = heap_openrv(oldrelation, AccessExclusiveLock); | ||||
| 	OIDOldHeap = RelationGetRelid(OldHeap); | ||||
| 
 | ||||
| 	istemp = is_temp_rel_name(oldrelation->relname); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The index is expected to be in the same namespace as the relation. | ||||
| 	 */ | ||||
| @ -105,7 +100,7 @@ cluster(RangeVar *oldrelation, char *oldindexname) | ||||
| 	 */ | ||||
| 	snprintf(NewHeapName, NAMEDATALEN, "temp_%u", OIDOldHeap); | ||||
| 
 | ||||
| 	OIDNewHeap = copy_heap(OIDOldHeap, NewHeapName, istemp); | ||||
| 	OIDNewHeap = copy_heap(OIDOldHeap, NewHeapName); | ||||
| 
 | ||||
| 	/* We do not need CommandCounterIncrement() because copy_heap did it. */ | ||||
| 
 | ||||
| @ -120,7 +115,7 @@ cluster(RangeVar *oldrelation, char *oldindexname) | ||||
| 	/* Create new index over the tuples of the new heap. */ | ||||
| 	snprintf(NewIndexName, NAMEDATALEN, "temp_%u", OIDOldIndex); | ||||
| 
 | ||||
| 	copy_index(OIDOldIndex, OIDNewHeap, NewIndexName, istemp); | ||||
| 	copy_index(OIDOldIndex, OIDNewHeap, NewIndexName); | ||||
| 
 | ||||
| 	CommandCounterIncrement(); | ||||
| 
 | ||||
| @ -145,7 +140,7 @@ cluster(RangeVar *oldrelation, char *oldindexname) | ||||
| } | ||||
| 
 | ||||
| static Oid | ||||
| copy_heap(Oid OIDOldHeap, char *NewName, bool istemp) | ||||
| copy_heap(Oid OIDOldHeap, char *NewName) | ||||
| { | ||||
| 	TupleDesc	OldHeapDesc, | ||||
| 				tupdesc; | ||||
| @ -166,7 +161,6 @@ copy_heap(Oid OIDOldHeap, char *NewName, bool istemp) | ||||
| 										  tupdesc, | ||||
| 										  OldHeap->rd_rel->relkind, | ||||
| 										  OldHeap->rd_rel->relhasoids, | ||||
| 										  istemp, | ||||
| 										  allowSystemTableMods); | ||||
| 
 | ||||
| 	/*
 | ||||
| @ -188,7 +182,7 @@ copy_heap(Oid OIDOldHeap, char *NewName, bool istemp) | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName, bool istemp) | ||||
| copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName) | ||||
| { | ||||
| 	Relation	OldIndex, | ||||
| 				NewHeap; | ||||
| @ -209,7 +203,6 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName, bool istemp) | ||||
| 				 indexInfo, | ||||
| 				 OldIndex->rd_rel->relam, | ||||
| 				 OldIndex->rd_index->indclass, | ||||
| 				 istemp, | ||||
| 				 OldIndex->rd_index->indisprimary, | ||||
| 				 allowSystemTableMods); | ||||
| 
 | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.168 2002/03/30 01:02:41 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.169 2002/03/31 06:26:30 tgl Exp $ | ||||
|  * | ||||
|  * NOTES | ||||
|  *	  The PerformAddAttribute() code, like most of the relation | ||||
| @ -55,7 +55,7 @@ | ||||
| #include "utils/lsyscache.h" | ||||
| #include "utils/syscache.h" | ||||
| #include "utils/relcache.h" | ||||
| #include "utils/temprel.h" | ||||
| 
 | ||||
| 
 | ||||
| static void drop_default(Oid relid, int16 attnum); | ||||
| static bool needs_toast_table(Relation rel); | ||||
| @ -1344,20 +1344,27 @@ AlterTableAddConstraint(Oid myrelid, | ||||
| 					List	   *list; | ||||
| 					int			count; | ||||
| 
 | ||||
| 					if (is_temp_rel_name(fkconstraint->pktable->relname) && | ||||
| 						!is_temp_rel_name(RelationGetRelationName(rel))) | ||||
| 						elog(ERROR, "ALTER TABLE / ADD CONSTRAINT: Unable to reference temporary table from permanent table constraint."); | ||||
| 
 | ||||
| 					/*
 | ||||
| 					 * Grab an exclusive lock on the pk table, so that | ||||
| 					 * someone doesn't delete rows out from under us. | ||||
| 					 * | ||||
| 					 * XXX wouldn't a lesser lock be sufficient? | ||||
| 					 */ | ||||
| 
 | ||||
| 					pkrel = heap_openrv(fkconstraint->pktable, | ||||
| 										AccessExclusiveLock); | ||||
| 
 | ||||
| 					/*
 | ||||
| 					 * Validity checks | ||||
| 					 */ | ||||
| 					if (pkrel->rd_rel->relkind != RELKIND_RELATION) | ||||
| 						elog(ERROR, "referenced table \"%s\" not a relation", | ||||
| 							 fkconstraint->pktable->relname); | ||||
| 
 | ||||
| 					if (isTempNamespace(RelationGetNamespace(pkrel)) && | ||||
| 						!isTempNamespace(RelationGetNamespace(rel))) | ||||
| 						elog(ERROR, "ALTER TABLE / ADD CONSTRAINT: Unable to reference temporary table from permanent table constraint."); | ||||
| 
 | ||||
| 					/* Don't need pkrel open anymore, but hold lock */ | ||||
| 					heap_close(pkrel, NoLock); | ||||
| 
 | ||||
| 					/*
 | ||||
| @ -1763,8 +1770,9 @@ AlterTableCreateToastTable(Oid relOid, bool silent) | ||||
| 	toast_relid = heap_create_with_catalog(toast_relname, | ||||
| 										   PG_TOAST_NAMESPACE, | ||||
| 										   tupdesc, | ||||
| 										   RELKIND_TOASTVALUE, false, | ||||
| 										   false, true); | ||||
| 										   RELKIND_TOASTVALUE, | ||||
| 										   false, | ||||
| 										   true); | ||||
| 
 | ||||
| 	/* make the toast relation visible, else index creation will fail */ | ||||
| 	CommandCounterIncrement(); | ||||
| @ -1794,7 +1802,7 @@ AlterTableCreateToastTable(Oid relOid, bool silent) | ||||
| 
 | ||||
| 	toast_idxid = index_create(toast_relid, toast_idxname, indexInfo, | ||||
| 							   BTREE_AM_OID, classObjectId, | ||||
| 							   false, true, true); | ||||
| 							   true, true); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Update toast rel's pg_class entry to show that it has an index. The | ||||
| @ -1971,7 +1979,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt) | ||||
| 	} | ||||
| 
 | ||||
| 	/* Create the schema's namespace */ | ||||
| 	NamespaceCreate(schemaName); | ||||
| 	NamespaceCreate(schemaName, owner_userid); | ||||
| 
 | ||||
| 	/* Let commands in the schema-element-list know about the schema */ | ||||
| 	CommandCounterIncrement(); | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.94 2002/03/29 22:10:33 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.95 2002/03/31 06:26:30 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -30,7 +30,7 @@ | ||||
| #include "parser/parse_type.h" | ||||
| #include "utils/acl.h" | ||||
| #include "utils/syscache.h" | ||||
| #include "utils/temprel.h" | ||||
| 
 | ||||
| 
 | ||||
| /* ----------------
 | ||||
|  *		local stuff | ||||
| @ -157,11 +157,11 @@ DefineRelation(CreateStmt *stmt, char relkind) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	relationId = heap_create_with_catalog(relname, namespaceId, | ||||
| 	relationId = heap_create_with_catalog(relname, | ||||
| 										  namespaceId, | ||||
| 										  descriptor, | ||||
| 										  relkind, | ||||
| 										  stmt->hasoids || parentHasOids, | ||||
| 										  stmt->relation->istemp, | ||||
| 										  allowSystemTableMods); | ||||
| 
 | ||||
| 	StoreCatalogInheritance(relationId, inheritOids); | ||||
| @ -447,7 +447,7 @@ MergeAttributes(List *schema, List *supers, bool istemp, | ||||
| 			elog(ERROR, "CREATE TABLE: inherited relation \"%s\" is not a table", | ||||
| 				 parent->relname); | ||||
| 		/* Permanent rels cannot inherit from temporary ones */ | ||||
| 		if (!istemp && is_temp_rel_name(parent->relname)) | ||||
| 		if (!istemp && isTempNamespace(RelationGetNamespace(relation))) | ||||
| 			elog(ERROR, "CREATE TABLE: cannot inherit from temp relation \"%s\"", | ||||
| 				 parent->relname); | ||||
| 
 | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.65 2002/03/26 19:15:41 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.66 2002/03/31 06:26:30 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -33,7 +33,6 @@ | ||||
| #include "utils/fmgroids.h" | ||||
| #include "utils/lsyscache.h" | ||||
| #include "utils/syscache.h" | ||||
| #include "utils/temprel.h" | ||||
| 
 | ||||
| 
 | ||||
| #define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args != NIL) | ||||
| @ -74,7 +73,6 @@ DefineIndex(RangeVar *heapRelation, | ||||
| 	Oid		   *classObjectId; | ||||
| 	Oid			accessMethodId; | ||||
| 	Oid			relationId; | ||||
| 	bool		istemp = is_temp_rel_name(heapRelation->relname); | ||||
| 	Relation	rel; | ||||
| 	HeapTuple	tuple; | ||||
| 	Form_pg_am	accessMethodForm; | ||||
| @ -191,7 +189,7 @@ DefineIndex(RangeVar *heapRelation, | ||||
| 
 | ||||
| 	index_create(relationId, indexRelationName, | ||||
| 				 indexInfo, accessMethodId, classObjectId, | ||||
| 				 istemp, primary, allowSystemTableMods); | ||||
| 				 primary, allowSystemTableMods); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * We update the relation's pg_class tuple even if it already has | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.66 2002/03/29 19:06:07 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.67 2002/03/31 06:26:30 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -39,7 +39,6 @@ | ||||
| #include "utils/lsyscache.h" | ||||
| #include "utils/relcache.h" | ||||
| #include "utils/syscache.h" | ||||
| #include "utils/temprel.h" | ||||
| 
 | ||||
| 
 | ||||
| #define RI_TRIGGER_PK	1		/* is a trigger on the PK relation */ | ||||
| @ -270,13 +269,6 @@ renamerel(const RangeVar *relation, const char *newrelname) | ||||
| 		elog(ERROR, "renamerel: Illegal class name: \"%s\" -- pg_ is reserved for system catalogs", | ||||
| 			 newrelname); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Check for renaming a temp table, which only requires altering the | ||||
| 	 * temp-table mapping, not the underlying table. | ||||
| 	 */ | ||||
| 	if (rename_temp_relation(relation->relname, newrelname)) | ||||
| 		return;					/* all done... */ | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Grab an exclusive lock on the target table or index, which we will | ||||
| 	 * NOT release until end of transaction. | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.109 2002/03/29 22:10:33 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.110 2002/03/31 06:26:30 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -471,7 +471,7 @@ RelationRemoveTriggers(Relation rel) | ||||
| 		Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tup); | ||||
| 
 | ||||
| 		elog(NOTICE, "DROP TABLE implicitly drops referential integrity trigger from table \"%s\"", | ||||
| 			 get_temp_rel_by_physicalname(get_rel_name(pg_trigger->tgrelid))); | ||||
| 			 get_rel_name(pg_trigger->tgrelid)); | ||||
| 
 | ||||
| 		DropTrigger(pg_trigger->tgrelid, NameStr(pg_trigger->tgname)); | ||||
| 
 | ||||
|  | ||||
| @ -13,7 +13,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.219 2002/03/21 23:27:22 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.220 2002/03/31 06:26:30 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -42,8 +42,6 @@ | ||||
| #include "utils/inval.h" | ||||
| #include "utils/relcache.h" | ||||
| #include "utils/syscache.h" | ||||
| #include "utils/temprel.h" | ||||
| 
 | ||||
| #include "pgstat.h" | ||||
| 
 | ||||
| 
 | ||||
| @ -351,16 +349,9 @@ getrels(Name VacRelP, const char *stmttype) | ||||
| 		 * we could use the cache here, but it is clearer to use scankeys | ||||
| 		 * for both vacuum cases, bjm 2000/01/19 | ||||
| 		 */ | ||||
| 		char	   *nontemp_relname; | ||||
| 
 | ||||
| 		/* We must re-map temp table names bjm 2000-04-06 */ | ||||
| 		nontemp_relname = get_temp_rel_by_username(NameStr(*VacRelP)); | ||||
| 		if (nontemp_relname == NULL) | ||||
| 			nontemp_relname = NameStr(*VacRelP); | ||||
| 
 | ||||
| 		ScanKeyEntryInitialize(&key, 0x0, Anum_pg_class_relname, | ||||
| 							   F_NAMEEQ, | ||||
| 							   PointerGetDatum(nontemp_relname)); | ||||
| 							   PointerGetDatum(NameStr(*VacRelP))); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
|  | ||||
| @ -27,7 +27,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.155 2002/03/26 19:15:54 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.156 2002/03/31 06:26:31 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -724,8 +724,8 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate) | ||||
| 					heap_create_with_catalog(intoName, | ||||
| 											 namespaceId, | ||||
| 											 tupdesc, | ||||
| 											 RELKIND_RELATION, true, | ||||
| 											 parseTree->into->istemp, | ||||
| 											 RELKIND_RELATION, | ||||
| 											 true, | ||||
| 											 allowSystemTableMods); | ||||
| 
 | ||||
| 				FreeTupleDesc(tupdesc); | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.224 2002/03/29 19:06:10 tgl Exp $ | ||||
|  *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.225 2002/03/31 06:26:31 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -37,8 +37,6 @@ | ||||
| #include "utils/fmgroids.h" | ||||
| #include "utils/relcache.h" | ||||
| #include "utils/syscache.h" | ||||
| #include "utils/temprel.h" | ||||
| 
 | ||||
| #ifdef MULTIBYTE | ||||
| #include "mb/pg_wchar.h" | ||||
| #endif | ||||
| @ -2553,7 +2551,6 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt, | ||||
| 			cxt.stmtType = "ALTER TABLE"; | ||||
| 			cxt.relation = stmt->relation; | ||||
| 			cxt.inhRelations = NIL; | ||||
| 			cxt.relation->istemp = is_temp_rel_name(stmt->relation->relname); | ||||
| 			cxt.relOid = RangeVarGetRelid(stmt->relation, false); | ||||
| 			cxt.hasoids = SearchSysCacheExists(ATTNUM, | ||||
| 											ObjectIdGetDatum(cxt.relOid), | ||||
| @ -2583,7 +2580,6 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt, | ||||
| 			cxt.stmtType = "ALTER TABLE"; | ||||
| 			cxt.relation = stmt->relation; | ||||
| 			cxt.inhRelations = NIL; | ||||
| 			cxt.relation->istemp = is_temp_rel_name(stmt->relation->relname); | ||||
| 			cxt.relOid = RangeVarGetRelid(stmt->relation, false); | ||||
| 			cxt.hasoids = SearchSysCacheExists(ATTNUM, | ||||
| 											ObjectIdGetDatum(cxt.relOid), | ||||
|  | ||||
| @ -10,7 +10,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.142 2002/03/29 22:10:33 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.143 2002/03/31 06:26:31 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -49,7 +49,6 @@ | ||||
| #include "utils/acl.h" | ||||
| #include "utils/lsyscache.h" | ||||
| #include "utils/syscache.h" | ||||
| #include "utils/temprel.h" | ||||
| #include "access/xlog.h" | ||||
| 
 | ||||
| /*
 | ||||
| @ -128,8 +127,7 @@ CheckDropPermissions(RangeVar *rel, char rightkind) | ||||
| 		elog(ERROR, "you do not own %s \"%s\"", | ||||
| 			 rentry->name, rel->relname); | ||||
| 
 | ||||
| 	if (!allowSystemTableMods && IsSystemRelationName(rel->relname) && | ||||
| 		!is_temp_relname(rel->relname)) | ||||
| 	if (!allowSystemTableMods && IsSystemRelationName(rel->relname)) | ||||
| 		elog(ERROR, "%s \"%s\" is a system %s", | ||||
| 			 rentry->name, rel->relname, rentry->name); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										4
									
								
								src/backend/utils/cache/Makefile
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								src/backend/utils/cache/Makefile
									
									
									
									
										vendored
									
									
								
							| @ -4,7 +4,7 @@ | ||||
| #    Makefile for utils/cache
 | ||||
| #
 | ||||
| # IDENTIFICATION
 | ||||
| #    $Header: /cvsroot/pgsql/src/backend/utils/cache/Makefile,v 1.15 2001/10/06 23:21:44 tgl Exp $
 | ||||
| #    $Header: /cvsroot/pgsql/src/backend/utils/cache/Makefile,v 1.16 2002/03/31 06:26:31 tgl Exp $
 | ||||
| #
 | ||||
| #-------------------------------------------------------------------------
 | ||||
| 
 | ||||
| @ -13,7 +13,7 @@ top_builddir = ../../../.. | ||||
| include $(top_builddir)/src/Makefile.global | ||||
| 
 | ||||
| OBJS = catcache.o inval.o relcache.o syscache.o lsyscache.o \
 | ||||
| 	fcache.o temprel.o | ||||
| 	fcache.o | ||||
| 
 | ||||
| all: SUBSYS.o | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										16
									
								
								src/backend/utils/cache/relcache.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								src/backend/utils/cache/relcache.c
									
									
									
									
										vendored
									
									
								
							| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.158 2002/03/26 19:16:10 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.159 2002/03/31 06:26:31 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -60,7 +60,6 @@ | ||||
| #include "utils/lsyscache.h" | ||||
| #include "utils/relcache.h" | ||||
| #include "utils/syscache.h" | ||||
| #include "utils/temprel.h" | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
| @ -186,7 +185,7 @@ do { \ | ||||
| 	nodentry->reldesc = RELATION; \ | ||||
| 	if (RelationGetNamespace(RELATION) == PG_CATALOG_NAMESPACE) \ | ||||
| 	{ \ | ||||
| 		char *relname = RelationGetPhysicalRelationName(RELATION); \ | ||||
| 		char *relname = RelationGetRelationName(RELATION); \ | ||||
| 		RelNameCacheEnt *namehentry; \ | ||||
| 		namehentry = (RelNameCacheEnt*)hash_search(RelationSysNameCache, \ | ||||
| 												   relname, \ | ||||
| @ -247,7 +246,7 @@ do { \ | ||||
| 		elog(WARNING, "trying to delete a reldesc that does not exist."); \ | ||||
| 	if (RelationGetNamespace(RELATION) == PG_CATALOG_NAMESPACE) \ | ||||
| 	{ \ | ||||
| 		char *relname = RelationGetPhysicalRelationName(RELATION); \ | ||||
| 		char *relname = RelationGetRelationName(RELATION); \ | ||||
| 		RelNameCacheEnt *namehentry; \ | ||||
| 		namehentry = (RelNameCacheEnt*)hash_search(RelationSysNameCache, \ | ||||
| 												   relname, \ | ||||
| @ -1571,18 +1570,9 @@ RelationIdGetRelation(Oid relationId) | ||||
| Relation | ||||
| RelationSysNameGetRelation(const char *relationName) | ||||
| { | ||||
| 	char	   *temprelname; | ||||
| 	Relation	rd; | ||||
| 	RelationBuildDescInfo buildinfo; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * if caller is looking for a temp relation, substitute its real name; | ||||
| 	 * we only index temp rels by their real names. | ||||
| 	 */ | ||||
| 	temprelname = get_temp_rel_by_username(relationName); | ||||
| 	if (temprelname != NULL) | ||||
| 		relationName = temprelname; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * first try and get a reldesc from the cache | ||||
| 	 */ | ||||
|  | ||||
							
								
								
									
										27
									
								
								src/backend/utils/cache/syscache.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								src/backend/utils/cache/syscache.c
									
									
									
									
										vendored
									
									
								
							| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.71 2002/03/29 19:06:15 tgl Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.72 2002/03/31 06:26:32 tgl Exp $ | ||||
|  * | ||||
|  * NOTES | ||||
|  *	  These routines allow the parser/planner/executor to perform | ||||
| @ -42,7 +42,6 @@ | ||||
| #include "catalog/pg_type.h" | ||||
| #include "utils/catcache.h" | ||||
| #include "utils/syscache.h" | ||||
| #include "utils/temprel.h" | ||||
| #include "miscadmin.h" | ||||
| 
 | ||||
| 
 | ||||
| @ -500,29 +499,9 @@ SearchSysCache(int cacheId, | ||||
| 			   Datum key3, | ||||
| 			   Datum key4) | ||||
| { | ||||
| 	if (cacheId < 0 || cacheId >= SysCacheSize) | ||||
| 	{ | ||||
| 	if (cacheId < 0 || cacheId >= SysCacheSize || | ||||
| 		! PointerIsValid(SysCache[cacheId])) | ||||
| 		elog(ERROR, "SearchSysCache: Bad cache id %d", cacheId); | ||||
| 		return (HeapTuple) NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	Assert(PointerIsValid(SysCache[cacheId])); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If someone tries to look up a relname, translate temp relation | ||||
| 	 * names to real names.  Less obviously, apply the same translation to | ||||
| 	 * type names, so that the type tuple of a temp table will be found | ||||
| 	 * when sought.  This is a kluge ... temp table substitution should be | ||||
| 	 * happening at a higher level ... | ||||
| 	 */ | ||||
| 	if (cacheId == RELNAMENSP || cacheId == TYPENAMENSP) | ||||
| 	{ | ||||
| 		char	   *nontemp_relname; | ||||
| 
 | ||||
| 		nontemp_relname = get_temp_rel_by_username(DatumGetCString(key1)); | ||||
| 		if (nontemp_relname != NULL) | ||||
| 			key1 = CStringGetDatum(nontemp_relname); | ||||
| 	} | ||||
| 
 | ||||
| 	return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4); | ||||
| } | ||||
|  | ||||
							
								
								
									
										335
									
								
								src/backend/utils/cache/temprel.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										335
									
								
								src/backend/utils/cache/temprel.c
									
									
									
									
										vendored
									
									
								
							| @ -1,335 +0,0 @@ | ||||
| /*-------------------------------------------------------------------------
 | ||||
|  * | ||||
|  * temprel.c | ||||
|  *	  POSTGRES temporary relation handling | ||||
|  * | ||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.36 2002/03/29 19:06:16 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| 
 | ||||
| /*
 | ||||
|  * This implements temp tables by modifying the relname cache lookups | ||||
|  * of pg_class. | ||||
|  * | ||||
|  * When a temp table is created, normal entries are made for it in pg_class, | ||||
|  * pg_type, etc using a unique "physical" relation name.  We also make an | ||||
|  * entry in the temp table list maintained by this module.	Subsequently, | ||||
|  * relname lookups are filtered through the temp table list, and attempts | ||||
|  * to look up a temp table name are changed to look up the physical name. | ||||
|  * This allows temp table names to mask a regular table of the same name | ||||
|  * for the duration of the session.  The temp table list is also used | ||||
|  * to drop the underlying physical relations at session shutdown. | ||||
|  */ | ||||
| 
 | ||||
| #include "postgres.h" | ||||
| 
 | ||||
| #include <sys/types.h> | ||||
| 
 | ||||
| #include "catalog/heap.h" | ||||
| #include "catalog/index.h" | ||||
| #include "miscadmin.h" | ||||
| #include "utils/temprel.h" | ||||
| 
 | ||||
| 
 | ||||
| /* ----------------
 | ||||
|  *		global variables | ||||
|  * ---------------- | ||||
|  */ | ||||
| 
 | ||||
| static List *temp_rels = NIL; | ||||
| 
 | ||||
| typedef struct TempTable | ||||
| { | ||||
| 	NameData	user_relname;	/* logical name of temp table */ | ||||
| 	NameData	relname;		/* underlying unique name */ | ||||
| 	Oid			relid;			/* needed properties of rel */ | ||||
| 	char		relkind; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If this entry was created during this xact, it should be deleted at | ||||
| 	 * xact abort.	Conversely, if this entry was deleted during this | ||||
| 	 * xact, it should be removed at xact commit.  We leave deleted | ||||
| 	 * entries in the list until commit so that we can roll back if needed | ||||
| 	 * --- but we ignore them for purposes of lookup! | ||||
| 	 */ | ||||
| 	bool		created_in_cur_xact; | ||||
| 	bool		deleted_in_cur_xact; | ||||
| } TempTable; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * Create a temp-relation list entry given the logical temp table name | ||||
|  * and the already-created pg_class tuple for the underlying relation. | ||||
|  * | ||||
|  * NB: we assume a check has already been made for a duplicate logical name. | ||||
|  */ | ||||
| void | ||||
| create_temp_relation(const char *relname, HeapTuple pg_class_tuple) | ||||
| { | ||||
| 	Form_pg_class pg_class_form = (Form_pg_class) GETSTRUCT(pg_class_tuple); | ||||
| 	MemoryContext oldcxt; | ||||
| 	TempTable  *temp_rel; | ||||
| 
 | ||||
| 	oldcxt = MemoryContextSwitchTo(CacheMemoryContext); | ||||
| 
 | ||||
| 	temp_rel = (TempTable *) palloc(sizeof(TempTable)); | ||||
| 
 | ||||
| 	StrNCpy(NameStr(temp_rel->user_relname), relname, | ||||
| 			NAMEDATALEN); | ||||
| 	StrNCpy(NameStr(temp_rel->relname), NameStr(pg_class_form->relname), | ||||
| 			NAMEDATALEN); | ||||
| 	temp_rel->relid = pg_class_tuple->t_data->t_oid; | ||||
| 	temp_rel->relkind = pg_class_form->relkind; | ||||
| 	temp_rel->created_in_cur_xact = true; | ||||
| 	temp_rel->deleted_in_cur_xact = false; | ||||
| 
 | ||||
| 	temp_rels = lcons(temp_rel, temp_rels); | ||||
| 
 | ||||
| 	MemoryContextSwitchTo(oldcxt); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Remove a temp relation map entry (part of DROP TABLE on a temp table). | ||||
|  * We don't actually remove the entry, just mark it dead. | ||||
|  * | ||||
|  * We don't have the relname for indexes, so we just pass the oid. | ||||
|  */ | ||||
| void | ||||
| remove_temp_rel_by_relid(Oid relid) | ||||
| { | ||||
| 	List	   *l; | ||||
| 
 | ||||
| 	foreach(l, temp_rels) | ||||
| 	{ | ||||
| 		TempTable  *temp_rel = (TempTable *) lfirst(l); | ||||
| 
 | ||||
| 		if (temp_rel->relid == relid) | ||||
| 			temp_rel->deleted_in_cur_xact = true; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Keep scanning 'cause there could be multiple matches; see | ||||
| 		 * RENAME | ||||
| 		 */ | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * To implement ALTER TABLE RENAME on a temp table, we shouldn't touch | ||||
|  * the underlying physical table at all, just change the map entry! | ||||
|  * | ||||
|  * This routine is invoked early in ALTER TABLE RENAME to check for | ||||
|  * the temp-table case.  If oldname matches a temp table name, change | ||||
|  * the mapping to the new logical name and return TRUE (or elog if | ||||
|  * there is a conflict with another temp table name).  If there is | ||||
|  * no match, return FALSE indicating that normal rename should proceed. | ||||
|  * | ||||
|  * We also reject an attempt to rename a normal table to a name in use | ||||
|  * as a temp table name.  That would fail later on anyway when rename.c | ||||
|  * looks for a rename conflict, but we can give a more specific error | ||||
|  * message for the problem here. | ||||
|  * | ||||
|  * It might seem that we need to check for attempts to rename the physical | ||||
|  * file underlying a temp table, but that'll be rejected anyway because | ||||
|  * pg_tempXXX looks like a system table name. | ||||
|  */ | ||||
| bool | ||||
| rename_temp_relation(const char *oldname, | ||||
| 					 const char *newname) | ||||
| { | ||||
| 	List	   *l; | ||||
| 
 | ||||
| 	foreach(l, temp_rels) | ||||
| 	{ | ||||
| 		TempTable  *temp_rel = (TempTable *) lfirst(l); | ||||
| 		MemoryContext oldcxt; | ||||
| 		TempTable  *new_temp_rel; | ||||
| 
 | ||||
| 		if (temp_rel->deleted_in_cur_xact) | ||||
| 			continue;			/* ignore it if logically deleted */ | ||||
| 
 | ||||
| 		if (strcmp(NameStr(temp_rel->user_relname), oldname) != 0) | ||||
| 			continue;			/* ignore non-matching entries */ | ||||
| 
 | ||||
| 		/* We are renaming a temp table --- is it OK to do so? */ | ||||
| 		if (is_temp_rel_name(newname)) | ||||
| 			elog(ERROR, "Cannot rename temp table \"%s\": temp table \"%s\" already exists", | ||||
| 				 oldname, newname); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Create a new mapping entry and mark the old one deleted in this | ||||
| 		 * xact.  One of these entries will be deleted at xact end. | ||||
| 		 * | ||||
| 		 * NOTE: the new mapping entry is inserted into the list just after | ||||
| 		 * the old one.  We could alternatively insert it before the old | ||||
| 		 * one, but that'd take more code.  It does need to be in one spot | ||||
| 		 * or the other, to ensure that deletion of temp rels happens in | ||||
| 		 * the right order during remove_all_temp_relations(). | ||||
| 		 */ | ||||
| 		oldcxt = MemoryContextSwitchTo(CacheMemoryContext); | ||||
| 
 | ||||
| 		new_temp_rel = (TempTable *) palloc(sizeof(TempTable)); | ||||
| 		memcpy(new_temp_rel, temp_rel, sizeof(TempTable)); | ||||
| 
 | ||||
| 		StrNCpy(NameStr(new_temp_rel->user_relname), newname, NAMEDATALEN); | ||||
| 		new_temp_rel->created_in_cur_xact = true; | ||||
| 
 | ||||
| 		lnext(l) = lcons(new_temp_rel, lnext(l)); | ||||
| 
 | ||||
| 		temp_rel->deleted_in_cur_xact = true; | ||||
| 
 | ||||
| 		MemoryContextSwitchTo(oldcxt); | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Old name does not match any temp table name, what about new? */ | ||||
| 	if (is_temp_rel_name(newname)) | ||||
| 		elog(ERROR, "Cannot rename \"%s\" to \"%s\": a temp table by that name already exists", | ||||
| 			 oldname, newname); | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * Remove underlying relations for all temp rels at backend shutdown. | ||||
|  */ | ||||
| void | ||||
| remove_all_temp_relations(void) | ||||
| { | ||||
| 	List	   *l; | ||||
| 
 | ||||
| 	/* skip xact start overhead if nothing to do */ | ||||
| 	if (temp_rels == NIL) | ||||
| 		return; | ||||
| 
 | ||||
| 	AbortOutOfAnyTransaction(); | ||||
| 	StartTransactionCommand(); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Scan the list and delete all entries not already deleted. We need | ||||
| 	 * not worry about list entries getting deleted from under us, because | ||||
| 	 * remove_temp_rel_by_relid() doesn't remove entries, only mark them | ||||
| 	 * dead.  Note that entries will be deleted in reverse order of | ||||
| 	 * creation --- that's critical for cases involving inheritance. | ||||
| 	 */ | ||||
| 	foreach(l, temp_rels) | ||||
| 	{ | ||||
| 		TempTable  *temp_rel = (TempTable *) lfirst(l); | ||||
| 
 | ||||
| 		if (temp_rel->deleted_in_cur_xact) | ||||
| 			continue;			/* ignore it if deleted already */ | ||||
| 
 | ||||
| 		if (temp_rel->relkind != RELKIND_INDEX) | ||||
| 			heap_drop_with_catalog(temp_rel->relid, allowSystemTableMods); | ||||
| 		else | ||||
| 			index_drop(temp_rel->relid); | ||||
| 		/* advance cmd counter to make catalog changes visible */ | ||||
| 		CommandCounterIncrement(); | ||||
| 	} | ||||
| 
 | ||||
| 	CommitTransactionCommand(); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Clean up temprel mapping entries during transaction commit or abort. | ||||
|  * | ||||
|  * During commit, remove entries that were deleted during this transaction; | ||||
|  * during abort, remove those created during this transaction. | ||||
|  * | ||||
|  * We do not need to worry about removing the underlying physical relation; | ||||
|  * that's someone else's job. | ||||
|  */ | ||||
| void | ||||
| AtEOXact_temp_relations(bool isCommit) | ||||
| { | ||||
| 	List	   *l, | ||||
| 			   *prev; | ||||
| 
 | ||||
| 	prev = NIL; | ||||
| 	l = temp_rels; | ||||
| 	while (l != NIL) | ||||
| 	{ | ||||
| 		TempTable  *temp_rel = (TempTable *) lfirst(l); | ||||
| 
 | ||||
| 		if (isCommit ? temp_rel->deleted_in_cur_xact : | ||||
| 			temp_rel->created_in_cur_xact) | ||||
| 		{ | ||||
| 			/* This entry must be removed */ | ||||
| 			if (prev != NIL) | ||||
| 			{ | ||||
| 				lnext(prev) = lnext(l); | ||||
| 				pfree(l); | ||||
| 				l = lnext(prev); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				temp_rels = lnext(l); | ||||
| 				pfree(l); | ||||
| 				l = temp_rels; | ||||
| 			} | ||||
| 			pfree(temp_rel); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			/* This entry must be preserved */ | ||||
| 			temp_rel->created_in_cur_xact = false; | ||||
| 			temp_rel->deleted_in_cur_xact = false; | ||||
| 			prev = l; | ||||
| 			l = lnext(l); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * Map user name to physical name --- returns NULL if no entry. | ||||
|  * | ||||
|  * This also supports testing whether a name is a temp table name; | ||||
|  * see is_temp_rel_name() macro. | ||||
|  */ | ||||
| char * | ||||
| get_temp_rel_by_username(const char *user_relname) | ||||
| { | ||||
| 	List	   *l; | ||||
| 
 | ||||
| 	foreach(l, temp_rels) | ||||
| 	{ | ||||
| 		TempTable  *temp_rel = (TempTable *) lfirst(l); | ||||
| 
 | ||||
| 		if (temp_rel->deleted_in_cur_xact) | ||||
| 			continue;			/* ignore it if logically deleted */ | ||||
| 
 | ||||
| 		if (strcmp(NameStr(temp_rel->user_relname), user_relname) == 0) | ||||
| 			return NameStr(temp_rel->relname); | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Map physical name to user name --- returns pstrdup'd input if no match. | ||||
|  */ | ||||
| char * | ||||
| get_temp_rel_by_physicalname(const char *relname) | ||||
| { | ||||
| 	List	   *l; | ||||
| 
 | ||||
| 	foreach(l, temp_rels) | ||||
| 	{ | ||||
| 		TempTable  *temp_rel = (TempTable *) lfirst(l); | ||||
| 
 | ||||
| 		if (temp_rel->deleted_in_cur_xact) | ||||
| 			continue;			/* ignore it if logically deleted */ | ||||
| 
 | ||||
| 		if (strcmp(NameStr(temp_rel->relname), relname) == 0) | ||||
| 			return NameStr(temp_rel->user_relname); | ||||
| 	} | ||||
| 	/* needed for bootstrapping temp tables */ | ||||
| 	return pstrdup(relname); | ||||
| } | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.100 2002/03/06 06:10:25 momjian Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.101 2002/03/31 06:26:32 tgl Exp $ | ||||
|  * | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
| @ -39,7 +39,6 @@ | ||||
| #include "utils/portal.h" | ||||
| #include "utils/relcache.h" | ||||
| #include "utils/syscache.h" | ||||
| #include "utils/temprel.h" | ||||
| 
 | ||||
| 
 | ||||
| static void ReverifyMyDatabase(const char *name); | ||||
| @ -386,20 +385,13 @@ InitPostgres(const char *dbname, const char *username) | ||||
| 	RelationCacheInitializePhase3(); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Set up process-exit callbacks to remove temp relations and then do | ||||
| 	 * pre-shutdown cleanup.  This should be last because we want | ||||
| 	 * shmem_exit to call these routines before the exit callbacks that | ||||
| 	 * are registered by buffer manager, lock manager, etc.  We need to | ||||
| 	 * run this code before we close down database access! | ||||
| 	 * Set up process-exit callback to do pre-shutdown cleanup.  This should | ||||
| 	 * be last because we want shmem_exit to call this routine before the exit | ||||
| 	 * callbacks that are registered by buffer manager, lock manager, etc. | ||||
| 	 * We need to run this code before we close down database access! | ||||
| 	 */ | ||||
| 	on_shmem_exit(ShutdownPostgres, 0); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * because callbacks are called in reverse order, this gets done | ||||
| 	 * first: | ||||
| 	 */ | ||||
| 	on_shmem_exit(remove_all_temp_relations, 0); | ||||
| 
 | ||||
| 	/* close the transaction we started above */ | ||||
| 	if (!bootstrap) | ||||
| 		CommitTransactionCommand(); | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $Id: heap.h,v 1.48 2002/03/29 19:06:17 tgl Exp $ | ||||
|  * $Id: heap.h,v 1.49 2002/03/31 06:26:32 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -27,16 +27,19 @@ typedef struct RawColumnDefault | ||||
| 								 * tree) */ | ||||
| } RawColumnDefault; | ||||
| 
 | ||||
| extern Relation heap_create(char *relname, Oid relnamespace, | ||||
| extern Relation heap_create(const char *relname, | ||||
| 			Oid relnamespace, | ||||
| 			TupleDesc tupDesc, | ||||
| 			bool istemp, bool storage_create, | ||||
| 			bool storage_create, | ||||
| 			bool allow_system_table_mods); | ||||
| 
 | ||||
| extern void heap_storage_create(Relation rel); | ||||
| 
 | ||||
| extern Oid heap_create_with_catalog(char *relname, Oid relnamespace, | ||||
| extern Oid heap_create_with_catalog(const char *relname, | ||||
| 						 Oid relnamespace, | ||||
| 						 TupleDesc tupdesc, | ||||
| 						 char relkind, bool relhasoids, bool istemp, | ||||
| 						 char relkind, | ||||
| 						 bool relhasoids, | ||||
| 						 bool allow_system_table_mods); | ||||
| 
 | ||||
| extern void heap_drop_with_catalog(Oid rid, bool allow_system_table_mods); | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $Id: index.h,v 1.46 2002/03/26 19:16:25 tgl Exp $ | ||||
|  * $Id: index.h,v 1.47 2002/03/31 06:26:32 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -30,11 +30,10 @@ typedef void (*IndexBuildCallback) (Relation index, | ||||
| 
 | ||||
| 
 | ||||
| extern Oid index_create(Oid heapRelationId, | ||||
| 			 char *indexRelationName, | ||||
| 			 const char *indexRelationName, | ||||
| 			 IndexInfo *indexInfo, | ||||
| 			 Oid accessMethodObjectId, | ||||
| 			 Oid *classObjectId, | ||||
| 			 bool istemp, | ||||
| 			 bool primary, | ||||
| 			 bool allow_system_table_mods); | ||||
| 
 | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $Id: namespace.h,v 1.3 2002/03/30 01:02:42 tgl Exp $ | ||||
|  * $Id: namespace.h,v 1.4 2002/03/31 06:26:32 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -29,4 +29,6 @@ extern Oid	QualifiedNameGetCreationNamespace(List *names, char **objname_p); | ||||
| 
 | ||||
| extern RangeVar *makeRangeVarFromNameList(List *names); | ||||
| 
 | ||||
| extern bool isTempNamespace(Oid namespaceId); | ||||
| 
 | ||||
| #endif   /* NAMESPACE_H */ | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $Id: pg_namespace.h,v 1.2 2002/03/30 01:02:42 tgl Exp $ | ||||
|  * $Id: pg_namespace.h,v 1.3 2002/03/31 06:26:32 tgl Exp $ | ||||
|  * | ||||
|  * NOTES | ||||
|  *	  the genbki.sh script reads this file and generates .bki | ||||
| @ -69,7 +69,7 @@ typedef FormData_pg_namespace *Form_pg_namespace; | ||||
| DATA(insert OID = 11 ( "pg_catalog" PGUID "{=r}" )); | ||||
| DESCR("System catalog namespace"); | ||||
| #define PG_CATALOG_NAMESPACE 11 | ||||
| DATA(insert OID = 99 ( "pg_toast" PGUID "{=r}" )); | ||||
| DATA(insert OID = 99 ( "pg_toast" PGUID "{=}" )); | ||||
| DESCR("Reserved namespace for TOAST tables"); | ||||
| #define PG_TOAST_NAMESPACE 99 | ||||
| DATA(insert OID = 2071 ( "pg_public" PGUID "{=rw}" )); | ||||
| @ -80,6 +80,6 @@ DESCR("Standard public namespace"); | ||||
| /*
 | ||||
|  * prototypes for functions in pg_namespace.c | ||||
|  */ | ||||
| extern Oid	NamespaceCreate(const char *nspName); | ||||
| extern Oid	NamespaceCreate(const char *nspName, int32 ownerSysId); | ||||
| 
 | ||||
| #endif   /* PG_NAMESPACE_H */ | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $Id: rel.h,v 1.57 2002/03/26 19:16:58 tgl Exp $ | ||||
|  * $Id: rel.h,v 1.58 2002/03/31 06:26:32 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -238,49 +238,15 @@ typedef Relation *RelationPtr; | ||||
|  */ | ||||
| #define RelationGetIndexStrategy(relation) ((relation)->rd_istrat) | ||||
| 
 | ||||
| /*
 | ||||
|  * Handle temp relations | ||||
|  */ | ||||
| #define PG_TEMP_REL_PREFIX "pg_temp" | ||||
| #define PG_TEMP_REL_PREFIX_LEN 7 | ||||
| 
 | ||||
| #define is_temp_relname(relname) \ | ||||
| 		(strncmp(relname, PG_TEMP_REL_PREFIX, PG_TEMP_REL_PREFIX_LEN) == 0) | ||||
| 
 | ||||
| /*
 | ||||
|  * RelationGetPhysicalRelationName | ||||
|  * | ||||
|  *	  Returns the rel's physical name, ie, the name appearing in pg_class. | ||||
|  * | ||||
|  * While this name is unique across all rels in the database, it is not | ||||
|  * necessarily useful for accessing the rel, since a temp table of the | ||||
|  * same name might mask the rel.  It is useful mainly for determining if | ||||
|  * the rel is a shared system rel or not. | ||||
|  * | ||||
|  * The macro is rather unfortunately named, since the pg_class name no longer | ||||
|  * has anything to do with the file name used for physical storage of the rel. | ||||
|  */ | ||||
| #define RelationGetPhysicalRelationName(relation) \ | ||||
| 	(NameStr((relation)->rd_rel->relname)) | ||||
| 
 | ||||
| /*
 | ||||
|  * RelationGetRelationName | ||||
|  * | ||||
|  *	  Returns the relation's logical name (as seen by the user). | ||||
|  *	  Returns the rel's name. | ||||
|  * | ||||
|  * If the rel is a temp rel, the temp name will be returned.  Therefore, | ||||
|  * this name is not unique.  But it is the name to use in heap_openr(), | ||||
|  * for example. | ||||
|  * Note that the name is only unique within the containing namespace. | ||||
|  */ | ||||
| #define RelationGetRelationName(relation) \ | ||||
| (\ | ||||
| 	is_temp_relname(RelationGetPhysicalRelationName(relation)) \ | ||||
| 	? \ | ||||
| 		get_temp_rel_by_physicalname( \ | ||||
| 			RelationGetPhysicalRelationName(relation)) \ | ||||
| 	: \ | ||||
| 		RelationGetPhysicalRelationName(relation) \ | ||||
| ) | ||||
| 	(NameStr((relation)->rd_rel->relname)) | ||||
| 
 | ||||
| /*
 | ||||
|  * RelationGetNamespace | ||||
| @ -290,7 +256,4 @@ typedef Relation *RelationPtr; | ||||
| #define RelationGetNamespace(relation) \ | ||||
| 	((relation)->rd_rel->relnamespace) | ||||
| 
 | ||||
| /* added to prevent circular dependency.  bjm 1999/11/15 */ | ||||
| extern char *get_temp_rel_by_physicalname(const char *relname); | ||||
| 
 | ||||
| #endif   /* REL_H */ | ||||
|  | ||||
| @ -1,33 +0,0 @@ | ||||
| /*-------------------------------------------------------------------------
 | ||||
|  * | ||||
|  * temprel.h | ||||
|  *	  Temporary relation functions | ||||
|  * | ||||
|  * | ||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $Id: temprel.h,v 1.20 2001/11/05 17:46:36 momjian Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| #ifndef TEMPREL_H | ||||
| #define TEMPREL_H | ||||
| 
 | ||||
| #include "access/htup.h" | ||||
| 
 | ||||
| extern void create_temp_relation(const char *relname, | ||||
| 					 HeapTuple pg_class_tuple); | ||||
| extern void remove_temp_rel_by_relid(Oid relid); | ||||
| extern bool rename_temp_relation(const char *oldname, | ||||
| 					 const char *newname); | ||||
| 
 | ||||
| extern void remove_all_temp_relations(void); | ||||
| extern void AtEOXact_temp_relations(bool isCommit); | ||||
| 
 | ||||
| extern char *get_temp_rel_by_username(const char *user_relname); | ||||
| extern char *get_temp_rel_by_physicalname(const char *relname); | ||||
| 
 | ||||
| #define is_temp_rel_name(relname) (get_temp_rel_by_username(relname) != NULL) | ||||
| 
 | ||||
| #endif   /* TEMPREL_H */ | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user