mirror of
https://github.com/postgres/postgres.git
synced 2025-07-12 21:01:52 +03:00
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.
This commit is contained in:
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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/acl.h"
|
||||||
#include "utils/relcache.h"
|
#include "utils/relcache.h"
|
||||||
#include "utils/syscache.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",
|
elog(ERROR, "renamerel: Illegal class name: \"%s\" -- pg_ is reserved for system catalogs",
|
||||||
newrelname);
|
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
|
* Instead of using heap_openr(), do it the hard way, so that we
|
||||||
* can rename indexes as well as regular relations.
|
* can rename indexes as well as regular relations.
|
||||||
|
134
src/backend/utils/cache/temprel.c
vendored
134
src/backend/utils/cache/temprel.c
vendored
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* This implements temp tables by modifying the relname cache lookups
|
||||||
* of pg_class.
|
* 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
|
* When a temp table is created, normal entries are made for it in pg_class,
|
||||||
* temp tables are converted to the internal temp table names.
|
* 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 <sys/types.h>
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "catalog/heap.h"
|
#include "catalog/heap.h"
|
||||||
#include "catalog/index.h"
|
#include "catalog/index.h"
|
||||||
#include "utils/catcache.h"
|
#include "utils/catcache.h"
|
||||||
@ -39,32 +46,37 @@ static List *temp_rels = NIL;
|
|||||||
|
|
||||||
typedef struct TempTable
|
typedef struct TempTable
|
||||||
{
|
{
|
||||||
char *user_relname;
|
char *user_relname; /* logical name of temp table */
|
||||||
char *relname;
|
char *relname; /* underlying unique name */
|
||||||
Oid relid;
|
Oid relid; /* needed properties of rel */
|
||||||
char relkind;
|
char relkind;
|
||||||
TransactionId xid;
|
TransactionId xid; /* xact in which temp tab was created */
|
||||||
} TempTable;
|
} 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
|
void
|
||||||
create_temp_relation(const char *relname, HeapTuple pg_class_tuple)
|
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;
|
MemoryContext oldcxt;
|
||||||
TempTable *temp_rel;
|
TempTable *temp_rel;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||||
|
|
||||||
temp_rel = palloc(sizeof(TempTable));
|
temp_rel = (TempTable *) palloc(sizeof(TempTable));
|
||||||
temp_rel->user_relname = palloc(NAMEDATALEN);
|
temp_rel->user_relname = (char *) palloc(NAMEDATALEN);
|
||||||
temp_rel->relname = palloc(NAMEDATALEN);
|
temp_rel->relname = (char *) palloc(NAMEDATALEN);
|
||||||
|
|
||||||
/* save user-supplied name */
|
StrNCpy(temp_rel->user_relname, relname, NAMEDATALEN);
|
||||||
strcpy(temp_rel->user_relname, relname);
|
StrNCpy(temp_rel->relname, NameStr(pg_class_form->relname), NAMEDATALEN);
|
||||||
StrNCpy(temp_rel->relname, NameStr(((Form_pg_class)
|
|
||||||
GETSTRUCT(pg_class_tuple))->relname), NAMEDATALEN);
|
|
||||||
temp_rel->relid = pg_class_tuple->t_data->t_oid;
|
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_rel->xid = GetCurrentTransactionId();
|
||||||
|
|
||||||
temp_rels = lcons(temp_rel, temp_rels);
|
temp_rels = lcons(temp_rel, temp_rels);
|
||||||
@ -72,6 +84,9 @@ create_temp_relation(const char *relname, HeapTuple pg_class_tuple)
|
|||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove underlying relations for all temp rels at backend shutdown.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
remove_all_temp_relations(void)
|
remove_all_temp_relations(void)
|
||||||
{
|
{
|
||||||
@ -87,7 +102,7 @@ remove_all_temp_relations(void)
|
|||||||
l = temp_rels;
|
l = temp_rels;
|
||||||
while (l != NIL)
|
while (l != NIL)
|
||||||
{
|
{
|
||||||
TempTable *temp_rel = lfirst(l);
|
TempTable *temp_rel = (TempTable *) lfirst(l);
|
||||||
|
|
||||||
next = lnext(l); /* do this first, l is deallocated */
|
next = lnext(l); /* do this first, l is deallocated */
|
||||||
|
|
||||||
@ -108,11 +123,14 @@ remove_all_temp_relations(void)
|
|||||||
CommitTransactionCommand();
|
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
|
void
|
||||||
remove_temp_relation(Oid relid)
|
remove_temp_relation(Oid relid)
|
||||||
{
|
{
|
||||||
|
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
List *l,
|
List *l,
|
||||||
*prev;
|
*prev;
|
||||||
@ -123,7 +141,7 @@ remove_temp_relation(Oid relid)
|
|||||||
l = temp_rels;
|
l = temp_rels;
|
||||||
while (l != NIL)
|
while (l != NIL)
|
||||||
{
|
{
|
||||||
TempTable *temp_rel = lfirst(l);
|
TempTable *temp_rel = (TempTable *) lfirst(l);
|
||||||
|
|
||||||
if (temp_rel->relid == relid)
|
if (temp_rel->relid == relid)
|
||||||
{
|
{
|
||||||
@ -154,7 +172,12 @@ remove_temp_relation(Oid relid)
|
|||||||
MemoryContextSwitchTo(oldcxt);
|
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
|
void
|
||||||
invalidate_temp_relations(void)
|
invalidate_temp_relations(void)
|
||||||
{
|
{
|
||||||
@ -168,7 +191,7 @@ invalidate_temp_relations(void)
|
|||||||
l = temp_rels;
|
l = temp_rels;
|
||||||
while (l != NIL)
|
while (l != NIL)
|
||||||
{
|
{
|
||||||
TempTable *temp_rel = lfirst(l);
|
TempTable *temp_rel = (TempTable *) lfirst(l);
|
||||||
|
|
||||||
if (temp_rel->xid == GetCurrentTransactionId())
|
if (temp_rel->xid == GetCurrentTransactionId())
|
||||||
{
|
{
|
||||||
@ -194,12 +217,70 @@ invalidate_temp_relations(void)
|
|||||||
prev = l;
|
prev = l;
|
||||||
l = lnext(l);
|
l = lnext(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryContextSwitchTo(oldcxt);
|
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 *
|
char *
|
||||||
get_temp_rel_by_username(const char *user_relname)
|
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)
|
foreach(l, temp_rels)
|
||||||
{
|
{
|
||||||
TempTable *temp_rel = lfirst(l);
|
TempTable *temp_rel = (TempTable *) lfirst(l);
|
||||||
|
|
||||||
if (strcmp(temp_rel->user_relname, user_relname) == 0)
|
if (strcmp(temp_rel->user_relname, user_relname) == 0)
|
||||||
return temp_rel->relname;
|
return temp_rel->relname;
|
||||||
@ -215,6 +296,9 @@ get_temp_rel_by_username(const char *user_relname)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map physical name to user name --- returns pstrdup'd input if no match.
|
||||||
|
*/
|
||||||
char *
|
char *
|
||||||
get_temp_rel_by_physicalname(const char *relname)
|
get_temp_rel_by_physicalname(const char *relname)
|
||||||
{
|
{
|
||||||
@ -222,7 +306,7 @@ get_temp_rel_by_physicalname(const char *relname)
|
|||||||
|
|
||||||
foreach(l, temp_rels)
|
foreach(l, temp_rels)
|
||||||
{
|
{
|
||||||
TempTable *temp_rel = lfirst(l);
|
TempTable *temp_rel = (TempTable *) lfirst(l);
|
||||||
|
|
||||||
if (strcmp(temp_rel->relname, relname) == 0)
|
if (strcmp(temp_rel->relname, relname) == 0)
|
||||||
return temp_rel->user_relname;
|
return temp_rel->user_relname;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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"
|
#include "access/htup.h"
|
||||||
|
|
||||||
void create_temp_relation(const char *relname, HeapTuple pg_class_tuple);
|
extern void create_temp_relation(const char *relname,
|
||||||
void remove_all_temp_relations(void);
|
HeapTuple pg_class_tuple);
|
||||||
void invalidate_temp_relations(void);
|
extern void remove_temp_relation(Oid relid);
|
||||||
void remove_temp_relation(Oid relid);
|
extern bool rename_temp_relation(const char *oldname,
|
||||||
char *get_temp_rel_by_username(const char *user_relname);
|
const char *newname);
|
||||||
char *get_temp_rel_by_physicalname(const char *relname);
|
|
||||||
|
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 */
|
#endif /* TEMPREL_H */
|
||||||
|
Reference in New Issue
Block a user