1 /*-------------------------------------------------------------------------
4 * POSTGRES temporary relation handling
6 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.34 2001/01/24 19:43:15 momjian Exp $
13 *-------------------------------------------------------------------------
17 * This implements temp tables by modifying the relname cache lookups
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.
32 #include <sys/types.h>
34 #include "catalog/heap.h"
35 #include "catalog/index.h"
36 #include "miscadmin.h"
37 #include "utils/temprel.h"
45 static List *temp_rels = NIL;
47 typedef struct TempTable
49 NameData user_relname; /* logical name of temp table */
50 NameData relname; /* underlying unique name */
51 Oid relid; /* needed properties of rel */
54 * If this entry was created during this xact, it should be deleted
55 * at xact abort. Conversely, if this entry was deleted during this
56 * xact, it should be removed at xact commit. We leave deleted entries
57 * in the list until commit so that we can roll back if needed ---
58 * but we ignore them for purposes of lookup!
60 bool created_in_cur_xact;
61 bool deleted_in_cur_xact;
66 * Create a temp-relation list entry given the logical temp table name
67 * and the already-created pg_class tuple for the underlying relation.
69 * NB: we assume a check has already been made for a duplicate logical name.
72 create_temp_relation(const char *relname, HeapTuple pg_class_tuple)
74 Form_pg_class pg_class_form = (Form_pg_class) GETSTRUCT(pg_class_tuple);
78 oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
80 temp_rel = (TempTable *) palloc(sizeof(TempTable));
82 StrNCpy(NameStr(temp_rel->user_relname), relname,
84 StrNCpy(NameStr(temp_rel->relname), NameStr(pg_class_form->relname),
86 temp_rel->relid = pg_class_tuple->t_data->t_oid;
87 temp_rel->relkind = pg_class_form->relkind;
88 temp_rel->created_in_cur_xact = true;
89 temp_rel->deleted_in_cur_xact = false;
91 temp_rels = lcons(temp_rel, temp_rels);
93 MemoryContextSwitchTo(oldcxt);
97 * Remove a temp relation map entry (part of DROP TABLE on a temp table).
98 * We don't actually remove the entry, just mark it dead.
100 * We don't have the relname for indexes, so we just pass the oid.
103 remove_temp_rel_by_relid(Oid relid)
107 foreach(l, temp_rels)
109 TempTable *temp_rel = (TempTable *) lfirst(l);
111 if (temp_rel->relid == relid)
112 temp_rel->deleted_in_cur_xact = true;
113 /* Keep scanning 'cause there could be multiple matches; see RENAME */
118 * To implement ALTER TABLE RENAME on a temp table, we shouldn't touch
119 * the underlying physical table at all, just change the map entry!
121 * This routine is invoked early in ALTER TABLE RENAME to check for
122 * the temp-table case. If oldname matches a temp table name, change
123 * the mapping to the new logical name and return TRUE (or elog if
124 * there is a conflict with another temp table name). If there is
125 * no match, return FALSE indicating that normal rename should proceed.
127 * We also reject an attempt to rename a normal table to a name in use
128 * as a temp table name. That would fail later on anyway when rename.c
129 * looks for a rename conflict, but we can give a more specific error
130 * message for the problem here.
132 * It might seem that we need to check for attempts to rename the physical
133 * file underlying a temp table, but that'll be rejected anyway because
134 * pg_tempXXX looks like a system table name.
137 rename_temp_relation(const char *oldname,
142 foreach(l, temp_rels)
144 TempTable *temp_rel = (TempTable *) lfirst(l);
145 MemoryContext oldcxt;
146 TempTable *new_temp_rel;
148 if (temp_rel->deleted_in_cur_xact)
149 continue; /* ignore it if logically deleted */
151 if (strcmp(NameStr(temp_rel->user_relname), oldname) != 0)
152 continue; /* ignore non-matching entries */
154 /* We are renaming a temp table --- is it OK to do so? */
155 if (is_temp_rel_name(newname))
156 elog(ERROR, "Cannot rename temp table \"%s\": temp table \"%s\" already exists",
160 * Create a new mapping entry and mark the old one deleted in this
161 * xact. One of these entries will be deleted at xact end.
163 * NOTE: the new mapping entry is inserted into the list just after
164 * the old one. We could alternatively insert it before the old one,
165 * but that'd take more code. It does need to be in one spot or the
166 * other, to ensure that deletion of temp rels happens in the right
167 * order during remove_all_temp_relations().
169 oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
171 new_temp_rel = (TempTable *) palloc(sizeof(TempTable));
172 memcpy(new_temp_rel, temp_rel, sizeof(TempTable));
174 StrNCpy(NameStr(new_temp_rel->user_relname), newname, NAMEDATALEN);
175 new_temp_rel->created_in_cur_xact = true;
177 lnext(l) = lcons(new_temp_rel, lnext(l));
179 temp_rel->deleted_in_cur_xact = true;
181 MemoryContextSwitchTo(oldcxt);
186 /* Old name does not match any temp table name, what about new? */
187 if (is_temp_rel_name(newname))
188 elog(ERROR, "Cannot rename \"%s\" to \"%s\": a temp table by that name already exists",
196 * Remove underlying relations for all temp rels at backend shutdown.
199 remove_all_temp_relations(void)
203 /* skip xact start overhead if nothing to do */
204 if (temp_rels == NIL)
207 AbortOutOfAnyTransaction();
208 StartTransactionCommand();
211 * Scan the list and delete all entries not already deleted.
212 * We need not worry about list entries getting deleted from under us,
213 * because remove_temp_rel_by_relid() doesn't remove entries, only
214 * mark them dead. Note that entries will be deleted in reverse order
215 * of creation --- that's critical for cases involving inheritance.
217 foreach(l, temp_rels)
219 TempTable *temp_rel = (TempTable *) lfirst(l);
221 if (temp_rel->deleted_in_cur_xact)
222 continue; /* ignore it if deleted already */
224 if (temp_rel->relkind != RELKIND_INDEX)
226 char relname[NAMEDATALEN];
228 /* safe from deallocation */
229 strcpy(relname, NameStr(temp_rel->user_relname));
230 heap_drop_with_catalog(relname, allowSystemTableMods);
233 index_drop(temp_rel->relid);
234 /* advance cmd counter to make catalog changes visible */
235 CommandCounterIncrement();
238 CommitTransactionCommand();
242 * Clean up temprel mapping entries during transaction commit or abort.
244 * During commit, remove entries that were deleted during this transaction;
245 * during abort, remove those created during this transaction.
247 * We do not need to worry about removing the underlying physical relation;
248 * that's someone else's job.
251 AtEOXact_temp_relations(bool isCommit)
260 TempTable *temp_rel = (TempTable *) lfirst(l);
262 if (isCommit ? temp_rel->deleted_in_cur_xact :
263 temp_rel->created_in_cur_xact)
265 /* This entry must be removed */
268 lnext(prev) = lnext(l);
274 temp_rels = lnext(l);
282 /* This entry must be preserved */
283 temp_rel->created_in_cur_xact = false;
284 temp_rel->deleted_in_cur_xact = false;
293 * Map user name to physical name --- returns NULL if no entry.
295 * This also supports testing whether a name is a temp table name;
296 * see is_temp_rel_name() macro.
299 get_temp_rel_by_username(const char *user_relname)
303 foreach(l, temp_rels)
305 TempTable *temp_rel = (TempTable *) lfirst(l);
307 if (temp_rel->deleted_in_cur_xact)
308 continue; /* ignore it if logically deleted */
310 if (strcmp(NameStr(temp_rel->user_relname), user_relname) == 0)
311 return NameStr(temp_rel->relname);
317 * Map physical name to user name --- returns pstrdup'd input if no match.
320 get_temp_rel_by_physicalname(const char *relname)
324 foreach(l, temp_rels)
326 TempTable *temp_rel = (TempTable *) lfirst(l);
328 if (temp_rel->deleted_in_cur_xact)
329 continue; /* ignore it if logically deleted */
331 if (strcmp(NameStr(temp_rel->relname), relname) == 0)
332 return NameStr(temp_rel->user_relname);
334 /* needed for bootstrapping temp tables */
335 return pstrdup(relname);