Skip to content

Commit 70988b7

Browse files
committed
Improve makeArrayTypeName's algorithm for choosing array type names.
As before, we start by prepending one underscore (truncating the base name if necessary). But if there is a conflict, then instead of prepending more and more underscores, append an underscore and some digits, in much the same way that ChooseRelationName does. While the previous logic could be driven to fail by creating a lot of types with long names differing only near the end, this version seems certain enough to eventually succeed that we can remove the failure code path that was there before. While at it, undo 6df7a96's decision to split this code out of makeArrayTypeName. That wasn't actually accomplishing anything, because no other function was using it --- and it would have been wrong to do so. The convention that a prefix "_" means an array, not something else, is too ancient to mess with. Andrey Lepikhov and Dmitry Koval, reviewed by Masahiko Sawada and myself Discussion: https://postgr.es/m/b84cd82c-cc67-198a-8b1c-60f44e1259ad@postgrespro.ru
1 parent 8bb3ad4 commit 70988b7

File tree

2 files changed

+37
-59
lines changed

2 files changed

+37
-59
lines changed

src/backend/catalog/pg_type.c

+34-56
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "catalog/pg_namespace.h"
2727
#include "catalog/pg_proc.h"
2828
#include "catalog/pg_type.h"
29+
#include "commands/defrem.h"
2930
#include "commands/typecmds.h"
3031
#include "mb/pg_wchar.h"
3132
#include "miscadmin.h"
@@ -37,9 +38,6 @@
3738
#include "utils/rel.h"
3839
#include "utils/syscache.h"
3940

40-
static char *makeUniqueTypeName(const char *typeName, Oid typeNamespace,
41-
bool tryOriginal);
42-
4341
/* Potentially set by pg_upgrade_support functions */
4442
Oid binary_upgrade_next_pg_type_oid = InvalidOid;
4543

@@ -815,16 +813,41 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
815813
char *
816814
makeArrayTypeName(const char *typeName, Oid typeNamespace)
817815
{
818-
char *arr;
816+
char *arr_name;
817+
int pass = 0;
818+
char suffix[NAMEDATALEN];
819819

820-
arr = makeUniqueTypeName(typeName, typeNamespace, false);
821-
if (arr == NULL)
822-
ereport(ERROR,
823-
(errcode(ERRCODE_DUPLICATE_OBJECT),
824-
errmsg("could not form array type name for type \"%s\"",
825-
typeName)));
820+
/*
821+
* Per ancient Postgres tradition, array type names are made by prepending
822+
* an underscore to the base type name. Much client code knows that
823+
* convention, so don't muck with it. However, the tradition is less
824+
* clear about what to do in the corner cases where the resulting name is
825+
* too long or conflicts with an existing name. Our current rules are (1)
826+
* truncate the base name on the right as needed, and (2) if there is a
827+
* conflict, append another underscore and some digits chosen to make it
828+
* unique. This is similar to what ChooseRelationName() does.
829+
*
830+
* The actual name generation can be farmed out to makeObjectName() by
831+
* giving it an empty first name component.
832+
*/
833+
834+
/* First, try with no numeric suffix */
835+
arr_name = makeObjectName("", typeName, NULL);
836+
837+
for (;;)
838+
{
839+
if (!SearchSysCacheExists2(TYPENAMENSP,
840+
CStringGetDatum(arr_name),
841+
ObjectIdGetDatum(typeNamespace)))
842+
break;
843+
844+
/* That attempt conflicted. Prepare a new name with some digits. */
845+
pfree(arr_name);
846+
snprintf(suffix, sizeof(suffix), "%d", ++pass);
847+
arr_name = makeObjectName("", typeName, suffix);
848+
}
826849

827-
return arr;
850+
return arr_name;
828851
}
829852

830853

@@ -931,48 +954,3 @@ makeMultirangeTypeName(const char *rangeTypeName, Oid typeNamespace)
931954

932955
return pstrdup(buf);
933956
}
934-
935-
/*
936-
* makeUniqueTypeName
937-
* Generate a unique name for a prospective new type
938-
*
939-
* Given a typeName, return a new palloc'ed name by prepending underscores
940-
* until a non-conflicting name results.
941-
*
942-
* If tryOriginal, first try with zero underscores.
943-
*/
944-
static char *
945-
makeUniqueTypeName(const char *typeName, Oid typeNamespace, bool tryOriginal)
946-
{
947-
int i;
948-
int namelen;
949-
char dest[NAMEDATALEN];
950-
951-
Assert(strlen(typeName) <= NAMEDATALEN - 1);
952-
953-
if (tryOriginal &&
954-
!SearchSysCacheExists2(TYPENAMENSP,
955-
CStringGetDatum(typeName),
956-
ObjectIdGetDatum(typeNamespace)))
957-
return pstrdup(typeName);
958-
959-
/*
960-
* The idea is to prepend underscores as needed until we make a name that
961-
* doesn't collide with anything ...
962-
*/
963-
namelen = strlen(typeName);
964-
for (i = 1; i < NAMEDATALEN - 1; i++)
965-
{
966-
dest[i - 1] = '_';
967-
strlcpy(dest + i, typeName, NAMEDATALEN - i);
968-
if (namelen + i >= NAMEDATALEN)
969-
truncate_identifier(dest, NAMEDATALEN, false);
970-
971-
if (!SearchSysCacheExists2(TYPENAMENSP,
972-
CStringGetDatum(dest),
973-
ObjectIdGetDatum(typeNamespace)))
974-
return pstrdup(dest);
975-
}
976-
977-
return NULL;
978-
}

src/test/regress/expected/alter_table.out

+3-3
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,9 @@ SELECT typname FROM pg_type WHERE oid = 'attmp_array[]'::regtype;
197197
(1 row)
198198

199199
SELECT typname FROM pg_type WHERE oid = '_attmp_array[]'::regtype;
200-
typname
201-
----------------
202-
___attmp_array
200+
typname
201+
-----------------
202+
__attmp_array_1
203203
(1 row)
204204

205205
DROP TABLE _attmp_array;

0 commit comments

Comments
 (0)