aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/cache
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/cache')
-rw-r--r--src/backend/utils/cache/inval.c148
-rw-r--r--src/backend/utils/cache/relcache.c82
-rw-r--r--src/backend/utils/cache/temprel.c282
3 files changed, 175 insertions, 337 deletions
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c
index e218daa7483..8f4fd626f8b 100644
--- a/src/backend/utils/cache/inval.c
+++ b/src/backend/utils/cache/inval.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.37 2000/06/08 19:51:03 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.38 2000/11/08 22:10:01 tgl Exp $
*
* Note - this code is real crufty...
*
@@ -80,10 +80,10 @@ typedef InvalidationMessageData *InvalidationMessage;
/*
* ----------------
- * Invalidation info was devided into three parts.
- * 1) shared invalidation to be registerd for all backends
+ * Invalidation info is divided into three parts.
+ * 1) shared invalidation to be registered for all backends
* 2) local invalidation for the transaction itself
- * 3) rollback information for the transaction itself
+ * 3) rollback information for the transaction itself (in case we abort)
* ----------------
*/
@@ -160,7 +160,9 @@ LocalInvalidRegister(LocalInvalid invalid,
* --------------------------------
*/
static void
- LocalInvalidInvalidate(LocalInvalid invalid, void (*function) (), bool freemember)
+LocalInvalidInvalidate(LocalInvalid invalid,
+ void (*function) (),
+ bool freemember)
{
InvalidationEntryData *entryDataP;
@@ -216,15 +218,10 @@ elog(DEBUG, "CacheIdRegisterLocalInvalid(%d, %d, [%d, %d])", \
elog(DEBUG, "CacheIdRegisterLocalRollback(%d, %d, [%d, %d])", \
cacheId, hashIndex, ItemPointerGetBlockNumber(pointer), \
ItemPointerGetOffsetNumber(pointer))
-#define CacheIdImmediateRegisterSharedInvalid_DEBUG1 \
-elog(DEBUG, "CacheIdImmediateRegisterSharedInvalid(%d, %d, [%d, %d])", \
- cacheId, hashIndex, ItemPointerGetBlockNumber(pointer), \
- ItemPointerGetOffsetNumber(pointer))
#else
#define CacheIdRegisterSpecifiedLocalInvalid_DEBUG1
#define CacheIdRegisterLocalInvalid_DEBUG1
#define CacheIdRegisterLocalRollback_DEBUG1
-#define CacheIdImmediateRegisterSharedInvalid_DEBUG1
#endif /* INVALIDDEBUG */
/* --------------------------------
@@ -233,7 +230,9 @@ elog(DEBUG, "CacheIdImmediateRegisterSharedInvalid(%d, %d, [%d, %d])", \
*/
static LocalInvalid
CacheIdRegisterSpecifiedLocalInvalid(LocalInvalid invalid,
- Index cacheId, Index hashIndex, ItemPointer pointer)
+ Index cacheId,
+ Index hashIndex,
+ ItemPointer pointer)
{
InvalidationMessage message;
@@ -318,43 +317,6 @@ CacheIdRegisterLocalRollback(Index cacheId, Index hashIndex,
}
/* --------------------------------
- * CacheIdImmediateRegisterSharedInvalid
- * --------------------------------
- */
-static void
-CacheIdImmediateRegisterSharedInvalid(Index cacheId, Index hashIndex,
- ItemPointer pointer)
-{
- InvalidationMessage message;
-
- /* ----------------
- * debugging stuff
- * ----------------
- */
- CacheIdImmediateRegisterSharedInvalid_DEBUG1;
-
- /* ----------------
- * create a message describing the system catalog tuple
- * we wish to invalidate.
- * ----------------
- */
- message = (InvalidationMessage)
- InvalidationEntryAllocate(sizeof(InvalidationMessageData));
-
- message->kind = 'c';
- message->any.catalog.cacheId = cacheId;
- message->any.catalog.hashIndex = hashIndex;
-
- ItemPointerCopy(pointer, &message->any.catalog.pointerData);
- /* ----------------
- * Register a shared catalog cache invalidation.
- * ----------------
- */
- InvalidationMessageRegisterSharedInvalid(message);
- free((Pointer) &((InvalidationUserData *) message)->dataP[-1]);
-}
-
-/* --------------------------------
* RelationIdRegisterSpecifiedLocalInvalid
* --------------------------------
*/
@@ -449,44 +411,6 @@ RelationIdRegisterLocalRollback(Oid relationId, Oid objectId)
}
/* --------------------------------
- * RelationIdImmediateRegisterSharedInvalid
- * --------------------------------
- */
-static void
-RelationIdImmediateRegisterSharedInvalid(Oid relationId, Oid objectId)
-{
- InvalidationMessage message;
-
- /* ----------------
- * debugging stuff
- * ----------------
- */
-#ifdef INVALIDDEBUG
- elog(DEBUG, "RelationImmediateRegisterSharedInvalid(%u, %u)", relationId,
- objectId);
-#endif /* defined(INVALIDDEBUG) */
-
- /* ----------------
- * create a message describing the relation descriptor
- * we wish to invalidate.
- * ----------------
- */
- message = (InvalidationMessage)
- InvalidationEntryAllocate(sizeof(InvalidationMessageData));
-
- message->kind = 'r';
- message->any.relation.relationId = relationId;
- message->any.relation.objectId = objectId;
-
- /* ----------------
- * Register a shared catalog cache invalidation.
- * ----------------
- */
- InvalidationMessageRegisterSharedInvalid(message);
- free((Pointer) &((InvalidationUserData *) message)->dataP[-1]);
-}
-
-/* --------------------------------
* CacheIdInvalidate
*
* This routine can invalidate a tuple in a system catalog cache
@@ -890,55 +814,3 @@ RelationMark4RollbackHeapTuple(Relation relation, HeapTuple tuple)
RelationIdRegisterLocalRollback,
"RelationMark4RollbackHeapTuple");
}
-
-/*
- * ImmediateInvalidateSharedHeapTuple
- * Different from RelationInvalidateHeapTuple()
- * this function queues shared invalidation info immediately.
- */
-void
-ImmediateInvalidateSharedHeapTuple(Relation relation, HeapTuple tuple)
-{
- InvokeHeapTupleInvalidation(relation, tuple,
- CacheIdImmediateRegisterSharedInvalid,
- RelationIdImmediateRegisterSharedInvalid,
- "ImmediateInvalidateSharedHeapTuple");
-}
-
-#ifdef NOT_USED
-/*
- * ImmediateSharedRelationCacheInvalidate
- * Register shared relation cache invalidation immediately
- *
- * This is needed for smgrunlink()/smgrtruncate().
- * Those functions unlink/truncate the base file immediately
- * and couldn't be rollbacked in case of abort/crash.
- * So relation cache invalidation must be registerd immediately.
- * Note:
- * Assumes Relation is valid.
- */
-void
-ImmediateSharedRelationCacheInvalidate(Relation relation)
-{
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
-
- if (IsBootstrapProcessingMode())
- return;
-
- /* ----------------
- * debugging stuff
- * ----------------
- */
-#ifdef INVALIDDEBUG
- elog(DEBUG, "ImmediateSharedRelationCacheInvalidate(%s)", \
- RelationGetPhysicalRelationName(relation));
-#endif /* defined(INVALIDDEBUG) */
-
- RelationIdImmediateRegisterSharedInvalid(
- RelOid_pg_class, RelationGetRelid(relation));
-}
-#endif
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index ea7a8d0212c..be902d78423 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.114 2000/10/28 16:20:57 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.115 2000/11/08 22:10:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -954,7 +954,6 @@ static Relation
RelationBuildDesc(RelationBuildDescInfo buildinfo,
Relation oldrelation)
{
- File fd;
Relation relation;
Oid relid;
Oid relam;
@@ -1069,18 +1068,10 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
* by the storage manager code to rd_fd.
* ----------------
*/
- if (relation->rd_rel->relkind != RELKIND_VIEW) {
- fd = smgropen(DEFAULT_SMGR, relation);
-
- Assert(fd >= -1);
- if (fd == -1)
- elog(NOTICE, "RelationBuildDesc: smgropen(%s): %m",
- NameStr(relation->rd_rel->relname));
-
- relation->rd_fd = fd;
- } else {
+ if (relation->rd_rel->relkind != RELKIND_VIEW)
+ relation->rd_fd = smgropen(DEFAULT_SMGR, relation, false);
+ else
relation->rd_fd = -1;
- }
/* ----------------
* insert newly created relation into proper relcaches,
@@ -1337,14 +1328,11 @@ RelationIdCacheGetRelation(Oid relationId)
if (RelationIsValid(rd))
{
+ /* re-open files if necessary */
if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
- {
- rd->rd_fd = smgropen(DEFAULT_SMGR, rd);
- Assert(rd->rd_fd != -1 || rd->rd_unlinked);
- }
+ rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
RelationIncrementReferenceCount(rd);
-
}
return rd;
@@ -1371,14 +1359,11 @@ RelationNameCacheGetRelation(const char *relationName)
if (RelationIsValid(rd))
{
+ /* re-open files if necessary */
if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
- {
- rd->rd_fd = smgropen(DEFAULT_SMGR, rd);
- Assert(rd->rd_fd != -1 || rd->rd_unlinked);
- }
+ rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
RelationIncrementReferenceCount(rd);
-
}
return rd;
@@ -1393,14 +1378,11 @@ RelationNodeCacheGetRelation(RelFileNode rnode)
if (RelationIsValid(rd))
{
+ /* re-open files if necessary */
if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
- {
- rd->rd_fd = smgropen(DEFAULT_SMGR, rd);
- Assert(rd->rd_fd != -1 || rd->rd_unlinked);
- }
+ rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
RelationIncrementReferenceCount(rd);
-
}
return rd;
@@ -1536,15 +1518,13 @@ RelationClearRelation(Relation relation, bool rebuildIt)
/*
* Make sure smgr and lower levels close the relation's files, if they
- * weren't closed already. We do this unconditionally; if the
- * relation is not deleted, the next smgr access should reopen the
- * files automatically. This ensures that the low-level file access
- * state is updated after, say, a vacuum truncation.
- *
- * NOTE: this call is a no-op if the relation's smgr file is already
- * closed or unlinked.
+ * weren't closed already. If the relation is not getting deleted,
+ * the next smgr access should reopen the files automatically. This
+ * ensures that the low-level file access state is updated after, say,
+ * a vacuum truncation.
*/
- smgrclose(DEFAULT_SMGR, relation);
+ if (relation->rd_fd >= 0)
+ smgrclose(DEFAULT_SMGR, relation);
/*
* Never, never ever blow away a nailed-in system relation, because
@@ -1617,7 +1597,6 @@ RelationClearRelation(Relation relation, bool rebuildIt)
MemoryContext old_rulescxt = relation->rd_rulescxt;
TriggerDesc *old_trigdesc = relation->trigdesc;
int old_nblocks = relation->rd_nblocks;
- bool relDescChanged = false;
RelationBuildDescInfo buildinfo;
buildinfo.infotype = INFO_RELID;
@@ -1644,7 +1623,6 @@ RelationClearRelation(Relation relation, bool rebuildIt)
else
{
FreeTupleDesc(old_att);
- relDescChanged = true;
}
if (equalRuleLocks(old_rules, relation->rd_rules))
{
@@ -1657,7 +1635,6 @@ RelationClearRelation(Relation relation, bool rebuildIt)
{
if (old_rulescxt)
MemoryContextDelete(old_rulescxt);
- relDescChanged = true;
}
if (equalTriggerDescs(old_trigdesc, relation->trigdesc))
{
@@ -1667,7 +1644,6 @@ RelationClearRelation(Relation relation, bool rebuildIt)
else
{
FreeTriggerDesc(old_trigdesc);
- relDescChanged = true;
}
relation->rd_nblocks = old_nblocks;
@@ -1675,14 +1651,7 @@ RelationClearRelation(Relation relation, bool rebuildIt)
* this is kind of expensive, but I think we must do it in case
* relation has been truncated...
*/
- if (relation->rd_unlinked)
- relation->rd_nblocks = 0;
- else
- relation->rd_nblocks = RelationGetNumberOfBlocks(relation);
-
- if (relDescChanged && !RelationHasReferenceCountZero(relation))
- elog(ERROR, "RelationClearRelation: relation %u modified while in use",
- buildinfo.i.info_id);
+ relation->rd_nblocks = RelationGetNumberOfBlocks(relation);
}
}
@@ -1934,9 +1903,6 @@ RelationRegisterRelation(Relation relation)
void
RelationPurgeLocalRelation(bool xactCommitted)
{
- if (newlyCreatedRelns == NULL)
- return;
-
while (newlyCreatedRelns)
{
List *l = newlyCreatedRelns;
@@ -1949,19 +1915,7 @@ RelationPurgeLocalRelation(bool xactCommitted)
newlyCreatedRelns = lnext(newlyCreatedRelns);
pfree(l);
- if (!xactCommitted)
- {
- /*
- * remove the file if we abort. This is so that files for
- * tables created inside a transaction block get removed.
- */
- if (! reln->rd_unlinked)
- {
- smgrunlink(DEFAULT_SMGR, reln);
- reln->rd_unlinked = true;
- }
- }
-
+ /* XXX is this step still needed? If so, why? */
if (!IsBootstrapProcessingMode())
RelationClearRelation(reln, false);
}
diff --git a/src/backend/utils/cache/temprel.c b/src/backend/utils/cache/temprel.c
index 460cf56a408..31591663cee 100644
--- a/src/backend/utils/cache/temprel.c
+++ b/src/backend/utils/cache/temprel.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.29 2000/10/19 23:06:24 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.30 2000/11/08 22:10:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,10 +27,10 @@
* to drop the underlying physical relations at session shutdown.
*/
-#include <sys/types.h>
-
#include "postgres.h"
+#include <sys/types.h>
+
#include "catalog/heap.h"
#include "catalog/index.h"
#include "miscadmin.h"
@@ -47,11 +47,19 @@ static List *temp_rels = NIL;
typedef struct TempTable
{
- char *user_relname; /* logical name of temp table */
- char *relname; /* underlying unique name */
+ NameData user_relname; /* logical name of temp table */
+ NameData relname; /* underlying unique name */
Oid relid; /* needed properties of rel */
char relkind;
- TransactionId xid; /* xact in which temp tab was created */
+ /*
+ * 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;
@@ -71,14 +79,15 @@ create_temp_relation(const char *relname, HeapTuple pg_class_tuple)
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
temp_rel = (TempTable *) palloc(sizeof(TempTable));
- temp_rel->user_relname = (char *) palloc(NAMEDATALEN);
- temp_rel->relname = (char *) palloc(NAMEDATALEN);
- StrNCpy(temp_rel->user_relname, relname, NAMEDATALEN);
- StrNCpy(temp_rel->relname, NameStr(pg_class_form->relname), NAMEDATALEN);
+ 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->xid = GetCurrentTransactionId();
+ temp_rel->created_in_cur_xact = true;
+ temp_rel->deleted_in_cur_xact = false;
temp_rels = lcons(temp_rel, temp_rels);
@@ -86,11 +95,106 @@ create_temp_relation(const char *relname, HeapTuple pg_class_tuple)
}
/*
+ * 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 (get_temp_rel_by_username(newname) != NULL)
+ 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.
+ */
+ 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;
+
+ temp_rels = lcons(new_temp_rel, temp_rels);
+
+ temp_rel->deleted_in_cur_xact = true;
+
+ MemoryContextSwitchTo(oldcxt);
+
+ return true;
+ }
+
+ /* Old name does not match any temp table name, what about new? */
+ if (get_temp_rel_by_username(newname) != NULL)
+ 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;
@@ -99,21 +203,24 @@ remove_all_temp_relations(void)
StartTransactionCommand();
/*
- * The way this works is that each time through the loop, we delete
- * the frontmost entry. The DROP will call remove_temp_rel_by_relid()
- * as a side effect, thereby removing the entry in the temp_rels list.
- * So this is not an infinite loop, even though it looks like one.
+ * 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.
*/
- while (temp_rels != NIL)
+ foreach(l, temp_rels)
{
- TempTable *temp_rel = (TempTable *) lfirst(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)
{
char relname[NAMEDATALEN];
/* safe from deallocation */
- strcpy(relname, temp_rel->user_relname);
+ strcpy(relname, NameStr(temp_rel->user_relname));
heap_drop_with_catalog(relname, allowSystemTableMods);
}
else
@@ -126,79 +233,30 @@ remove_all_temp_relations(void)
}
/*
- * Remove a temp relation map entry (part of DROP TABLE on a temp table)
+ * Clean up temprel mapping entries during transaction commit or abort.
*
- * we don't have the relname for indexes, so we just pass the oid
- */
-void
-remove_temp_rel_by_relid(Oid relid)
-{
- MemoryContext oldcxt;
- List *l,
- *prev;
-
- oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
-
- prev = NIL;
- l = temp_rels;
- while (l != NIL)
- {
- TempTable *temp_rel = (TempTable *) lfirst(l);
-
- if (temp_rel->relid == relid)
- {
- pfree(temp_rel->user_relname);
- pfree(temp_rel->relname);
- pfree(temp_rel);
- /* remove from linked list */
- if (prev != NIL)
- {
- lnext(prev) = lnext(l);
- pfree(l);
- l = lnext(prev);
- }
- else
- {
- temp_rels = lnext(l);
- pfree(l);
- l = temp_rels;
- }
- }
- else
- {
- prev = l;
- l = lnext(l);
- }
- }
-
- MemoryContextSwitchTo(oldcxt);
-}
-
-/*
- * Remove freshly-created map entries during transaction abort.
+ * During commit, remove entries that were deleted during this transaction;
+ * during abort, remove those created during this transaction.
*
- * The underlying physical rel will be removed by normal abort processing.
- * We just have to delete the map entry.
+ * We do not need to worry about removing the underlying physical relation;
+ * that's someone else's job.
*/
void
-remove_temp_rel_in_myxid(void)
+AtEOXact_temp_relations(bool isCommit)
{
- MemoryContext oldcxt;
List *l,
*prev;
- oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
-
prev = NIL;
l = temp_rels;
while (l != NIL)
{
TempTable *temp_rel = (TempTable *) lfirst(l);
- if (temp_rel->xid == GetCurrentTransactionId())
+ if (isCommit ? temp_rel->deleted_in_cur_xact :
+ temp_rel->created_in_cur_xact)
{
- pfree(temp_rel->user_relname);
- pfree(temp_rel->relname);
+ /* This entry must be removed */
pfree(temp_rel);
/* remove from linked list */
if (prev != NIL)
@@ -216,65 +274,13 @@ remove_temp_rel_in_myxid(void)
}
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);
}
}
-
- MemoryContextSwitchTo(oldcxt);
-}
-
-/*
- * 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 map entry 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.
- *
- * A nitpicker might complain that the rename should be undone if the
- * current xact is later aborted, but I'm not going to fix that now.
- * This whole mapping mechanism ought to be replaced with something
- * schema-based, anyhow.
- */
-bool
-rename_temp_relation(const char *oldname,
- const char *newname)
-{
- List *l;
-
- foreach(l, temp_rels)
- {
- TempTable *temp_rel = (TempTable *) lfirst(l);
-
- if (strcmp(temp_rel->user_relname, oldname) == 0)
- {
- if (get_temp_rel_by_username(newname) != NULL)
- elog(ERROR, "Cannot rename temp table \"%s\": temp table \"%s\" already exists",
- oldname, newname);
- /* user_relname was palloc'd NAMEDATALEN, so safe to re-use it */
- StrNCpy(temp_rel->user_relname, newname, NAMEDATALEN);
- return true;
- }
- }
-
- /* Old name does not match any temp table name, what about new? */
- if (get_temp_rel_by_username(newname) != NULL)
- elog(ERROR, "Cannot rename \"%s\" to \"%s\": a temp table by that name already exists",
- oldname, newname);
-
- return false;
}
@@ -292,8 +298,11 @@ get_temp_rel_by_username(const char *user_relname)
{
TempTable *temp_rel = (TempTable *) lfirst(l);
- if (strcmp(temp_rel->user_relname, user_relname) == 0)
- return temp_rel->relname;
+ 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;
}
@@ -310,8 +319,11 @@ get_temp_rel_by_physicalname(const char *relname)
{
TempTable *temp_rel = (TempTable *) lfirst(l);
- if (strcmp(temp_rel->relname, relname) == 0)
- return temp_rel->user_relname;
+ 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);