1 /*-------------------------------------------------------------------------
4 * renameatt() and renamerel() reside here.
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.45 2000/05/25 21:30:20 tgl Exp $
13 *-------------------------------------------------------------------------
19 #include "access/heapam.h"
20 #include "catalog/catname.h"
21 #include "catalog/pg_type.h"
22 #include "catalog/heap.h"
23 #include "catalog/indexing.h"
24 #include "catalog/catalog.h"
25 #include "commands/rename.h"
26 #include "miscadmin.h"
27 #include "storage/smgr.h"
28 #include "optimizer/prep.h"
29 #include "utils/acl.h"
30 #include "utils/relcache.h"
31 #include "utils/syscache.h"
35 * renameatt - changes the name of a attribute in a relation
37 * Attname attribute is changed in attribute catalog.
38 * No record of the previous attname is kept (correct?).
40 * get proper relrelation from relation catalog (if not arg)
41 * scan attribute catalog
42 * for name conflict (within rel)
43 * for original attribute (if not arg)
44 * modify attname in attribute tuple
45 * insert modified attribute in attribute catalog
46 * delete original attribute from attribute catalog
48 * XXX Renaming an indexed attribute must (eventually) also change
49 * the attribute name in the associated indexes.
52 renameatt(char *relname,
58 Relation targetrelation;
66 * permissions checking. this would normally be done in utility.c,
67 * but this particular routine is recursive.
69 * normally, only the owner of a class can change its schema.
71 if (!allowSystemTableMods && IsSystemRelationName(relname))
72 elog(ERROR, "renameatt: class \"%s\" is a system catalog",
75 if (!IsBootstrapProcessingMode() &&
76 !pg_ownercheck(userName, relname, RELNAME))
77 elog(ERROR, "renameatt: you do not own class \"%s\"",
82 * Grab an exclusive lock on the target table, which we will NOT
83 * release until end of transaction.
85 targetrelation = heap_openr(relname, AccessExclusiveLock);
86 relid = RelationGetRelid(targetrelation);
87 heap_close(targetrelation, NoLock); /* close rel but keep lock! */
90 * if the 'recurse' flag is set then we are supposed to rename this
91 * attribute in all classes that inherit from 'relname' (as well as in
94 * any permissions or problems with duplicate attributes will cause the
95 * whole transaction to abort, which is what we want -- all or
103 /* this routine is actually in the planner */
104 children = find_all_inheritors(relid);
107 * find_all_inheritors does the recursive search of the
108 * inheritance hierarchy, so all we have to do is process all of
109 * the relids in the list that it returns.
111 foreach(child, children)
113 Oid childrelid = lfirsti(child);
114 char childname[NAMEDATALEN];
116 if (childrelid == relid)
118 reltup = SearchSysCacheTuple(RELOID,
119 ObjectIdGetDatum(childrelid),
121 if (!HeapTupleIsValid(reltup))
123 elog(ERROR, "renameatt: can't find catalog entry for inheriting class with oid %u",
126 /* make copy of cache value, could disappear in call */
128 NameStr(((Form_pg_class) GETSTRUCT(reltup))->relname),
130 /* note we need not recurse again! */
131 renameatt(childname, oldattname, newattname, userName, 0);
135 attrelation = heap_openr(AttributeRelationName, RowExclusiveLock);
137 oldatttup = SearchSysCacheTupleCopy(ATTNAME,
138 ObjectIdGetDatum(relid),
139 PointerGetDatum(oldattname),
141 if (!HeapTupleIsValid(oldatttup))
142 elog(ERROR, "renameatt: attribute \"%s\" nonexistent", oldattname);
144 if (((Form_pg_attribute) GETSTRUCT(oldatttup))->attnum < 0)
145 elog(ERROR, "renameatt: system attribute \"%s\" not renamed", oldattname);
147 newatttup = SearchSysCacheTuple(ATTNAME,
148 ObjectIdGetDatum(relid),
149 PointerGetDatum(newattname),
151 /* should not already exist */
152 if (HeapTupleIsValid(newatttup))
154 heap_freetuple(oldatttup);
155 elog(ERROR, "renameatt: attribute \"%s\" exists", newattname);
158 StrNCpy(NameStr(((Form_pg_attribute) GETSTRUCT(oldatttup))->attname),
159 newattname, NAMEDATALEN);
161 heap_update(attrelation, &oldatttup->t_self, oldatttup, NULL);
163 /* keep system catalog indices current */
165 Relation irelations[Num_pg_attr_indices];
167 CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, irelations);
168 CatalogIndexInsert(irelations, Num_pg_attr_indices, attrelation, oldatttup);
169 CatalogCloseIndices(Num_pg_attr_indices, irelations);
172 heap_freetuple(oldatttup);
173 heap_close(attrelation, RowExclusiveLock);
177 * renamerel - change the name of a relation
180 renamerel(const char *oldrelname, const char *newrelname)
183 Relation targetrelation;
184 Relation relrelation; /* for RELATION relation */
188 char oldpath[MAXPGPATH],
190 toldpath[MAXPGPATH + 10],
191 tnewpath[MAXPGPATH + 10];
192 Relation irelations[Num_pg_class_indices];
194 if (!allowSystemTableMods && IsSystemRelationName(oldrelname))
195 elog(ERROR, "renamerel: system relation \"%s\" not renamed",
198 if (!allowSystemTableMods && IsSystemRelationName(newrelname))
199 elog(ERROR, "renamerel: Illegal class name: \"%s\" -- pg_ is reserved for system catalogs",
203 * Instead of using heap_openr(), do it the hard way, so that we
204 * can rename indexes as well as regular relations.
206 targetrelation = RelationNameGetRelation(oldrelname);
208 if (!RelationIsValid(targetrelation))
209 elog(ERROR, "Relation '%s' does not exist", oldrelname);
212 * Grab an exclusive lock on the target table, which we will NOT
213 * release until end of transaction.
215 LockRelation(targetrelation, AccessExclusiveLock);
218 * RENAME TABLE within a transaction block is dangerous, because
219 * if the transaction is later rolled back we have no way to
220 * undo the rename of the relation's physical file. For now, allow it
221 * but emit a warning message.
222 * Someday we might want to consider postponing the physical rename
223 * until transaction commit, but that's a lot of work...
224 * The only case that actually works right is for relations created
225 * in the current transaction, since the post-abort state would be that
226 * they don't exist anyway. So, no warning in that case.
229 if (IsTransactionBlock() && !targetrelation->rd_myxactonly)
230 elog(NOTICE, "Caution: RENAME TABLE cannot be rolled back, so don't abort now");
232 reloid = RelationGetRelid(targetrelation);
233 relkind = targetrelation->rd_rel->relkind;
236 * Flush all blocks of the relation out of the buffer pool. We need
237 * this because the blocks are marked with the relation's name as well
238 * as OID. If some backend tries to write a dirty buffer with
239 * mdblindwrt after we've renamed the physical file, we'll be in big
242 * Since we hold the exclusive lock on the relation, we don't have to
243 * worry about more blocks being read in while we finish the rename.
245 if (FlushRelationBuffers(targetrelation, (BlockNumber) 0) < 0)
246 elog(ERROR, "renamerel: unable to flush relation from buffer pool");
249 * Make sure smgr and lower levels close the relation's files. (Next
250 * access to rel will reopen them.)
252 * Note: we rely on shared cache invalidation message to make other
253 * backends close and re-open the files.
255 smgrclose(DEFAULT_SMGR, targetrelation);
258 * Close rel, but keep exclusive lock!
260 heap_close(targetrelation, NoLock);
263 * Flush the relcache entry (easier than trying to change it at exactly
264 * the right instant). It'll get rebuilt on next access to relation.
266 * XXX What if relation is myxactonly?
268 targetrelation = NULL; /* make sure I don't touch it again */
269 RelationIdInvalidateRelationCacheByRelationId(reloid);
272 * Find relation's pg_class tuple, and make sure newrelname isn't in
275 relrelation = heap_openr(RelationRelationName, RowExclusiveLock);
277 oldreltup = SearchSysCacheTupleCopy(RELNAME,
278 PointerGetDatum(oldrelname),
280 if (!HeapTupleIsValid(oldreltup))
281 elog(ERROR, "renamerel: relation \"%s\" does not exist", oldrelname);
283 if (RelnameFindRelid(newrelname) != InvalidOid)
284 elog(ERROR, "renamerel: relation \"%s\" exists", newrelname);
287 * Update pg_class tuple with new relname.
289 StrNCpy(NameStr(((Form_pg_class) GETSTRUCT(oldreltup))->relname),
290 newrelname, NAMEDATALEN);
292 heap_update(relrelation, &oldreltup->t_self, oldreltup, NULL);
294 /* keep the system catalog indices current */
295 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, irelations);
296 CatalogIndexInsert(irelations, Num_pg_class_indices, relrelation, oldreltup);
297 CatalogCloseIndices(Num_pg_class_indices, irelations);
299 heap_close(relrelation, NoLock);
302 * Also rename the associated type, if any.
304 if (relkind != RELKIND_INDEX)
305 TypeRename(oldrelname, newrelname);
308 * Perform physical rename of files. If this fails, we haven't yet
309 * done anything irreversible. NOTE that this MUST be the last step;
310 * an error occurring afterwards would leave the relation hosed!
312 * XXX smgr.c ought to provide an interface for this; doing it directly
315 strcpy(oldpath, relpath(oldrelname));
316 strcpy(newpath, relpath(newrelname));
317 if (rename(oldpath, newpath) < 0)
318 elog(ERROR, "renamerel: unable to rename %s to %s: %m",
321 /* rename additional segments of relation, too */
324 sprintf(toldpath, "%s.%d", oldpath, i);
325 sprintf(tnewpath, "%s.%d", newpath, i);
326 if (rename(toldpath, tnewpath) < 0)
328 /* expected case is that there's not another segment file */
331 /* otherwise we're up the creek... */
332 elog(ERROR, "renamerel: unable to rename %s to %s: %m",