summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2017-05-26 19:16:59 +0000
committerTom Lane2017-05-26 19:16:59 +0000
commit94aced8cd0e229670877fe5c406a98d9a4f1b92a (patch)
tree99ad5e8370ef6a3f0f378293d7d3ff62716ee366
parent0461b66e361f56560aaa50e1bd006e36e8bedc6e (diff)
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/[email protected]
-rw-r--r--src/backend/catalog/pg_type.c38
-rw-r--r--src/test/regress/expected/alter_table.out49
-rw-r--r--src/test/regress/sql/alter_table.sql20
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)