]> granicus.if.org Git - postgresql/commitdiff
Make renaming a temp table behave sensibly. We don't need to touch
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 20 Jun 2000 06:41:13 +0000 (06:41 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 20 Jun 2000 06:41:13 +0000 (06:41 +0000)
the underlying table at all, just change the mapping entry ... but
that logic was missing.

src/backend/commands/rename.c
src/backend/utils/cache/temprel.c
src/include/utils/temprel.h

index 7f46a3d83bee7ca19454dd7269b6b52d45fbe328..2daebf7c5e186e590c6013c6b55092c8a44f787e 100644 (file)
@@ -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.
index 0023fa06415eeb8591fcf4f8a7e3227dedbfb9f2..d09e35336e1a5b8bb8c247703d6f0c08eb66c2cf 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * 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;
index 7a1dfa9e1bfb5ab33f0276e7a9569ed1f6433702..337188b61245001c7072ced86a2d21d047f9c9a9 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 
 #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 */