/* * RenameTypeInternal * This renames a type, as well as any associated array type. * * Caller must have already checked privileges. * * Currently this is used for renaming table rowtypes and for * ALTER TYPE RENAME TO command. */ void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace) { Relation pg_type_desc; HeapTuple tuple; Form_pg_type typ; Oid arrayOid; pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock); tuple = SearchSysCacheCopy(TYPEOID, ObjectIdGetDatum(typeOid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for type %u", typeOid); typ = (Form_pg_type) GETSTRUCT(tuple); /* We are not supposed to be changing schemas here */ Assert(typeNamespace == typ->typnamespace); arrayOid = typ->typarray; /* Just to give a more friendly error than unique-index violation */ if (SearchSysCacheExists(TYPENAMENSP, CStringGetDatum(newTypeName), ObjectIdGetDatum(typeNamespace), 0, 0)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("type \"%s\" already exists", newTypeName))); /* OK, do the rename --- tuple is a copy, so OK to scribble on it */ namestrcpy(&(typ->typname), newTypeName); simple_heap_update(pg_type_desc, &tuple->t_self, tuple); /* update the system catalog indexes */ CatalogUpdateIndexes(pg_type_desc, tuple); heap_freetuple(tuple); heap_close(pg_type_desc, RowExclusiveLock); /* If the type has an array type, recurse to handle that */ if (OidIsValid(arrayOid)) { char *arrname = makeArrayTypeName(newTypeName, typeNamespace); RenameTypeInternal(arrayOid, arrname, typeNamespace); pfree(arrname); } }
/* * moveArrayTypeName * - try to reassign an array type name that the user wants to use. * * The given type name has been discovered to already exist (with the given * OID). If it is an autogenerated array type, change the array type's name * to not conflict. This allows the user to create type "foo" followed by * type "_foo" without problems. (Of course, there are race conditions if * two backends try to create similarly-named types concurrently, but the * worst that can happen is an unnecessary failure --- anything we do here * will be rolled back if the type creation fails due to conflicting names.) * * Note that this must be called *before* calling makeArrayTypeName to * determine the new type's own array type name; else the latter will * certainly pick the same name. * * Returns TRUE if successfully moved the type, FALSE if not. * * We also return TRUE if the given type is a shell type. In this case * the type has not been renamed out of the way, but nonetheless it can * be expected that TypeCreate will succeed. This behavior is convenient * for most callers --- those that need to distinguish the shell-type case * must do their own typisdefined test. */ bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace) { Oid elemOid; char *newname; /* We need do nothing if it's a shell type. */ if (!get_typisdefined(typeOid)) return true; /* Can't change it if it's not an autogenerated array type. */ elemOid = get_element_type(typeOid); if (!OidIsValid(elemOid) || get_array_type(elemOid) != typeOid) return false; /* * OK, use makeArrayTypeName to pick an unused modification of the name. * Note that since makeArrayTypeName is an iterative process, this will * produce a name that it might have produced the first time, had the * conflicting type we are about to create already existed. */ newname = makeArrayTypeName(typeName, typeNamespace); /* Apply the rename */ RenameTypeInternal(typeOid, newname, typeNamespace); /* * We must bump the command counter so that any subsequent use of * makeArrayTypeName sees what we just did and doesn't pick the same name. */ CommandCounterIncrement(); pfree(newname); return true; }
/* * RenameTypeInternal * This renames a type, as well as any associated array type. * * Caller must have already checked privileges. * * Currently this is used for renaming table rowtypes and for * ALTER TYPE RENAME TO command. */ void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace) { Relation pg_type_desc; HeapTuple tuple; Form_pg_type typ; Oid arrayOid; Oid oldTypeOid; pg_type_desc = table_open(TypeRelationId, RowExclusiveLock); tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid)); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for type %u", typeOid); typ = (Form_pg_type) GETSTRUCT(tuple); /* We are not supposed to be changing schemas here */ Assert(typeNamespace == typ->typnamespace); arrayOid = typ->typarray; /* Check for a conflicting type name. */ oldTypeOid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum(newTypeName), ObjectIdGetDatum(typeNamespace)); /* * If there is one, see if it's an autogenerated array type, and if so * rename it out of the way. (But we must skip that for a shell type * because moveArrayTypeName will do the wrong thing in that case.) * Otherwise, we can at least give a more friendly error than unique-index * violation. */ if (OidIsValid(oldTypeOid)) { if (get_typisdefined(oldTypeOid) && moveArrayTypeName(oldTypeOid, newTypeName, typeNamespace)) /* successfully dodged the problem */ ; else ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("type \"%s\" already exists", newTypeName))); } /* OK, do the rename --- tuple is a copy, so OK to scribble on it */ namestrcpy(&(typ->typname), newTypeName); CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple); InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0); heap_freetuple(tuple); table_close(pg_type_desc, RowExclusiveLock); /* * If the type has an array type, recurse to handle that. But we don't * need to do anything more if we already renamed that array type above * (which would happen when, eg, renaming "foo" to "_foo"). */ if (OidIsValid(arrayOid) && arrayOid != oldTypeOid) { char *arrname = makeArrayTypeName(newTypeName, typeNamespace); RenameTypeInternal(arrayOid, arrname, typeNamespace); pfree(arrname); } }