Commit 94aced8c authored by Tom Lane's avatar Tom Lane

Move autogenerated array types out of the way during ALTER ... RENAME.

Commit 9aa3c782 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
parent 0461b66e
......@@ -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)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment