/*
* Common checks on switching namespaces.
*
- * We complain if (1) the old and new namespaces are the same, (2) either the
- * old or new namespaces is a temporary schema (or temporary toast schema), or
- * (3) either the old or new namespaces is the TOAST schema.
+ * We complain if (1) either the old or new namespaces is a temporary schema
+ * (or temporary toast schema), or (3) either the old or new namespaces is the
+ * TOAST schema.
*/
void
-CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid, Oid objid)
+CheckSetNamespace(Oid oldNspOid, Oid nspOid)
{
- if (oldNspOid == nspOid)
- ereport(ERROR,
- (classid == RelationRelationId ?
- errcode(ERRCODE_DUPLICATE_TABLE) :
- classid == ProcedureRelationId ?
- errcode(ERRCODE_DUPLICATE_FUNCTION) :
- errcode(ERRCODE_DUPLICATE_OBJECT),
- errmsg("%s is already in schema \"%s\"",
- getObjectDescriptionOids(classid, objid),
- get_namespace_name(nspOid))));
-
/* disallow renaming into or out of temp schemas */
if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
ereport(ERROR,
if (object_address_present(&thisobj, objsMoved))
continue;
- if (conform->connamespace == oldNspId)
+ /* Don't update if the object is already part of the namespace */
+ if (conform->connamespace == oldNspId && oldNspId != newNspId)
{
tup = heap_copytuple(tup);
conform = (Form_pg_constraint) GETSTRUCT(tup);
Assert(!isnull);
oldNspOid = DatumGetObjectId(namespace);
+ /*
+ * If the object is already in the correct namespace, we don't need
+ * to do anything except fire the object access hook.
+ */
+ if (oldNspOid == nspOid)
+ {
+ InvokeObjectPostAlterHook(classId, objid, 0);
+ return oldNspOid;
+ }
+
/* Check basic namespace related issues */
- CheckSetNamespace(oldNspOid, nspOid, classId, objid);
+ CheckSetNamespace(oldNspOid, nspOid);
/* Permission checks ... superusers can always do it */
if (!superuser())
nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
/* common checks on switching namespaces */
- CheckSetNamespace(oldNspOid, nspOid, RelationRelationId, relid);
+ CheckSetNamespace(oldNspOid, nspOid);
objsMoved = new_object_addresses();
AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
HeapTuple classTup;
Form_pg_class classForm;
ObjectAddress thisobj;
+ bool already_done = false;
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
if (!HeapTupleIsValid(classTup))
thisobj.objectSubId = 0;
/*
- * Do nothing when there's nothing to do.
+ * If the object has already been moved, don't move it again. If it's
+ * already in the right place, don't move it, but still fire the object
+ * access hook.
*/
- if (!object_address_present(&thisobj, objsMoved))
+ already_done = object_address_present(&thisobj, objsMoved);
+ if (!already_done && oldNspOid != newNspOid)
{
/* check for duplicate name (more friendly than unique-index failure) */
if (get_relname_relid(NameStr(classForm->relname),
newNspOid) != 1)
elog(ERROR, "failed to change schema dependency for relation \"%s\"",
NameStr(classForm->relname));
-
+ }
+ if (!already_done)
+ {
add_exact_object_address(&thisobj, objsMoved);
InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
oldNspOid = typform->typnamespace;
arrayOid = typform->typarray;
- /* common checks on switching namespaces */
- CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid);
+ /* If the type is already there, we scan skip these next few checks. */
+ if (oldNspOid != nspOid)
+ {
+ /* common checks on switching namespaces */
+ CheckSetNamespace(oldNspOid, nspOid);
- /* check for duplicate name (more friendly than unique-index failure) */
- if (SearchSysCacheExists2(TYPENAMENSP,
- CStringGetDatum(NameStr(typform->typname)),
- ObjectIdGetDatum(nspOid)))
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_OBJECT),
- errmsg("type \"%s\" already exists in schema \"%s\"",
- NameStr(typform->typname),
- get_namespace_name(nspOid))));
+ /* check for duplicate name (more friendly than unique-index failure) */
+ if (SearchSysCacheExists2(TYPENAMENSP,
+ CStringGetDatum(NameStr(typform->typname)),
+ ObjectIdGetDatum(nspOid)))
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("type \"%s\" already exists in schema \"%s\"",
+ NameStr(typform->typname),
+ get_namespace_name(nspOid))));
+ }
/* Detect whether type is a composite type (but not a table rowtype) */
isCompositeType =
format_type_be(typeOid)),
errhint("Use ALTER TABLE instead.")));
- /* OK, modify the pg_type row */
+ if (oldNspOid != nspOid)
+ {
+ /* OK, modify the pg_type row */
- /* tup is a copy, so we can scribble directly on it */
- typform->typnamespace = nspOid;
+ /* tup is a copy, so we can scribble directly on it */
+ typform->typnamespace = nspOid;
- simple_heap_update(rel, &tup->t_self, tup);
- CatalogUpdateIndexes(rel, tup);
+ simple_heap_update(rel, &tup->t_self, tup);
+ CatalogUpdateIndexes(rel, tup);
+ }
/*
* Composite types have pg_class entries.
* Update dependency on schema, if any --- a table rowtype has not got
* one, and neither does an implicit array.
*/
- if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
+ if (oldNspOid != nspOid &&
+ (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
!isImplicitArray)
if (changeDependencyFor(TypeRelationId, typeOid,
NamespaceRelationId, oldNspOid, nspOid) != 1)
extern Oid get_namespace_oid(const char *nspname, bool missing_ok);
extern Oid LookupCreationNamespace(const char *nspname);
-extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid,
- Oid objid);
+extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid);
extern Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p);
extern RangeVar *makeRangeVarFromNameList(List *names);
extern char *NameListToString(List *names);
ALTER FUNCTION alt_func2(int) OWNER TO regtest_alter_user2; -- failed (no role membership)
ERROR: must be member of role "regtest_alter_user2"
ALTER FUNCTION alt_func2(int) OWNER TO regtest_alter_user3; -- OK
+ALTER FUNCTION alt_func2(int) SET SCHEMA alt_nsp1; -- OK, already there
ALTER FUNCTION alt_func2(int) SET SCHEMA alt_nsp2; -- OK
ALTER AGGREGATE alt_agg1(int) RENAME TO alt_agg2; -- failed (name conflict)
ERROR: function alt_agg2(integer) already exists in schema "alt_nsp1"
create text search dictionary alter1.dict(template = alter1.tmpl);
insert into alter1.t1(f2) values(11);
insert into alter1.t1(f2) values(12);
+alter table alter1.t1 set schema alter1; -- no-op, same schema
alter table alter1.t1 set schema alter2;
alter table alter1.v1 set schema alter2;
alter function alter1.plus1(int) set schema alter2;
alter operator family alter1.ctype_hash_ops using hash set schema alter2;
alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
+alter type alter1.ctype set schema alter1; -- no-op, same schema
alter type alter1.ctype set schema alter2;
alter conversion alter1.ascii_to_utf8 set schema alter2;
alter text search parser alter1.prs set schema alter2;
-- XXX: it's currently impossible to move relations out of pg_catalog
ALTER TABLE new_system_table SET SCHEMA public;
ERROR: cannot remove dependency on schema pg_catalog because it is a system object
--- move back, will currently error out, already there
+-- move back, will be ignored -- already there
ALTER TABLE new_system_table SET SCHEMA pg_catalog;
-ERROR: table new_system_table is already in schema "pg_catalog"
ALTER TABLE new_system_table RENAME TO old_system_table;
CREATE INDEX old_system_table__othercol ON old_system_table (othercol);
INSERT INTO old_system_table(othercol) VALUES ('somedata'), ('otherdata');
ALTER FUNCTION alt_func1(int) RENAME TO alt_func3; -- OK
ALTER FUNCTION alt_func2(int) OWNER TO regtest_alter_user2; -- failed (no role membership)
ALTER FUNCTION alt_func2(int) OWNER TO regtest_alter_user3; -- OK
+ALTER FUNCTION alt_func2(int) SET SCHEMA alt_nsp1; -- OK, already there
ALTER FUNCTION alt_func2(int) SET SCHEMA alt_nsp2; -- OK
ALTER AGGREGATE alt_agg1(int) RENAME TO alt_agg2; -- failed (name conflict)
insert into alter1.t1(f2) values(11);
insert into alter1.t1(f2) values(12);
+alter table alter1.t1 set schema alter1; -- no-op, same schema
alter table alter1.t1 set schema alter2;
alter table alter1.v1 set schema alter2;
alter function alter1.plus1(int) set schema alter2;
alter operator family alter1.ctype_hash_ops using hash set schema alter2;
alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
+alter type alter1.ctype set schema alter1; -- no-op, same schema
alter type alter1.ctype set schema alter2;
alter conversion alter1.ascii_to_utf8 set schema alter2;
alter text search parser alter1.prs set schema alter2;
-- XXX: it's currently impossible to move relations out of pg_catalog
ALTER TABLE new_system_table SET SCHEMA public;
--- move back, will currently error out, already there
+-- move back, will be ignored -- already there
ALTER TABLE new_system_table SET SCHEMA pg_catalog;
ALTER TABLE new_system_table RENAME TO old_system_table;
CREATE INDEX old_system_table__othercol ON old_system_table (othercol);