4 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
6 -- Did it create the right number of rows?
8 SELECT COUNT(*) FROM pg_enum WHERE enumtypid = 'rainbow'::regtype;
17 SELECT 'red'::rainbow;
23 SELECT 'mauve'::rainbow;
24 ERROR: invalid input value for enum rainbow: "mauve"
25 LINE 1: SELECT 'mauve'::rainbow;
30 CREATE TYPE planets AS ENUM ( 'venus', 'earth', 'mars' );
31 SELECT enumlabel, enumsortorder
33 WHERE enumtypid = 'planets'::regtype
35 enumlabel | enumsortorder
36 -----------+---------------
42 ALTER TYPE planets ADD VALUE 'uranus';
43 SELECT enumlabel, enumsortorder
45 WHERE enumtypid = 'planets'::regtype
47 enumlabel | enumsortorder
48 -----------+---------------
55 ALTER TYPE planets ADD VALUE 'mercury' BEFORE 'venus';
56 ALTER TYPE planets ADD VALUE 'saturn' BEFORE 'uranus';
57 ALTER TYPE planets ADD VALUE 'jupiter' AFTER 'mars';
58 ALTER TYPE planets ADD VALUE 'neptune' AFTER 'uranus';
59 SELECT enumlabel, enumsortorder
61 WHERE enumtypid = 'planets'::regtype
63 enumlabel | enumsortorder
64 -----------+---------------
75 SELECT enumlabel, enumsortorder
77 WHERE enumtypid = 'planets'::regtype
78 ORDER BY enumlabel::planets;
79 enumlabel | enumsortorder
80 -----------+---------------
91 -- errors for adding labels
92 ALTER TYPE planets ADD VALUE
93 'plutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutopluto';
94 ERROR: invalid enum label "plutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutopluto"
95 DETAIL: Labels must be 63 bytes or less.
96 ALTER TYPE planets ADD VALUE 'pluto' AFTER 'zeus';
97 ERROR: "zeus" is not an existing enum label
98 -- if not exists tests
99 -- existing value gives error
100 ALTER TYPE planets ADD VALUE 'mercury';
101 ERROR: enum label "mercury" already exists
102 -- unless IF NOT EXISTS is specified
103 ALTER TYPE planets ADD VALUE IF NOT EXISTS 'mercury';
104 NOTICE: enum label "mercury" already exists, skipping
105 -- should be neptune, not mercury
106 SELECT enum_last(NULL::planets);
112 ALTER TYPE planets ADD VALUE IF NOT EXISTS 'pluto';
113 -- should be pluto, i.e. the new value
114 SELECT enum_last(NULL::planets);
121 -- Test inserting so many values that we have to renumber
123 create type insenum as enum ('L1', 'L2');
124 alter type insenum add value 'i1' before 'L2';
125 alter type insenum add value 'i2' before 'L2';
126 alter type insenum add value 'i3' before 'L2';
127 alter type insenum add value 'i4' before 'L2';
128 alter type insenum add value 'i5' before 'L2';
129 alter type insenum add value 'i6' before 'L2';
130 alter type insenum add value 'i7' before 'L2';
131 alter type insenum add value 'i8' before 'L2';
132 alter type insenum add value 'i9' before 'L2';
133 alter type insenum add value 'i10' before 'L2';
134 alter type insenum add value 'i11' before 'L2';
135 alter type insenum add value 'i12' before 'L2';
136 alter type insenum add value 'i13' before 'L2';
137 alter type insenum add value 'i14' before 'L2';
138 alter type insenum add value 'i15' before 'L2';
139 alter type insenum add value 'i16' before 'L2';
140 alter type insenum add value 'i17' before 'L2';
141 alter type insenum add value 'i18' before 'L2';
142 alter type insenum add value 'i19' before 'L2';
143 alter type insenum add value 'i20' before 'L2';
144 alter type insenum add value 'i21' before 'L2';
145 alter type insenum add value 'i22' before 'L2';
146 alter type insenum add value 'i23' before 'L2';
147 alter type insenum add value 'i24' before 'L2';
148 alter type insenum add value 'i25' before 'L2';
149 alter type insenum add value 'i26' before 'L2';
150 alter type insenum add value 'i27' before 'L2';
151 alter type insenum add value 'i28' before 'L2';
152 alter type insenum add value 'i29' before 'L2';
153 alter type insenum add value 'i30' before 'L2';
154 -- The exact values of enumsortorder will now depend on the local properties
155 -- of float4, but in any reasonable implementation we should get at least
156 -- 20 splits before having to renumber; so only hide values > 20.
158 case when enumsortorder > 20 then null else enumsortorder end as so
160 WHERE enumtypid = 'insenum'::regtype
161 ORDER BY enumsortorder;
199 -- Basic table creation, row selection
201 CREATE TABLE enumtest (col rainbow);
202 INSERT INTO enumtest values ('red'), ('orange'), ('yellow'), ('green');
203 COPY enumtest FROM stdin;
204 SELECT * FROM enumtest;
216 -- Operators, no index
218 SELECT * FROM enumtest WHERE col = 'orange';
224 SELECT * FROM enumtest WHERE col <> 'orange' ORDER BY col;
234 SELECT * FROM enumtest WHERE col > 'yellow' ORDER BY col;
242 SELECT * FROM enumtest WHERE col >= 'yellow' ORDER BY col;
251 SELECT * FROM enumtest WHERE col < 'green' ORDER BY col;
259 SELECT * FROM enumtest WHERE col <= 'green' ORDER BY col;
271 SELECT 'red'::rainbow::text || 'hithere';
277 SELECT 'red'::text::rainbow = 'red'::rainbow;
286 SELECT min(col) FROM enumtest;
292 SELECT max(col) FROM enumtest;
298 SELECT max(col) FROM enumtest WHERE col < 'green';
305 -- Index tests, force use of index
307 SET enable_seqscan = off;
308 SET enable_bitmapscan = off;
310 -- Btree index / opclass with the various operators
312 CREATE UNIQUE INDEX enumtest_btree ON enumtest USING btree (col);
313 SELECT * FROM enumtest WHERE col = 'orange';
319 SELECT * FROM enumtest WHERE col <> 'orange' ORDER BY col;
329 SELECT * FROM enumtest WHERE col > 'yellow' ORDER BY col;
337 SELECT * FROM enumtest WHERE col >= 'yellow' ORDER BY col;
346 SELECT * FROM enumtest WHERE col < 'green' ORDER BY col;
354 SELECT * FROM enumtest WHERE col <= 'green' ORDER BY col;
363 SELECT min(col) FROM enumtest;
369 SELECT max(col) FROM enumtest;
375 SELECT max(col) FROM enumtest WHERE col < 'green';
381 DROP INDEX enumtest_btree;
383 -- Hash index / opclass with the = operator
385 CREATE INDEX enumtest_hash ON enumtest USING hash (col);
386 SELECT * FROM enumtest WHERE col = 'orange';
392 DROP INDEX enumtest_hash;
396 RESET enable_seqscan;
397 RESET enable_bitmapscan;
399 -- Domains over enums
401 CREATE DOMAIN rgb AS rainbow CHECK (VALUE IN ('red', 'green', 'blue'));
408 SELECT 'purple'::rgb;
409 ERROR: value for domain rgb violates check constraint "rgb_check"
410 SELECT 'purple'::rainbow::rgb;
411 ERROR: value for domain rgb violates check constraint "rgb_check"
416 SELECT '{red,green,blue}'::rainbow[];
422 SELECT ('{red,green,blue}'::rainbow[])[2];
428 SELECT 'red' = ANY ('{red,green,blue}'::rainbow[]);
434 SELECT 'yellow' = ANY ('{red,green,blue}'::rainbow[]);
440 SELECT 'red' = ALL ('{red,green,blue}'::rainbow[]);
446 SELECT 'red' = ALL ('{red,red}'::rainbow[]);
455 SELECT enum_first(NULL::rainbow);
461 SELECT enum_last('green'::rainbow);
467 SELECT enum_range(NULL::rainbow);
469 ---------------------------------------
470 {red,orange,yellow,green,blue,purple}
473 SELECT enum_range('orange'::rainbow, 'green'::rainbow);
475 -----------------------
476 {orange,yellow,green}
479 SELECT enum_range(NULL, 'green'::rainbow);
481 ---------------------------
482 {red,orange,yellow,green}
485 SELECT enum_range('orange'::rainbow, NULL);
487 -----------------------------------
488 {orange,yellow,green,blue,purple}
491 SELECT enum_range(NULL::rainbow, NULL);
493 ---------------------------------------
494 {red,orange,yellow,green,blue,purple}
498 -- User functions, can't test perl/python etc here since may not be compiled.
500 CREATE FUNCTION echo_me(anyenum) RETURNS text AS $$
502 RETURN $1::text || 'omg';
505 SELECT echo_me('red'::rainbow);
512 -- Concrete function should override generic one
514 CREATE FUNCTION echo_me(rainbow) RETURNS text AS $$
516 RETURN $1::text || 'wtf';
519 SELECT echo_me('red'::rainbow);
526 -- If we drop the original generic one, we don't have to qualify the type
527 -- anymore, since there's only one match
529 DROP FUNCTION echo_me(anyenum);
530 SELECT echo_me('red');
536 DROP FUNCTION echo_me(rainbow);
538 -- RI triggers on enum types
540 CREATE TABLE enumtest_parent (id rainbow PRIMARY KEY);
541 CREATE TABLE enumtest_child (parent rainbow REFERENCES enumtest_parent);
542 INSERT INTO enumtest_parent VALUES ('red');
543 INSERT INTO enumtest_child VALUES ('red');
544 INSERT INTO enumtest_child VALUES ('blue'); -- fail
545 ERROR: insert or update on table "enumtest_child" violates foreign key constraint "enumtest_child_parent_fkey"
546 DETAIL: Key (parent)=(blue) is not present in table "enumtest_parent".
547 DELETE FROM enumtest_parent; -- fail
548 ERROR: update or delete on table "enumtest_parent" violates foreign key constraint "enumtest_child_parent_fkey" on table "enumtest_child"
549 DETAIL: Key (id)=(red) is still referenced from table "enumtest_child".
551 -- cross-type RI should fail
553 CREATE TYPE bogus AS ENUM('good', 'bad', 'ugly');
554 CREATE TABLE enumtest_bogus_child(parent bogus REFERENCES enumtest_parent);
555 ERROR: foreign key constraint "enumtest_bogus_child_parent_fkey" cannot be implemented
556 DETAIL: Key columns "parent" and "id" are of incompatible types: bogus and rainbow.
558 -- check renaming a value
559 ALTER TYPE rainbow RENAME VALUE 'red' TO 'crimson';
560 SELECT enumlabel, enumsortorder
562 WHERE enumtypid = 'rainbow'::regtype
564 enumlabel | enumsortorder
565 -----------+---------------
574 -- check that renaming a non-existent value fails
575 ALTER TYPE rainbow RENAME VALUE 'red' TO 'crimson';
576 ERROR: "red" is not an existing enum label
577 -- check that renaming to an existent value fails
578 ALTER TYPE rainbow RENAME VALUE 'blue' TO 'green';
579 ERROR: enum label "green" already exists
581 -- check transactional behaviour of ALTER TYPE ... ADD VALUE
583 CREATE TYPE bogus AS ENUM('good');
584 -- check that we can add new values to existing enums in a transaction
585 -- but we can't use them
587 ALTER TYPE bogus ADD VALUE 'new';
589 SELECT 'new'::bogus; -- unsafe
590 ERROR: unsafe use of new value "new" of enum type bogus
591 LINE 1: SELECT 'new'::bogus;
593 HINT: New enum values must be committed before they can be used.
595 SELECT enum_first(null::bogus); -- safe
601 SELECT enum_last(null::bogus); -- unsafe
602 ERROR: unsafe use of new value "new" of enum type bogus
603 HINT: New enum values must be committed before they can be used.
605 SELECT enum_range(null::bogus); -- unsafe
606 ERROR: unsafe use of new value "new" of enum type bogus
607 HINT: New enum values must be committed before they can be used.
610 SELECT 'new'::bogus; -- now safe
616 SELECT enumlabel, enumsortorder
618 WHERE enumtypid = 'bogus'::regtype
620 enumlabel | enumsortorder
621 -----------+---------------
626 -- check that we recognize the case where the enum already existed but was
627 -- modified in the current txn; this should not be considered safe
629 ALTER TYPE bogus RENAME TO bogon;
630 ALTER TYPE bogon ADD VALUE 'bad';
632 ERROR: unsafe use of new value "bad" of enum type bogon
633 LINE 1: SELECT 'bad'::bogon;
635 HINT: New enum values must be committed before they can be used.
637 -- but a renamed value is safe to use later in same transaction
639 ALTER TYPE bogus RENAME VALUE 'good' to 'bad';
648 -- check that values created during CREATE TYPE can be used in any case
650 CREATE TYPE bogus AS ENUM('good','bad','ugly');
651 ALTER TYPE bogus RENAME TO bogon;
652 select enum_range(null::bogon);
659 -- ideally, we'd allow this usage; but it requires keeping track of whether
660 -- the enum type was created in the current transaction, which is expensive
662 CREATE TYPE bogus AS ENUM('good');
663 ALTER TYPE bogus RENAME TO bogon;
664 ALTER TYPE bogon ADD VALUE 'bad';
665 ALTER TYPE bogon ADD VALUE 'ugly';
666 select enum_range(null::bogon); -- fails
667 ERROR: unsafe use of new value "bad" of enum type bogon
668 HINT: New enum values must be committed before they can be used.
673 DROP TABLE enumtest_child;
674 DROP TABLE enumtest_parent;
678 -- Verify properly cleaned up
680 SELECT COUNT(*) FROM pg_type WHERE typname = 'rainbow';
686 SELECT * FROM pg_enum WHERE NOT EXISTS
687 (SELECT 1 FROM pg_type WHERE pg_type.oid = enumtypid);
688 oid | enumtypid | enumsortorder | enumlabel
689 -----+-----------+---------------+-----------