mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
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:
@ -700,6 +700,7 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
|
|||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
Form_pg_type typ;
|
Form_pg_type typ;
|
||||||
Oid arrayOid;
|
Oid arrayOid;
|
||||||
|
Oid oldTypeOid;
|
||||||
|
|
||||||
pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
|
pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
|
||||||
|
|
||||||
@ -713,13 +714,28 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
|
|||||||
|
|
||||||
arrayOid = typ->typarray;
|
arrayOid = typ->typarray;
|
||||||
|
|
||||||
/* Just to give a more friendly error than unique-index violation */
|
/* Check for a conflicting type name. */
|
||||||
if (SearchSysCacheExists2(TYPENAMENSP,
|
oldTypeOid = GetSysCacheOid2(TYPENAMENSP,
|
||||||
CStringGetDatum(newTypeName),
|
CStringGetDatum(newTypeName),
|
||||||
ObjectIdGetDatum(typeNamespace)))
|
ObjectIdGetDatum(typeNamespace));
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
/*
|
||||||
errmsg("type \"%s\" already exists", newTypeName)));
|
* 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 */
|
/* OK, do the rename --- tuple is a copy, so OK to scribble on it */
|
||||||
namestrcpy(&(typ->typname), newTypeName);
|
namestrcpy(&(typ->typname), newTypeName);
|
||||||
@ -734,8 +750,12 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
|
|||||||
heap_freetuple(tuple);
|
heap_freetuple(tuple);
|
||||||
heap_close(pg_type_desc, RowExclusiveLock);
|
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);
|
char *arrname = makeArrayTypeName(newTypeName, typeNamespace);
|
||||||
|
|
||||||
|
@ -128,6 +128,55 @@ SELECT * FROM tmp_new2;
|
|||||||
|
|
||||||
DROP TABLE tmp_new;
|
DROP TABLE tmp_new;
|
||||||
DROP TABLE tmp_new2;
|
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
|
-- ALTER TABLE ... RENAME on non-table relations
|
||||||
-- renaming indexes (FIXME: this should probably test the index's functionality)
|
-- renaming indexes (FIXME: this should probably test the index's functionality)
|
||||||
ALTER INDEX IF EXISTS __onek_unique1 RENAME TO tmp_onek_unique1;
|
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_new;
|
||||||
DROP TABLE tmp_new2;
|
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
|
-- ALTER TABLE ... RENAME on non-table relations
|
||||||
-- renaming indexes (FIXME: this should probably test the index's functionality)
|
-- renaming indexes (FIXME: this should probably test the index's functionality)
|
||||||
|
Reference in New Issue
Block a user