aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
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 04c10c6347b..6b0e4f4729f 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 c88fd768482..8aadbb88a34 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 c0e29720dc5..c41b48785b5 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)