Skip to content

Commit 94aced8

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/0f4ade49-4f0b-a9a3-c120-7589f01d1eb8@2ndquadrant.com
1 parent 0461b66 commit 94aced8

File tree

3 files changed

+98
-9
lines changed

3 files changed

+98
-9
lines changed

src/backend/catalog/pg_type.c

+29-9
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,7 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
695695
HeapTuple tuple;
696696
Form_pg_type typ;
697697
Oid arrayOid;
698+
Oid oldTypeOid;
698699

699700
pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
700701

@@ -708,13 +709,28 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
708709

709710
arrayOid = typ->typarray;
710711

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

719735
/* OK, do the rename --- tuple is a copy, so OK to scribble on it */
720736
namestrcpy(&(typ->typname), newTypeName);
@@ -726,8 +742,12 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
726742
heap_freetuple(tuple);
727743
heap_close(pg_type_desc, RowExclusiveLock);
728744

729-
/* If the type has an array type, recurse to handle that */
730-
if (OidIsValid(arrayOid))
745+
/*
746+
* If the type has an array type, recurse to handle that. But we don't
747+
* need to do anything more if we already renamed that array type above
748+
* (which would happen when, eg, renaming "foo" to "_foo").
749+
*/
750+
if (OidIsValid(arrayOid) && arrayOid != oldTypeOid)
731751
{
732752
char *arrname = makeArrayTypeName(newTypeName, typeNamespace);
733753

src/test/regress/expected/alter_table.out

+49
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

+20
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)