From 94aced8cd0e229670877fe5c406a98d9a4f1b92a Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 26 May 2017 15:16:59 -0400 Subject: [PATCH] Move autogenerated array types out of the way during ALTER ... RENAME. Commit 9aa3c782c added code to allow CREATE TABLE/CREATE TYPE to not fail when the desired type name conflicts with an autogenerated array type, by dint of renaming the array type out of the way. But I (tgl) overlooked that the same case arises in ALTER TABLE/TYPE RENAME. Fix that too. Back-patch to all supported branches. Report and patch by Vik Fearing, modified a bit by me Discussion: https://postgr.es/m/0f4ade49-4f0b-a9a3-c120-7589f01d1eb8@2ndquadrant.com --- src/backend/catalog/pg_type.c | 38 +++++++++++++----- src/test/regress/expected/alter_table.out | 49 +++++++++++++++++++++++ src/test/regress/sql/alter_table.sql | 20 +++++++++ 3 files changed, 98 insertions(+), 9 deletions(-) diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index 04c10c6347..6b0e4f4729 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -695,6 +695,7 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace) HeapTuple tuple; Form_pg_type typ; Oid arrayOid; + Oid oldTypeOid; pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock); @@ -708,13 +709,28 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace) arrayOid = typ->typarray; - /* Just to give a more friendly error than unique-index violation */ - if (SearchSysCacheExists2(TYPENAMENSP, - CStringGetDatum(newTypeName), - ObjectIdGetDatum(typeNamespace))) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("type \"%s\" already exists", newTypeName))); + /* Check for a conflicting type name. */ + oldTypeOid = GetSysCacheOid2(TYPENAMENSP, + 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); @@ -726,8 +742,12 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace) heap_freetuple(tuple); heap_close(pg_type_desc, RowExclusiveLock); - /* If the type has an array type, recurse to handle that */ - if (OidIsValid(arrayOid)) + /* + * 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); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index c88fd76848..8aadbb88a3 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -128,6 +128,55 @@ SELECT * FROM tmp_new2; DROP TABLE tmp_new; DROP TABLE tmp_new2; +-- +-- check renaming to a table's array type's autogenerated name +-- (the array type's name should get out of the way) +-- +CREATE TABLE tmp_array (id int); +CREATE TABLE tmp_array2 (id int); +SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype; + typname +------------ + _tmp_array +(1 row) + +SELECT typname FROM pg_type WHERE oid = 'tmp_array2[]'::regtype; + typname +------------- + _tmp_array2 +(1 row) + +ALTER TABLE tmp_array2 RENAME TO _tmp_array; +SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype; + typname +------------- + __tmp_array +(1 row) + +SELECT typname FROM pg_type WHERE oid = '_tmp_array[]'::regtype; + typname +-------------- + ___tmp_array +(1 row) + +DROP TABLE _tmp_array; +DROP TABLE tmp_array; +-- renaming to table's own array type's name is an interesting corner case +CREATE TABLE tmp_array (id int); +SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype; + typname +------------ + _tmp_array +(1 row) + +ALTER TABLE tmp_array RENAME TO _tmp_array; +SELECT typname FROM pg_type WHERE oid = '_tmp_array[]'::regtype; + typname +------------- + __tmp_array +(1 row) + +DROP TABLE _tmp_array; -- ALTER TABLE ... RENAME on non-table relations -- renaming indexes (FIXME: this should probably test the index's functionality) ALTER INDEX IF EXISTS __onek_unique1 RENAME TO tmp_onek_unique1; diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index c0e29720dc..c41b48785b 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -165,6 +165,26 @@ SELECT * FROM tmp_new2; DROP TABLE tmp_new; DROP TABLE tmp_new2; +-- +-- check renaming to a table's array type's autogenerated name +-- (the array type's name should get out of the way) +-- +CREATE TABLE tmp_array (id int); +CREATE TABLE tmp_array2 (id int); +SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype; +SELECT typname FROM pg_type WHERE oid = 'tmp_array2[]'::regtype; +ALTER TABLE tmp_array2 RENAME TO _tmp_array; +SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype; +SELECT typname FROM pg_type WHERE oid = '_tmp_array[]'::regtype; +DROP TABLE _tmp_array; +DROP TABLE tmp_array; + +-- renaming to table's own array type's name is an interesting corner case +CREATE TABLE tmp_array (id int); +SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype; +ALTER TABLE tmp_array RENAME TO _tmp_array; +SELECT typname FROM pg_type WHERE oid = '_tmp_array[]'::regtype; +DROP TABLE _tmp_array; -- ALTER TABLE ... RENAME on non-table relations -- renaming indexes (FIXME: this should probably test the index's functionality) -- 2.40.0