aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2017-05-26 15:16:59 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2017-05-26 15:16:59 -0400
commitacab87ece1a471290ff275541687dd5b843eec23 (patch)
tree69e0e9c1d32fbf1588d40792914a82fe89bd7730 /src
parent5886c7d5893f88efe5de0bf78d9a1439d09c004a (diff)
downloadpostgresql-acab87ece1a471290ff275541687dd5b843eec23.tar.gz
postgresql-acab87ece1a471290ff275541687dd5b843eec23.zip
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
Diffstat (limited to 'src')
-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 4b2d281f2c9..525273ef3ec 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -700,6 +700,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);
@@ -713,13 +714,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);
@@ -734,8 +750,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 3886d4e6bc4..de9677c5b76 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 d01b8b0be3f..fe78067ae75 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)