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
4047typedef 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 */
4552char 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+ */
5063void
5164create_temp_relation (const char * relname ,HeapTuple pg_class_tuple )
5265{
66+ Form_pg_class pg_class_form = (Form_pg_class )GETSTRUCT (pg_class_tuple );
5367MemoryContext oldcxt ;
5468TempTable * temp_rel ;
5569
5670oldcxt = 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 );
6678temp_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 ;
6880temp_rel -> xid = GetCurrentTransactionId ();
6981
7082temp_rels = lcons (temp_rel ,temp_rels );
7183
7284MemoryContextSwitchTo (oldcxt );
7385}
7486
87+ /*
88+ * Remove underlying relations for all temp rels at backend shutdown.
89+ */
7590void
7691remove_all_temp_relations (void )
7792{
@@ -87,7 +102,7 @@ remove_all_temp_relations(void)
87102l = temp_rels ;
88103while (l != NIL )
89104{
90- TempTable * temp_rel = lfirst (l );
105+ TempTable * temp_rel = ( TempTable * ) lfirst (l );
91106
92107next = lnext (l );/* do this first, l is deallocated */
93108
@@ -108,11 +123,14 @@ remove_all_temp_relations(void)
108123CommitTransactionCommand ();
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+ */
112131void
113132remove_temp_relation (Oid relid )
114133{
115-
116134MemoryContext oldcxt ;
117135List * l ,
118136* prev ;
@@ -123,7 +141,7 @@ remove_temp_relation(Oid relid)
123141l = temp_rels ;
124142while (l != NIL )
125143{
126- TempTable * temp_rel = lfirst (l );
144+ TempTable * temp_rel = ( TempTable * ) lfirst (l );
127145
128146if (temp_rel -> relid == relid )
129147{
@@ -154,7 +172,12 @@ remove_temp_relation(Oid relid)
154172MemoryContextSwitchTo (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+ */
158181void
159182invalidate_temp_relations (void )
160183{
@@ -168,7 +191,7 @@ invalidate_temp_relations(void)
168191l = temp_rels ;
169192while (l != NIL )
170193{
171- TempTable * temp_rel = lfirst (l );
194+ TempTable * temp_rel = ( TempTable * ) lfirst (l );
172195
173196if (temp_rel -> xid == GetCurrentTransactionId ())
174197{
@@ -194,35 +217,96 @@ invalidate_temp_relations(void)
194217prev = l ;
195218l = lnext (l );
196219}
197-
198220}
199221
200222MemoryContextSwitchTo (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+ */
203284char *
204285get_temp_rel_by_username (const char * user_relname )
205286{
206287List * l ;
207288
208289foreach (l ,temp_rels )
209290{
210- TempTable * temp_rel = lfirst (l );
291+ TempTable * temp_rel = ( TempTable * ) lfirst (l );
211292
212293if (strcmp (temp_rel -> user_relname ,user_relname )== 0 )
213294return temp_rel -> relname ;
214295}
215296return NULL ;
216297}
217298
299+ /*
300+ * Map physical name to user name --- returns pstrdup'd input if no match.
301+ */
218302char *
219303get_temp_rel_by_physicalname (const char * relname )
220304{
221305List * l ;
222306
223307foreach (l ,temp_rels )
224308{
225- TempTable * temp_rel = lfirst (l );
309+ TempTable * temp_rel = ( TempTable * ) lfirst (l );
226310
227311if (strcmp (temp_rel -> relname ,relname )== 0 )
228312return temp_rel -> user_relname ;