diff options
Diffstat (limited to 'src/backend/utils')
-rw-r--r-- | src/backend/utils/cache/inval.c | 148 | ||||
-rw-r--r-- | src/backend/utils/cache/relcache.c | 82 | ||||
-rw-r--r-- | src/backend/utils/cache/temprel.c | 282 |
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); |