#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
+#include "commands/defrem.h"
#include "commands/typecmds.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "utils/rel.h"
#include "utils/syscache.h"
-static char *makeUniqueTypeName(const char *typeName, Oid typeNamespace,
- bool tryOriginal);
-
/* Potentially set by pg_upgrade_support functions */
Oid binary_upgrade_next_pg_type_oid = InvalidOid;
char *
makeArrayTypeName(const char *typeName, Oid typeNamespace)
{
- char *arr;
+ char *arr_name;
+ int pass = 0;
+ char suffix[NAMEDATALEN];
- arr = makeUniqueTypeName(typeName, typeNamespace, false);
- if (arr == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_OBJECT),
- errmsg("could not form array type name for type \"%s\"",
- typeName)));
+ /*
+ * Per ancient Postgres tradition, array type names are made by prepending
+ * an underscore to the base type name. Much client code knows that
+ * convention, so don't muck with it. However, the tradition is less
+ * clear about what to do in the corner cases where the resulting name is
+ * too long or conflicts with an existing name. Our current rules are (1)
+ * truncate the base name on the right as needed, and (2) if there is a
+ * conflict, append another underscore and some digits chosen to make it
+ * unique. This is similar to what ChooseRelationName() does.
+ *
+ * The actual name generation can be farmed out to makeObjectName() by
+ * giving it an empty first name component.
+ */
+
+ /* First, try with no numeric suffix */
+ arr_name = makeObjectName("", typeName, NULL);
+
+ for (;;)
+ {
+ if (!SearchSysCacheExists2(TYPENAMENSP,
+ CStringGetDatum(arr_name),
+ ObjectIdGetDatum(typeNamespace)))
+ break;
+
+ /* That attempt conflicted. Prepare a new name with some digits. */
+ pfree(arr_name);
+ snprintf(suffix, sizeof(suffix), "%d", ++pass);
+ arr_name = makeObjectName("", typeName, suffix);
+ }
- return arr;
+ return arr_name;
}
return pstrdup(buf);
}
-
-/*
- * makeUniqueTypeName
- * Generate a unique name for a prospective new type
- *
- * Given a typeName, return a new palloc'ed name by prepending underscores
- * until a non-conflicting name results.
- *
- * If tryOriginal, first try with zero underscores.
- */
-static char *
-makeUniqueTypeName(const char *typeName, Oid typeNamespace, bool tryOriginal)
-{
- int i;
- int namelen;
- char dest[NAMEDATALEN];
-
- Assert(strlen(typeName) <= NAMEDATALEN - 1);
-
- if (tryOriginal &&
- !SearchSysCacheExists2(TYPENAMENSP,
- CStringGetDatum(typeName),
- ObjectIdGetDatum(typeNamespace)))
- return pstrdup(typeName);
-
- /*
- * The idea is to prepend underscores as needed until we make a name that
- * doesn't collide with anything ...
- */
- namelen = strlen(typeName);
- for (i = 1; i < NAMEDATALEN - 1; i++)
- {
- dest[i - 1] = '_';
- strlcpy(dest + i, typeName, NAMEDATALEN - i);
- if (namelen + i >= NAMEDATALEN)
- truncate_identifier(dest, NAMEDATALEN, false);
-
- if (!SearchSysCacheExists2(TYPENAMENSP,
- CStringGetDatum(dest),
- ObjectIdGetDatum(typeNamespace)))
- return pstrdup(dest);
- }
-
- return NULL;
-}