Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 525780c

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 a561254 commit 525780c

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
@@ -683,6 +683,7 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
683683
HeapTuple tuple;
684684
Form_pg_type typ;
685685
Oid arrayOid;
686+
Oid oldTypeOid;
686687

687688
pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
688689

@@ -696,13 +697,28 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
696697

697698
arrayOid = typ->typarray;
698699

699-
/* Just to give a more friendly error than unique-index violation */
700-
if (SearchSysCacheExists2(TYPENAMENSP,
701-
CStringGetDatum(newTypeName),
702-
ObjectIdGetDatum(typeNamespace)))
703-
ereport(ERROR,
704-
(errcode(ERRCODE_DUPLICATE_OBJECT),
705-
errmsg("type \"%s\" already exists", newTypeName)));
700+
/* Check for a conflicting type name. */
701+
oldTypeOid = GetSysCacheOid2(TYPENAMENSP,
702+
CStringGetDatum(newTypeName),
703+
ObjectIdGetDatum(typeNamespace));
704+
705+
/*
706+
* If there is one, see if it's an autogenerated array type, and if so
707+
* rename it out of the way. (But we must skip that for a shell type
708+
* because moveArrayTypeName will do the wrong thing in that case.)
709+
* Otherwise, we can at least give a more friendly error than unique-index
710+
* violation.
711+
*/
712+
if (OidIsValid(oldTypeOid))
713+
{
714+
if (get_typisdefined(oldTypeOid) &&
715+
moveArrayTypeName(oldTypeOid, newTypeName, typeNamespace))
716+
/* successfully dodged the problem */ ;
717+
else
718+
ereport(ERROR,
719+
(errcode(ERRCODE_DUPLICATE_OBJECT),
720+
errmsg("type \"%s\" already exists", newTypeName)));
721+
}
706722

707723
/* OK, do the rename --- tuple is a copy, so OK to scribble on it */
708724
namestrcpy(&(typ->typname), newTypeName);
@@ -717,8 +733,12 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
717733
heap_freetuple(tuple);
718734
heap_close(pg_type_desc, RowExclusiveLock);
719735

720-
/* If the type has an array type, recurse to handle that */
721-
if (OidIsValid(arrayOid))
736+
/*
737+
* If the type has an array type, recurse to handle that. But we don't
738+
* need to do anything more if we already renamed that array type above
739+
* (which would happen when, eg, renaming "foo" to "_foo").
740+
*/
741+
if (OidIsValid(arrayOid) && arrayOid != oldTypeOid)
722742
{
723743
char *arrname = makeArrayTypeName(newTypeName, typeNamespace);
724744

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)