Skip to content

Commit 9f1a223

Browse files
committed
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.
1 parent 38db5fa commit 9f1a223

File tree

3 files changed

+130
-33
lines changed

3 files changed

+130
-33
lines changed

src/backend/commands/rename.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.45 2000/05/25 21:30:20 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.46 2000/06/20 06:41:13 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -29,6 +29,7 @@
2929
#include "utils/acl.h"
3030
#include "utils/relcache.h"
3131
#include "utils/syscache.h"
32+
#include "utils/temprel.h"
3233

3334

3435
/*
@@ -199,6 +200,13 @@ renamerel(const char *oldrelname, const char *newrelname)
199200
elog(ERROR, "renamerel: Illegal class name: \"%s\" -- pg_ is reserved for system catalogs",
200201
newrelname);
201202

203+
/*
204+
* Check for renaming a temp table, which only requires altering
205+
* the temp-table mapping, not the physical table.
206+
*/
207+
if (rename_temp_relation(oldrelname, newrelname))
208+
return; /* all done... */
209+
202210
/*
203211
* Instead of using heap_openr(), do it the hard way, so that we
204212
* can rename indexes as well as regular relations.

src/backend/utils/cache/temprel.c

Lines changed: 109 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,29 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.23 2000/05/30 00:49:54 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.24 2000/06/20 06:41:12 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
1515

1616
/*
1717
* This implements temp tables by modifying the relname cache lookups
1818
* of pg_class.
19-
* When a temp table is created, a linked list of temp table tuples is
20-
* stored here. When a relname cache lookup is done, references to user-named
21-
* temp tables are converted to the internal temp table names.
19+
*
20+
* When a temp table is created, normal entries are made for it in pg_class,
21+
* pg_type, etc using a unique "physical" relation name. We also make an
22+
* entry in the temp table list maintained by this module. Subsequently,
23+
* relname lookups are filtered through the temp table list, and attempts
24+
* to look up a temp table name are changed to look up the physical name.
25+
* This allows temp table names to mask a regular table of the same name
26+
* for the duration of the session. The temp table list is also used
27+
* to drop the underlying physical relations at session shutdown.
2228
*/
2329

2430
#include <sys/types.h>
2531

2632
#include "postgres.h"
33+
2734
#include "catalog/heap.h"
2835
#include "catalog/index.h"
2936
#include "utils/catcache.h"
@@ -39,39 +46,47 @@ static List *temp_rels = NIL;
3946

4047
typedef struct TempTable
4148
{
42-
char *user_relname;
43-
char *relname;
44-
Oid relid;
49+
char *user_relname; /* logical name of temp table */
50+
char *relname; /* underlying unique name */
51+
Oid relid; /* needed properties of rel */
4552
char relkind;
46-
TransactionId xid;
53+
TransactionId xid; /* xact in which temp tab was created */
4754
} TempTable;
4855

4956

57+
/*
58+
* Create a temp-relation list entry given the logical temp table name
59+
* and the already-created pg_class tuple for the underlying relation.
60+
*
61+
* NB: we assume a check has already been made for a duplicate logical name.
62+
*/
5063
void
5164
create_temp_relation(const char *relname, HeapTuple pg_class_tuple)
5265
{
66+
Form_pg_class pg_class_form = (Form_pg_class) GETSTRUCT(pg_class_tuple);
5367
MemoryContext oldcxt;
5468
TempTable *temp_rel;
5569

5670
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
5771

58-
temp_rel = palloc(sizeof(TempTable));
59-
temp_rel->user_relname = palloc(NAMEDATALEN);
60-
temp_rel->relname = palloc(NAMEDATALEN);
72+
temp_rel = (TempTable *) palloc(sizeof(TempTable));
73+
temp_rel->user_relname = (char *) palloc(NAMEDATALEN);
74+
temp_rel->relname = (char *) palloc(NAMEDATALEN);
6175

62-
/* save user-supplied name */
63-
strcpy(temp_rel->user_relname, relname);
64-
StrNCpy(temp_rel->relname, NameStr(((Form_pg_class)
65-
GETSTRUCT(pg_class_tuple))->relname), NAMEDATALEN);
76+
StrNCpy(temp_rel->user_relname, relname, NAMEDATALEN);
77+
StrNCpy(temp_rel->relname, NameStr(pg_class_form->relname), NAMEDATALEN);
6678
temp_rel->relid = pg_class_tuple->t_data->t_oid;
67-
temp_rel->relkind = ((Form_pg_class) GETSTRUCT(pg_class_tuple))->relkind;
79+
temp_rel->relkind = pg_class_form->relkind;
6880
temp_rel->xid = GetCurrentTransactionId();
6981

7082
temp_rels = lcons(temp_rel, temp_rels);
7183

7284
MemoryContextSwitchTo(oldcxt);
7385
}
7486

