Skip to content
Snippets Groups Projects
Commit 9f1a2230 authored by Tom Lane's avatar Tom Lane
Browse files

Make renaming a temp table behave sensibly. We don't need to touch

the underlying table at all, just change the mapping entry ... but
that logic was missing.
parent 38db5fab
Branches
Tags
No related merge requests found
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.45 2000/05/25 21:30:20 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.46 2000/06/20 06:41:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -29,6 +29,7 @@
#include "utils/acl.h"
#include "utils/relcache.h"
#include "utils/syscache.h"
#include "utils/temprel.h"
/*
......@@ -199,6 +200,13 @@ renamerel(const char *oldrelname, 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 physical table.
*/
if (rename_temp_relation(oldrelname, newrelname))
return; /* all done... */
/*
* Instead of using heap_openr(), do it the hard way, so that we
* can rename indexes as well as regular relations.
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.23 2000/05/30 00:49:54 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.24 2000/06/20 06:41:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -16,14 +16,21 @@
/*
* This implements temp tables by modifying the relname cache lookups
* of pg_class.
* When a temp table is created, a linked list of temp table tuples is
* stored here. When a relname cache lookup is done, references to user-named
* temp tables are converted to the internal temp table names.
*
* 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 <sys/types.h>
#include "postgres.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "utils/catcache.h"
......@@ -39,32 +46,37 @@ static List *temp_rels = NIL;
typedef struct TempTable
{
char *user_relname;
char *relname;
Oid relid;
char *user_relname; /* logical name of temp table */
char *relname; /* underlying unique name */
Oid relid; /* needed properties of rel */
char relkind;
TransactionId xid;
TransactionId xid; /* xact in which temp tab was created */
} 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((MemoryContext) CacheCxt);
temp_rel = palloc(sizeof(TempTable));
temp_rel->user_relname = palloc(NAMEDATALEN);
temp_rel->relname = palloc(NAMEDATALEN);
temp_rel = (TempTable *) palloc(sizeof(TempTable));
temp_rel->user_relname = (char *) palloc(NAMEDATALEN);
temp_rel->relname = (char *) palloc(NAMEDATALEN);
/* save user-supplied name */
strcpy(temp_rel->user_relname, relname);
StrNCpy(temp_rel->relname, NameStr(((Form_pg_class)
GETSTRUCT(pg_class_tuple))->relname), NAMEDATALEN);
StrNCpy(temp_rel->user_relname, relname, NAMEDATALEN);
StrNCpy(temp_rel->relname, NameStr(pg_class_form->relname), NAMEDATALEN);
temp_rel->relid = pg_class_tuple->t_data->t_oid;
temp_rel->relkind = ((Form_pg_class) GETSTRUCT(pg_class_tuple))->relkind;
temp_rel->relkind = pg_class_form->relkind;
temp_rel->xid = GetCurrentTransactionId();
temp_rels = lcons(temp_rel, temp_rels);
......@@ -72,6 +84,9 @@ create_temp_relation(const char *relname, HeapTuple pg_class_tuple)
MemoryContextSwitchTo(oldcxt);
}
/*
* Remove underlying relations for all temp rels at backend shutdown.
*/
void
remove_all_temp_relations(void)
{
......@@ -87,7 +102,7 @@ remove_all_temp_relations(void)
l = temp_rels;
while (l != NIL)
{
TempTable *temp_rel = lfirst(l);
TempTable *temp_rel = (TempTable *) lfirst(l);
next = lnext(l); /* do this first, l is deallocated */
......@@ -108,11 +123,14 @@ remove_all_temp_relations(void)
CommitTransactionCommand();
}
/* we don't have the relname for indexes, so we just pass the oid */
/*
* Remove a temp relation map entry (part of DROP TABLE on a temp table)
*
* we don't have the relname for indexes, so we just pass the oid
*/
void
remove_temp_relation(Oid relid)
{
MemoryContext oldcxt;
List *l,
*prev;
......@@ -123,7 +141,7 @@ remove_temp_relation(Oid relid)
l = temp_rels;
while (l != NIL)
{
TempTable *temp_rel = lfirst(l);
TempTable *temp_rel = (TempTable *) lfirst(l);
if (temp_rel->relid == relid)
{
......@@ -154,7 +172,12 @@ remove_temp_relation(Oid relid)
MemoryContextSwitchTo(oldcxt);
}
/* remove entries from aborted transactions */
/*
* Remove freshly-created map entries during transaction abort.
*
* The underlying physical rel will be removed by normal abort processing.
* We just have to delete the map entry.
*/
void
invalidate_temp_relations(void)
{
......@@ -168,7 +191,7 @@ invalidate_temp_relations(void)
l = temp_rels;
while (l != NIL)
{
TempTable *temp_rel = lfirst(l);
TempTable *temp_rel = (TempTable *) lfirst(l);
if (temp_rel->xid == GetCurrentTransactionId())
{
......@@ -194,12 +217,70 @@ invalidate_temp_relations(void)
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;
}
/*
* Map user name to physical name --- returns NULL if no entry.
*
* This is the normal way to test whether a name is a temp table name.
*/
char *
get_temp_rel_by_username(const char *user_relname)
{
......@@ -207,7 +288,7 @@ get_temp_rel_by_username(const char *user_relname)
foreach(l, temp_rels)
{
TempTable *temp_rel = lfirst(l);
TempTable *temp_rel = (TempTable *) lfirst(l);
if (strcmp(temp_rel->user_relname, user_relname) == 0)
return temp_rel->relname;
......@@ -215,6 +296,9 @@ get_temp_rel_by_username(const char *user_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)
{
......@@ -222,7 +306,7 @@ get_temp_rel_by_physicalname(const char *relname)
foreach(l, temp_rels)
{
TempTable *temp_rel = lfirst(l);
TempTable *temp_rel = (TempTable *) lfirst(l);
if (strcmp(temp_rel->relname, relname) == 0)
return temp_rel->user_relname;
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: temprel.h,v 1.9 2000/04/12 17:16:55 momjian Exp $
* $Id: temprel.h,v 1.10 2000/06/20 06:41:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -16,11 +16,16 @@
#include "access/htup.h"
void create_temp_relation(const char *relname, HeapTuple pg_class_tuple);
void remove_all_temp_relations(void);
void invalidate_temp_relations(void);
void remove_temp_relation(Oid relid);
char *get_temp_rel_by_username(const char *user_relname);
char *get_temp_rel_by_physicalname(const char *relname);
extern void create_temp_relation(const char *relname,
HeapTuple pg_class_tuple);
extern void remove_temp_relation(Oid relid);
extern bool rename_temp_relation(const char *oldname,
const char *newname);
extern void remove_all_temp_relations(void);
extern void invalidate_temp_relations(void);
extern char *get_temp_rel_by_username(const char *user_relname);
extern char *get_temp_rel_by_physicalname(const char *relname);
#endif /* TEMPREL_H */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment