Move autogenerated array types out of the way during ALTER ... RENAME.
Commit 9aa3c782c 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
This commit is contained in:
parent
0461b66e36
commit
94aced8cd0
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user