public inbox for [email protected]
help / color / mirror / Atom feedFrom: Maksim Kita <[email protected]>
Subject: [PATCH] Allow alter type delete value in enum
Date: Wed, 7 Oct 2020 23:35:56 +0300
---
src/backend/catalog/pg_enum.c | 69 +++++++++++++++++++++++++++++++++
src/backend/commands/typecmds.c | 8 +++-
src/backend/parser/gram.y | 11 ++++++
src/backend/utils/adt/enum.c | 10 +++++
src/include/catalog/pg_enum.h | 2 +
5 files changed, 98 insertions(+), 2 deletions(-)
diff --git a/src/backend/catalog/pg_enum.c b/src/backend/catalog/pg_enum.c
index 27e4100a6f..907db93cf4 100644
--- a/src/backend/catalog/pg_enum.c
+++ b/src/backend/catalog/pg_enum.c
@@ -133,6 +133,7 @@ EnumValuesCreate(Oid enumTypeOid, List *vals)
values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(elemno + 1);
namestrcpy(&enumlabel, lab);
values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel);
+ values[Anum_pg_enum_isdropped - 1] = false;
tup = heap_form_tuple(RelationGetDescr(pg_enum), values, nulls);
@@ -485,6 +486,7 @@ restart:
values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(newelemorder);
namestrcpy(&enumlabel, newVal);
values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel);
+ values[Anum_pg_enum_isdropped - 1] = false;
enum_tup = heap_form_tuple(RelationGetDescr(pg_enum), values, nulls);
CatalogTupleInsert(pg_enum, enum_tup);
heap_freetuple(enum_tup);
@@ -583,6 +585,73 @@ RenameEnumLabel(Oid enumTypeOid,
table_close(pg_enum, RowExclusiveLock);
}
+extern void RemoveEnumLabel(Oid enumTypeOid, const char *val)
+{
+ Relation pg_enum;
+ HeapTuple enum_tup;
+ Form_pg_enum en;
+ CatCList *list;
+ int nelems;
+ HeapTuple old_tup;
+ int i;
+
+ /* check length of new label is ok */
+ if (strlen(val) > (NAMEDATALEN - 1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_NAME),
+ errmsg("invalid enum label \"%s\"", val),
+ errdetail("Labels must be %d characters or less.",
+ NAMEDATALEN - 1)));
+
+ /*
+ * Acquire a lock on the enum type, which we won't release until commit.
+ * This ensures that two backends aren't concurrently modifying the same
+ * enum type. Since we are not changing the type's sort order, this is
+ * probably not really necessary, but there seems no reason not to take
+ * the lock to be sure.
+ */
+ LockDatabaseObject(TypeRelationId, enumTypeOid, 0, ExclusiveLock);
+
+ pg_enum = table_open(EnumRelationId, RowExclusiveLock);
+
+ /* Get the list of existing members of the enum */
+ list = SearchSysCacheList1(ENUMTYPOIDNAME,
+ ObjectIdGetDatum(enumTypeOid));
+ nelems = list->n_members;
+
+ /*
+ * Check if the label is in use. (The unique index on pg_enum would catch that anyway, but we
+ * prefer a friendlier error message.)
+ */
+ for (i = 0; i < nelems; i++)
+ {
+ enum_tup = &(list->members[i]->tuple);
+ en = (Form_pg_enum) GETSTRUCT(enum_tup);
+ if (strcmp(NameStr(en->enumlabel), val) == 0)
+ {
+ old_tup = enum_tup;
+ break;
+ }
+ }
+ if (!old_tup)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("\"%s\" is not an existing enum label",
+ val)));
+
+ /* OK, make a writable copy of old tuple */
+ enum_tup = heap_copytuple(old_tup);
+ en = (Form_pg_enum) GETSTRUCT(enum_tup);
+
+ ReleaseCatCacheList(list);
+
+ /* Update the pg_enum entry */
+ en->isdropped = true;
+ CatalogTupleUpdate(pg_enum, &enum_tup->t_self, enum_tup);
+ heap_freetuple(enum_tup);
+
+ table_close(pg_enum, RowExclusiveLock);
+}
/*
* Test if the given enum value is on the blacklist
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 483bb65ddc..b9b3e18a94 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -1232,13 +1232,17 @@ AlterEnum(AlterEnumStmt *stmt)
ReleaseSysCache(tup);
- if (stmt->oldVal)
+ if (stmt->oldVal && stmt->newVal)
{
/* Rename an existing label */
RenameEnumLabel(enum_type_oid, stmt->oldVal, stmt->newVal);
}
- else
+ else if (stmt->oldVal)
{
+ /* Delete an existing label */
+ RemoveEnumLabel(enum_type_oid, stmt->oldVal);
+ }
+ else {
/* Add a new label */
AddEnumLabel(enum_type_oid, stmt->newVal,
stmt->newValNeighbor, stmt->newValIsAfter,
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 0d101d8171..82dd5147fa 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -5792,6 +5792,17 @@ AlterEnumStmt:
n->skipIfNewValExists = false;
$$ = (Node *) n;
}
+ | ALTER TYPE_P any_name DELETE_P VALUE_P Sconst
+ {
+ AlterEnumStmt *n = makeNode(AlterEnumStmt);
+ n->typeName = $3;
+ n->oldVal = $6;
+ n->newVal = NULL;
+ n->newValNeighbor = NULL;
+ n->newValIsAfter = false;
+ n->skipIfNewValExists = false;
+ $$ = (Node *) n;
+ }
;
opt_if_not_exists: IF_P NOT EXISTS { $$ = true; }
diff --git a/src/backend/utils/adt/enum.c b/src/backend/utils/adt/enum.c
index 5ead794e34..397c02fa69 100644
--- a/src/backend/utils/adt/enum.c
+++ b/src/backend/utils/adt/enum.c
@@ -113,6 +113,7 @@ enum_in(PG_FUNCTION_ARGS)
Oid enumtypoid = PG_GETARG_OID(1);
Oid enumoid;
HeapTuple tup;
+ Form_pg_enum en;
/* must check length to prevent Assert failure within SearchSysCache */
if (strlen(name) >= NAMEDATALEN)
@@ -132,6 +133,15 @@ enum_in(PG_FUNCTION_ARGS)
format_type_be(enumtypoid),
name)));
+ en = (Form_pg_enum) GETSTRUCT(tup);
+
+ if (en->isdropped)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("enum value is dropped %s: \"%s\"",
+ format_type_be(enumtypoid),
+ name)));
+
/* check it's safe to use in SQL */
check_safe_enum_use(tup);
diff --git a/src/include/catalog/pg_enum.h b/src/include/catalog/pg_enum.h
index b28d441ba7..6a7b00ffbe 100644
--- a/src/include/catalog/pg_enum.h
+++ b/src/include/catalog/pg_enum.h
@@ -34,6 +34,7 @@ CATALOG(pg_enum,3501,EnumRelationId)
Oid enumtypid; /* OID of owning enum type */
float4 enumsortorder; /* sort position of this enum value */
NameData enumlabel; /* text representation of enum value */
+ bool isdropped; /* is enum value dropped */
} FormData_pg_enum;
/* ----------------
@@ -53,6 +54,7 @@ extern void AddEnumLabel(Oid enumTypeOid, const char *newVal,
bool skipIfExists);
extern void RenameEnumLabel(Oid enumTypeOid,
const char *oldVal, const char *newVal);
+extern void RemoveEnumLabel(Oid enumTypeOid, const char *val);
extern bool EnumBlacklisted(Oid enum_id);
extern Size EstimateEnumBlacklistSpace(void);
extern void SerializeEnumBlacklist(void *space, Size size);
--
2.25.1
--qDbXVdCdHGoSgWSk--
view thread (5+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected]
Subject: Re: [PATCH] Allow alter type delete value in enum
In-Reply-To: <no-message-id-1864570@localhost>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox