Hi Jim,

On Mon, 25 Aug 2025 10:08:23 +0200
Jim Jones <jim.jo...@uni-muenster.de> wrote:

> Hi Yugo
> 
> On 03.07.25 17:04, Yugo Nagata wrote:
> > Currently, when creating an enum type, duplicate labels are caught by a 
> > unique
> > index on pg_enum, resulting in a generic error message. 
> >
> >  postgres=# create type t as enum ('a','b','a');
> >  ERROR:  duplicate key value violates unique constraint 
> > "pg_enum_typid_label_index"
> >  DETAIL:  Key (enumtypid, enumlabel)=(16418, a) already exists.
> >
> > I propose adding an explicit check for duplicate labels during enum 
> > creation,
> > so that a more user-friendly and descriptive error message can be produced,
> > similar to what is already done in ALTER TYPE ... ADD VALUE
> > or ALTER TYPE ... RENAME VALUE .. TO ....
> >  
> > With the attached patch applied, the error message becomes:
> >
> > ERROR:  label "a" used more than once
> >
> 
> The error message for already existing enum labels starts with "enum",
> e.g.  ERROR:  enum label "bar" already exists. So, perhaps this new
> error message should follow the same pattern?

Thank you for taking a look. That makes sense, so I updated the message to:

 ERROR:  enum label "a" used more than once


> I also wonder if we need to add tests for it, so that we make sure the
> new error is triggered prior to the generic one, e.g. in create_type.sql
> 
> -- check for duplicate enum entries
> CREATE TYPE den AS ENUM ('foo','bar','foo');
> CREATE TYPE en AS ENUM ('foo','bar');
> ALTER TYPE en ADD VALUE 'foo';
> ALTER TYPE en RENAME VALUE 'foo' TO 'bar';
> DROP TYPE en;

I also added a test for duplicate enum entries to enum.sql,
since tests for existing entries are already there.

Regards,
Yugo Nagata

-- 
Yugo Nagata <nag...@sraoss.co.jp>
>From 9b7392f7e26af0c6464731c42adc5b8b91a011f7 Mon Sep 17 00:00:00 2001
From: Yugo Nagata <nag...@sraoss.co.jp>
Date: Thu, 3 Jul 2025 23:45:40 +0900
Subject: [PATCH v2] Improve error message for duplicate labels in enum types

Previously, duplicate labels in an enum type were caught by a unique
index on pg_enum, resulting in a generic error message. This adds an
explicit check beforehand to produce a more user-friendly and descriptive
error message.
---
 src/backend/catalog/pg_enum.c      | 19 +++++++++++++++++++
 src/test/regress/expected/enum.out |  3 +++
 src/test/regress/sql/enum.sql      |  3 +++
 3 files changed, 25 insertions(+)

diff --git a/src/backend/catalog/pg_enum.c b/src/backend/catalog/pg_enum.c
index a1634e58eec..daa11d34976 100644
--- a/src/backend/catalog/pg_enum.c
+++ b/src/backend/catalog/pg_enum.c
@@ -164,6 +164,25 @@ EnumValuesCreate(Oid enumTypeOid, List *vals)
 	{
 		char	   *lab = strVal(lfirst(lc));
 		Name		enumlabel = palloc0(NAMEDATALEN);
+		ListCell   *lc2;
+
+		/*
+		 * Check for duplicate labels. The unique index on pg_enum would catch
+		 * that anyway, but we prefer a friendlier error message.
+		 */
+		foreach(lc2, vals)
+		{
+			char	   *lab2 = strVal(lfirst(lc2));
+
+			if (lc == lc2)
+				break;
+
+			if (strcmp(lab, lab2) == 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("enum label \"%s\" used more than once",
+								lab)));
+		}
 
 		/*
 		 * labels are stored in a name field, for easier syscache lookup, so
diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out
index 4d9f36d0d36..09201489080 100644
--- a/src/test/regress/expected/enum.out
+++ b/src/test/regress/expected/enum.out
@@ -52,6 +52,9 @@ hint           |
 sql_error_code | 22P02
 
 \x
+-- check for duplicate enum entries
+CREATE TYPE den AS ENUM ('foo','bar','foo');
+ERROR:  enum label "foo" used more than once
 --
 -- adding new values
 --
diff --git a/src/test/regress/sql/enum.sql b/src/test/regress/sql/enum.sql
index ecc4878a678..8f744c71bea 100644
--- a/src/test/regress/sql/enum.sql
+++ b/src/test/regress/sql/enum.sql
@@ -23,6 +23,9 @@ SELECT * FROM pg_input_error_info('mauve', 'rainbow');
 SELECT * FROM pg_input_error_info(repeat('too_long', 32), 'rainbow');
 \x
 
+-- check for duplicate enum entries
+CREATE TYPE den AS ENUM ('foo','bar','foo');
+
 --
 -- adding new values
 --
-- 
2.43.0

Reply via email to