Skip to content

Commit acab87e

Browse files
committed
Move autogenerated array types out of the way during ALTER ... RENAME.
Commit 9aa3c78 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]
1 parent 5886c7d commit acab87e

File tree

3 files changed

+98
-9
lines changed

3 files changed

+98
-9
lines changed

src/backend/catalog/pg_type.c

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,7 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
700700
HeapTuple tuple;
701701
Form_pg_type typ;
702702
Oid arrayOid;
703+
Oid oldTypeOid;
703704

704705
pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
705706

@@ -713,13 +714,28 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
713714

714715
arrayOid = typ->typarray;
715716

716-
/* Just to give a more friendly error than unique-index violation */
717-
if (SearchSysCacheExists2(TYPENAMENSP,
718-
CStringGetDatum(newTypeName),
719-
ObjectIdGetDatum(typeNamespace)))
720-
ereport(ERROR,
721-
(errcode(ERRCODE_DUPLICATE_OBJECT),
722-
errmsg("type \"%s\" already exists", newTypeName)));
717+
/* Check for a conflicting type name. */
718+
oldTypeOid = GetSysCacheOid2(TYPENAMENSP,
719+
CStringGetDatum(newTypeName),
720+
ObjectIdGetDatum(typeNamespace));
721+
722+
/*
723+
* If there is one, see if it's an autogenerated array type, and if so
724+
* rename it out of the way. (But we must skip that for a shell type
725+
* because moveArrayTypeName will do the wrong thing in that case.)
726+
* Otherwise, we can at least give a more friendly error than unique-index
727+
* violation.
728+
*/
729+
if (OidIsValid(oldTypeOid))
730+
{
731+
if (get_typisdefined(oldTypeOid) &&
732+
moveArrayTypeName(oldTypeOid, newTypeName, typeNamespace))
733+
/* successfully dodged the problem */ ;
734+
else
735+
ereport(ERROR,
736+
(errcode(ERRCODE_DUPLICATE_OBJECT),
737+
errmsg("type \"%s\" already exists", newTypeName)));
738+
}
723739

724740
/* OK, do the rename --- tuple is a copy, so OK to scribble on it */
725741
namestrcpy(&(typ->typname), newTypeName);
@@ -734,8 +750,12 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
734750
heap_freetuple(tuple);
735751
heap_close(pg_type_desc, RowExclusiveLock);
736752

737-
/* If the type has an array type, recurse to handle that */
738-
if (OidIsValid(arrayOid))
753+
/*
754+
* If the type has an array type, recurse to handle that. But we don't
755+
* need to do anything more if we already renamed that array type above
756+
* (which would happen when, eg, renaming "foo" to "_foo").
757+
*/
758+
if (OidIsValid(arrayOid) && arrayOid != oldTypeOid)
739759
{
740760
char *arrname = makeArrayTypeName(newTypeName, typeNamespace);
741761

src/test/regress/expected/alter_table.out

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,55 @@ SELECT * FROM tmp_new2;
128128

129129
DROP TABLE tmp_new;
130130
DROP TABLE tmp_new2;
131+
--
132+
-- check renaming to a table's array type's autogenerated name
133+
-- (the array type's name should get out of the way)
134+
--
135+
CREATE TABLE tmp_array (id int);
136+
CREATE TABLE tmp_array2 (id int);
137+
SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype;
138+
typname
139+
------------
140+
_tmp_array
141+
(1 row)
142+
143+
SELECT typname FROM pg_type WHERE oid = 'tmp_array2[]'::regtype;
144+
typname
145+
-------------
146+
_tmp_array2
147+
(1 row)
148+
149+
ALTER TABLE tmp_array2 RENAME TO _tmp_array;
150+
SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype;
151+
typname
152+
-------------
153+
__tmp_array
154+
(1 row)
155+
156+
SELECT typname FROM pg_type WHERE oid = '_tmp_array[]'::regtype;
157+
typname
158+
--------------
159+
___tmp_array
160+
(1 row)
161+
162+
DROP TABLE _tmp_array;
163+
DROP TABLE tmp_array;
164+
-- renaming to table's own array type's name is an interesting corner case
165+
CREATE TABLE tmp_array (id int);
166+
SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype;
167+
typname
168+
------------
169+
_tmp_array
170+
(1 row)
171+
172+
ALTER TABLE tmp_array RENAME TO _tmp_array;
173+
SELECT typname FROM pg_type WHERE oid = '_tmp_array[]'::regtype;
174+
typname
175+
-------------
176+
__tmp_array
177+
(1 row)
178+
179+
DROP TABLE _tmp_array;
131180
-- ALTER TABLE ... RENAME on non-table relations
132181
-- renaming indexes (FIXME: this should probably test the index's functionality)
133182
ALTER INDEX IF EXISTS __onek_unique1 RENAME TO tmp_onek_unique1;

src/test/regress/sql/alter_table.sql

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,26 @@ SELECT * FROM tmp_new2;
165165
DROP TABLE tmp_new;
166166
DROP TABLE tmp_new2;
167167

168+
--
169+
-- check renaming to a table's array type's autogenerated name
170+
-- (the array type's name should get out of the way)
171+
--
172+
CREATE TABLE tmp_array (id int);
173+
CREATE TABLE tmp_array2 (id int);
174+
SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype;
175+
SELECT typname FROM pg_type WHERE oid = 'tmp_array2[]'::regtype;
176+
ALTER TABLE tmp_array2 RENAME TO _tmp_array;
177+
SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype;
178+
SELECT typname FROM pg_type WHERE oid = '_tmp_array[]'::regtype;
179+
DROP TABLE _tmp_array;
180+
DROP TABLE tmp_array;
181+
182+
-- renaming to table's own array type's name is an interesting corner case
183+
CREATE TABLE tmp_array (id int);
184+
SELECT typname FROM pg_type WHERE oid = 'tmp_array[]'::regtype;
185+
ALTER TABLE tmp_array RENAME TO _tmp_array;
186+
SELECT typname FROM pg_type WHERE oid = '_tmp_array[]'::regtype;
187+
DROP TABLE _tmp_array;
168188

169189
-- ALTER TABLE ... RENAME on non-table relations
170190
-- renaming indexes (FIXME: this should probably test the index's functionality)

0 commit comments

Comments
 (0)