87+
/*
88+
* Remove underlying relations for all temp rels at backend shutdown.
89+
*/
7590
void
7691
remove_all_temp_relations(void)
7792
{
@@ -87,7 +102,7 @@ remove_all_temp_relations(void)
87102
l = temp_rels;
88103
while (l != NIL)
89104
{
90-
TempTable *temp_rel = lfirst(l);
105+
TempTable *temp_rel = (TempTable *) lfirst(l);
91106

92107
next = lnext(l); /* do this first, l is deallocated */
93108

@@ -108,11 +123,14 @@ remove_all_temp_relations(void)
108123
CommitTransactionCommand();
109124
}
110125

111-
/* we don't have the relname for indexes, so we just pass the oid */
126+
/*
127+
* Remove a temp relation map entry (part of DROP TABLE on a temp table)
128+
*
129+
* we don't have the relname for indexes, so we just pass the oid
130+
*/
112131
void
113132
remove_temp_relation(Oid relid)
114133
{
115-
116134
MemoryContext oldcxt;
117135
List *l,
118136
*prev;
@@ -123,7 +141,7 @@ remove_temp_relation(Oid relid)
123141
l = temp_rels;
124142
while (l != NIL)
125143
{
126-
TempTable *temp_rel = lfirst(l);
144+
TempTable *temp_rel = (TempTable *) lfirst(l);
127145

128146
if (temp_rel->relid == relid)
129147
{
@@ -154,7 +172,12 @@ remove_temp_relation(Oid relid)
154172
MemoryContextSwitchTo(oldcxt);
155173
}
156174

157-
/* remove entries from aborted transactions */
175+
/*
176+
* Remove freshly-created map entries during transaction abort.
177+
*
178+
* The underlying physical rel will be removed by normal abort processing.
179+
* We just have to delete the map entry.
180+
*/
158181
void
159182
invalidate_temp_relations(void)
160183
{
@@ -168,7 +191,7 @@ invalidate_temp_relations(void)
168191
l = temp_rels;
169192
while (l != NIL)
170193
{
171-
TempTable *temp_rel = lfirst(l);
194+
TempTable *temp_rel = (TempTable *) lfirst(l);
172195

173196
if (temp_rel->xid == GetCurrentTransactionId())
174197
{
@@ -194,35 +217,96 @@ invalidate_temp_relations(void)
194217
prev = l;
195218
l = lnext(l);
196219
}
197-
198220
}
199221

200222
MemoryContextSwitchTo(oldcxt);
201223
}
202224

225+
/*
226+
* To implement ALTER TABLE RENAME on a temp table, we shouldn't touch
227+
* the underlying physical table at all, just change the map entry!
228+
*
229+
* This routine is invoked early in ALTER TABLE RENAME to check for
230+
* the temp-table case. If oldname matches a temp table name, change
231+
* the map entry to the new logical name and return TRUE (or elog if
232+
* there is a conflict with another temp table name). If there is
233+
* no match, return FALSE indicating that normal rename should proceed.
234+
*
235+
* We also reject an attempt to rename a normal table to a name in use
236+
* as a temp table name. That would fail later on anyway when rename.c
237+
* looks for a rename conflict, but we can give a more specific error
238+
* message for the problem here.
239+
*
240+
* It might seem that we need to check for attempts to rename the physical
241+
* file underlying a temp table, but that'll be rejected anyway because
242+
* pg_tempXXX looks like a system table name.
243+
*
244+
* A nitpicker might complain that the rename should be undone if the
245+
* current xact is later aborted, but I'm not going to fix that now.
246+
* This whole mapping mechanism ought to be replaced with something
247+
* schema-based, anyhow.
248+
*/
249+
bool
250+
rename_temp_relation(const char *oldname,
251+
const char *newname)
252+
{
253+
List *l;
254+
255+
foreach(l, temp_rels)
256+
{
257+
TempTable *temp_rel = (TempTable *) lfirst(l);
258+
259+
if (strcmp(temp_rel->user_relname, oldname) == 0)
260+
{
261+
if (get_temp_rel_by_username(newname) != NULL)
262+
elog(ERROR, "Cannot rename temp table \"%s\": temp table \"%s\" already exists",
263+
oldname, newname);
264+
/* user_relname was palloc'd NAMEDATALEN, so safe to re-use it */
265+
StrNCpy(temp_rel->user_relname, newname, NAMEDATALEN);
266+
return true;
267+
}
268+
}
269+
270+
/* Old name does not match any temp table name, what about new? */
271+
if (get_temp_rel_by_username(newname) != NULL)
272+
elog(ERROR, "Cannot rename \"%s\" to \"%s\": a temp table by that name already exists",
273+
oldname, newname);
274+
275+
return false;
276+
}
277+
278+
279+
/*
280+
* Map user name to physical name --- returns NULL if no entry.
281+
*
282+
* This is the normal way to test whether a name is a temp table name.
283+
*/
203284
char *
204285
get_temp_rel_by_username(const char *user_relname)
205286
{
206287
List *l;
207288

208289
foreach(l, temp_rels)
209290
{
210-
TempTable *temp_rel = lfirst(l);
291+
TempTable *temp_rel = (TempTable *) lfirst(l);
211292

212293
if (strcmp(temp_rel->user_relname, user_relname) == 0)
213294
return temp_rel->relname;
214295
}
215296
return NULL;
216297
}
217298

299+
/*
300+
* Map physical name to user name --- returns pstrdup'd input if no match.
301+
*/
218302
char *
219303
get_temp_rel_by_physicalname(const char *relname)
220304
{
221305
List *l;
222306

223307
foreach(l, temp_rels)
224308
{
225-
TempTable *temp_rel = lfirst(l);
309+
TempTable *temp_rel = (TempTable *) lfirst(l);
226310

227311
if (strcmp(temp_rel->relname, relname) == 0)
228312
return temp_rel->user_relname;

src/include/utils/temprel.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: temprel.h,v 1.9 2000/04/12 17:16:55 momjian Exp $
10+
* $Id: temprel.h,v 1.10 2000/06/20 06:41:11 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -16,11 +16,16 @@
1616

1717
#include "access/htup.h"
1818

19-
void create_temp_relation(const char *relname, HeapTuple pg_class_tuple);
20-
void remove_all_temp_relations(void);
21-
void invalidate_temp_relations(void);
22-
void remove_temp_relation(Oid relid);
23-
char *get_temp_rel_by_username(const char *user_relname);
24-
char *get_temp_rel_by_physicalname(const char *relname);
19+
extern void create_temp_relation(const char *relname,
20+
HeapTuple pg_class_tuple);
21+
extern void remove_temp_relation(Oid relid);
22+
extern bool rename_temp_relation(const char *oldname,
23+
const char *newname);
24+
25+
extern void remove_all_temp_relations(void);
26+
extern void invalidate_temp_relations(void);
27+
28+
extern char *get_temp_rel_by_username(const char *user_relname);
29+
extern char *get_temp_rel_by_physicalname(const char *relname);
2530

2631
#endif /* TEMPREL_H */

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy