HeapTuple tuple;
Form_pg_type typ;
Oid arrayOid;
+ Oid oldTypeOid;
pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
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);
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);
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;
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)