|
28 | 28 | #include"utils/builtins.h"
|
29 | 29 | #include"utils/catcache.h"
|
30 | 30 | #include"utils/fmgroids.h"
|
| 31 | +#include"utils/hsearch.h" |
| 32 | +#include"utils/memutils.h" |
31 | 33 | #include"utils/syscache.h"
|
32 | 34 | #include"utils/tqual.h"
|
33 | 35 |
|
34 | 36 |
|
35 | 37 | /* Potentially set by pg_upgrade_support functions */
|
36 | 38 | Oidbinary_upgrade_next_pg_enum_oid=InvalidOid;
|
37 | 39 |
|
| 40 | +/* |
| 41 | + * Hash table of enum value OIDs created during the current transaction by |
| 42 | + * AddEnumLabel. We disallow using these values until the transaction is |
| 43 | + * committed; otherwise, they might get into indexes where we can't clean |
| 44 | + * them up, and then if the transaction rolls back we have a broken index. |
| 45 | + * (See comments for check_safe_enum_use() in enum.c.) Values created by |
| 46 | + * EnumValuesCreate are *not* blacklisted; we assume those are created during |
| 47 | + * CREATE TYPE, so they can't go away unless the enum type itself does. |
| 48 | + */ |
| 49 | +staticHTAB*enum_blacklist=NULL; |
| 50 | + |
38 | 51 | staticvoidRenumberEnumType(Relationpg_enum,HeapTuple*existing,intnelems);
|
39 | 52 | staticintsort_order_cmp(constvoid*p1,constvoid*p2);
|
40 | 53 |
|
@@ -460,6 +473,24 @@ AddEnumLabel(Oid enumTypeOid,
|
460 | 473 | heap_freetuple(enum_tup);
|
461 | 474 |
|
462 | 475 | heap_close(pg_enum,RowExclusiveLock);
|
| 476 | + |
| 477 | +/* Set up the blacklist hash if not already done in this transaction */ |
| 478 | +if (enum_blacklist==NULL) |
| 479 | +{ |
| 480 | +HASHCTLhash_ctl; |
| 481 | + |
| 482 | +memset(&hash_ctl,0,sizeof(hash_ctl)); |
| 483 | +hash_ctl.keysize=sizeof(Oid); |
| 484 | +hash_ctl.entrysize=sizeof(Oid); |
| 485 | +hash_ctl.hcxt=TopTransactionContext; |
| 486 | +enum_blacklist=hash_create("Enum value blacklist", |
| 487 | +32, |
| 488 | +&hash_ctl, |
| 489 | +HASH_ELEM |HASH_BLOBS |HASH_CONTEXT); |
| 490 | +} |
| 491 | + |
| 492 | +/* Add the new value to the blacklist */ |
| 493 | +(void)hash_search(enum_blacklist,&newOid,HASH_ENTER,NULL); |
463 | 494 | }
|
464 | 495 |
|
465 | 496 |
|
@@ -547,6 +578,39 @@ RenameEnumLabel(Oid enumTypeOid,
|
547 | 578 | }
|
548 | 579 |
|
549 | 580 |
|
| 581 | +/* |
| 582 | + * Test if the given enum value is on the blacklist |
| 583 | + */ |
| 584 | +bool |
| 585 | +EnumBlacklisted(Oidenum_id) |
| 586 | +{ |
| 587 | +boolfound; |
| 588 | + |
| 589 | +/* If we've made no blacklist table, all values are safe */ |
| 590 | +if (enum_blacklist==NULL) |
| 591 | +return false; |
| 592 | + |
| 593 | +/* Else, is it in the table? */ |
| 594 | +(void)hash_search(enum_blacklist,&enum_id,HASH_FIND,&found); |
| 595 | +returnfound; |
| 596 | +} |
| 597 | + |
| 598 | + |
| 599 | +/* |
| 600 | + * Clean up enum stuff after end of top-level transaction. |
| 601 | + */ |
| 602 | +void |
| 603 | +AtEOXact_Enum(void) |
| 604 | +{ |
| 605 | +/* |
| 606 | + * Reset the blacklist table, as all our enum values are now committed. |
| 607 | + * The memory will go away automatically when TopTransactionContext is |
| 608 | + * freed; it's sufficient to clear our pointer. |
| 609 | + */ |
| 610 | +enum_blacklist=NULL; |
| 611 | +} |
| 612 | + |
| 613 | + |
550 | 614 | /*
|
551 | 615 | * RenumberEnumType
|
552 | 616 | *Renumber existing enum elements to have sort positions 1..n.
|
|