diff --git a/src/backend/catalog/pg_enum.c b/src/backend/catalog/pg_enum.c index fe61d4d..52c1271 100644 --- a/src/backend/catalog/pg_enum.c +++ b/src/backend/catalog/pg_enum.c @@ -28,6 +28,8 @@ #include "utils/builtins.h" #include "utils/catcache.h" #include "utils/fmgroids.h" +#include "utils/hsearch.h" +#include "utils/memutils.h" #include "utils/syscache.h" #include "utils/tqual.h" @@ -38,6 +40,9 @@ Oid binary_upgrade_next_pg_enum_oid = InvalidOid; static void RenumberEnumType(Relation pg_enum, HeapTuple *existing, int nelems); static int sort_order_cmp(const void *p1, const void *p2); +/* hash table of values added in current transaction by AddEnumLabel */ + +static HTAB *enum_blacklist = NULL; /* * EnumValuesCreate @@ -460,8 +465,44 @@ restart: heap_freetuple(enum_tup); heap_close(pg_enum, RowExclusiveLock); + + /* set up blacklist hash if required */ + if (enum_blacklist == NULL) + { + HASHCTL hash_ctl; + memset(&hash_ctl, 0, sizeof(hash_ctl)); + hash_ctl.keysize = sizeof(Oid); + hash_ctl.entrysize = sizeof(Oid); + hash_ctl.hcxt = CurTransactionContext; + enum_blacklist = hash_create("Enum blacklist for current transaction", + 32, + &hash_ctl, + HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); + + } + + /* and add the new value to the blacklist */ + + (void) hash_search(enum_blacklist, &newOid, HASH_ENTER, NULL); } +bool +EnumBlacklisted(Oid enum_id) +{ + bool found; + + if (enum_blacklist == NULL) + return false; + + (void) hash_search(enum_blacklist, &enum_id, HASH_FIND, &found); + return found; +} + +void +InitEnumBlacklist(void) +{ + enum_blacklist = NULL; +} /* * RenameEnumLabel diff --git a/src/backend/utils/adt/enum.c b/src/backend/utils/adt/enum.c index 973397c..a7ba3d0 100644 --- a/src/backend/utils/adt/enum.c +++ b/src/backend/utils/adt/enum.c @@ -76,6 +76,10 @@ check_safe_enum_use(HeapTuple enumval_tup) TransactionIdDidCommit(xmin)) return; + /* Check if the enum value is blacklisted. If not, it's safe */ + if (! EnumBlacklisted(HeapTupleGetOid(enumval_tup))) + return; + /* It is a new enum value, so check to see if the whole enum is new */ en = (Form_pg_enum) GETSTRUCT(enumval_tup); enumtyp_tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(en->enumtypid)); diff --git a/src/include/catalog/pg_enum.h b/src/include/catalog/pg_enum.h index 5938ba5..f8a492b 100644 --- a/src/include/catalog/pg_enum.h +++ b/src/include/catalog/pg_enum.h @@ -69,5 +69,7 @@ extern void AddEnumLabel(Oid enumTypeOid, const char *newVal, bool skipIfExists); extern void RenameEnumLabel(Oid enumTypeOid, const char *oldVal, const char *newVal); +extern bool EnumBlacklisted(Oid enum_id); +extern void InitEnumBlacklist(void); #endif /* PG_ENUM_H */