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;
27 -- Also try it with non-error-throwing API
28 SELECT pg_input_is_valid('red', 'rainbow');
34 SELECT pg_input_is_valid('mauve', 'rainbow');
40 SELECT * FROM pg_input_error_info('mauve', 'rainbow');
41 message | detail | hint | sql_error_code
42 -----------------------------------------------+--------+------+----------------
43 invalid input value for enum rainbow: "mauve" | | | 22P02
47 SELECT * FROM pg_input_error_info(repeat('too_long', 32), 'rainbow');
48 -[ RECORD 1 ]--+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
49 message | invalid input value for enum rainbow: "too_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_long"
52 sql_error_code | 22P02
58 CREATE TYPE planets AS ENUM ( 'venus', 'earth', 'mars' );
59 SELECT enumlabel, enumsortorder
61 WHERE enumtypid = 'planets'::regtype
63 enumlabel | enumsortorder
64 -----------+---------------
70 ALTER TYPE planets ADD VALUE 'uranus';
71 SELECT enumlabel, enumsortorder
73 WHERE enumtypid = 'planets'::regtype
75 enumlabel | enumsortorder
76 -----------+---------------
83 ALTER TYPE planets ADD VALUE 'mercury' BEFORE 'venus';
84 ALTER TYPE planets ADD VALUE 'saturn' BEFORE 'uranus';
85 ALTER TYPE planets ADD VALUE 'jupiter' AFTER 'mars';
86 ALTER TYPE planets ADD VALUE 'neptune' AFTER 'uranus';
87 SELECT enumlabel, enumsortorder
89 WHERE enumtypid = 'planets'::regtype
91 enumlabel | enumsortorder
92 -----------+---------------
103 SELECT enumlabel, enumsortorder
105 WHERE enumtypid = 'planets'::regtype
106 ORDER BY enumlabel::planets;
107 enumlabel | enumsortorder
108 -----------+---------------
119 -- errors for adding labels
120 ALTER TYPE planets ADD VALUE
121 'plutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutopluto';
122 ERROR: invalid enum label "plutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutopluto"
123 DETAIL: Labels must be 63 bytes or less.
124 ALTER TYPE planets ADD VALUE 'pluto' AFTER 'zeus';
125 ERROR: "zeus" is not an existing enum label
126 -- if not exists tests
127 -- existing value gives error
128 ALTER TYPE planets ADD VALUE 'mercury';
129 ERROR: enum label "mercury" already exists
130 -- unless IF NOT EXISTS is specified
131 ALTER TYPE planets ADD VALUE IF NOT EXISTS 'mercury';
132 NOTICE: enum label "mercury" already exists, skipping
133 -- should be neptune, not mercury
134 SELECT enum_last(NULL::planets);
140 ALTER TYPE planets ADD VALUE IF NOT EXISTS 'pluto';
141 -- should be pluto, i.e. the new value
142 SELECT enum_last(NULL::planets);
149 -- Test inserting so many values that we have to renumber
151 create type insenum as enum ('L1', 'L2');
152 alter type insenum add value 'i1' before 'L2';
153 alter type insenum add value 'i2' before 'L2';
154 alter type insenum add value 'i3' before 'L2';
155 alter type insenum add value 'i4' before 'L2';
156 alter type insenum add value 'i5' before 'L2';
157 alter type insenum add value 'i6' before 'L2';
158 alter type insenum add value 'i7' before 'L2';
159 alter type insenum add value 'i8' before 'L2';
160 alter type insenum add value 'i9' before 'L2';
161 alter type insenum add value 'i10' before 'L2';
162 alter type insenum add value 'i11' before 'L2';
163 alter type insenum add value 'i12' before 'L2';
164 alter type insenum add value 'i13' before 'L2';
165 alter type insenum add value 'i14' before 'L2';
166 alter type insenum add value 'i15' before 'L2';
167 alter type insenum add value 'i16' before 'L2';
168 alter type insenum add value 'i17' before 'L2';
169 alter type insenum add value 'i18' before 'L2';
170 alter type insenum add value 'i19' before 'L2';
171 alter type insenum add value 'i20' before 'L2';
172 alter type insenum add value 'i21' before 'L2';
173 alter type insenum add value 'i22' before 'L2';
174 alter type insenum add value 'i23' before 'L2';
175 alter type insenum add value 'i24' before 'L2';
176 alter type insenum add value 'i25' before 'L2';
177 alter type insenum add value 'i26' before 'L2';
178 alter type insenum add value 'i27' before 'L2';
179 alter type insenum add value 'i28' before 'L2';
180 alter type insenum add value 'i29' before 'L2';
181 alter type insenum add value 'i30' before 'L2';
182 -- The exact values of enumsortorder will now depend on the local properties
183 -- of float4, but in any reasonable implementation we should get at least
184 -- 20 splits before having to renumber; so only hide values > 20.
186 case when enumsortorder > 20 then null else enumsortorder end as so
188 WHERE enumtypid = 'insenum'::regtype
189 ORDER BY enumsortorder;
227 -- Basic table creation, row selection
229 CREATE TABLE enumtest (col rainbow);
230 INSERT INTO enumtest values ('red'), ('orange'), ('yellow'), ('green');
231 COPY enumtest FROM stdin;
232 SELECT * FROM enumtest;
244 -- Operators, no index
246 SELECT * FROM enumtest WHERE col = 'orange';
252 SELECT * FROM enumtest WHERE col <> 'orange' ORDER BY col;
262 SELECT * FROM enumtest WHERE col > 'yellow' ORDER BY col;
270 SELECT * FROM enumtest WHERE col >= 'yellow' ORDER BY col;
279 SELECT * FROM enumtest WHERE col < 'green' ORDER BY col;
287 SELECT * FROM enumtest WHERE col <= 'green' ORDER BY col;
299 SELECT 'red'::rainbow::text || 'hithere';
305 SELECT 'red'::text::rainbow = 'red'::rainbow;
314 SELECT min(col) FROM enumtest;
320 SELECT max(col) FROM enumtest;
326 SELECT max(col) FROM enumtest WHERE col < 'green';
333 -- Index tests, force use of index
335 SET enable_seqscan = off;
336 SET enable_bitmapscan = off;
338 -- Btree index / opclass with the various operators
340 CREATE UNIQUE INDEX enumtest_btree ON enumtest USING btree (col);
341 SELECT * FROM enumtest WHERE col = 'orange';
347 SELECT * FROM enumtest WHERE col <> 'orange' ORDER BY col;
357 SELECT * FROM enumtest WHERE col > 'yellow' ORDER BY col;
365 SELECT * FROM enumtest WHERE col >= 'yellow' ORDER BY col;
374 SELECT * FROM enumtest WHERE col < 'green' ORDER BY col;
382 SELECT * FROM enumtest WHERE col <= 'green' ORDER BY col;
391 SELECT min(col) FROM enumtest;
397 SELECT max(col) FROM enumtest;
403 SELECT max(col) FROM enumtest WHERE col < 'green';
409 DROP INDEX enumtest_btree;
411 -- Hash index / opclass with the = operator
413 CREATE INDEX enumtest_hash ON enumtest USING hash (col);
414 SELECT * FROM enumtest WHERE col = 'orange';
420 DROP INDEX enumtest_hash;
424 RESET enable_seqscan;
425 RESET enable_bitmapscan;
427 -- Domains over enums
429 CREATE DOMAIN rgb AS rainbow CHECK (VALUE IN ('red', 'green', 'blue'));
436 SELECT 'purple'::rgb;
437 ERROR: value for domain rgb violates check constraint "rgb_check"
438 SELECT 'purple'::rainbow::rgb;
439 ERROR: value for domain rgb violates check constraint "rgb_check"
444 SELECT '{red,green,blue}'::rainbow[];
450 SELECT ('{red,green,blue}'::rainbow[])[2];
456 SELECT 'red' = ANY ('{red,green,blue}'::rainbow[]);
462 SELECT 'yellow' = ANY ('{red,green,blue}'::rainbow[]);
468 SELECT 'red' = ALL ('{red,green,blue}'::rainbow[]);
474 SELECT 'red' = ALL ('{red,red}'::rainbow[]);
483 SELECT enum_first(NULL::rainbow);
489 SELECT enum_last('green'::rainbow);
495 SELECT enum_range(NULL::rainbow);
497 ---------------------------------------
498 {red,orange,yellow,green,blue,purple}
501 SELECT enum_range('orange'::rainbow, 'green'::rainbow);
503 -----------------------
504 {orange,yellow,green}
507 SELECT enum_range(NULL, 'green'::rainbow);
509 ---------------------------
510 {red,orange,yellow,green}
513 SELECT enum_range('orange'::rainbow, NULL);
515 -----------------------------------
516 {orange,yellow,green,blue,purple}
519 SELECT enum_range(NULL::rainbow, NULL);
521 ---------------------------------------
522 {red,orange,yellow,green,blue,purple}
526 -- User functions, can't test perl/python etc here since may not be compiled.
528 CREATE FUNCTION echo_me(anyenum) RETURNS text AS $$
530 RETURN $1::text || 'omg';
533 SELECT echo_me('red'::rainbow);
540 -- Concrete function should override generic one
542 CREATE FUNCTION echo_me(rainbow) RETURNS text AS $$
544 RETURN $1::text || 'wtf';
547 SELECT echo_me('red'::rainbow);
554 -- If we drop the original generic one, we don't have to qualify the type
555 -- anymore, since there's only one match
557 DROP FUNCTION echo_me(anyenum);
558 SELECT echo_me('red');
564 DROP FUNCTION echo_me(rainbow);
566 -- RI triggers on enum types
568 CREATE TABLE enumtest_parent (id rainbow PRIMARY KEY);
569 CREATE TABLE enumtest_child (parent rainbow REFERENCES enumtest_parent);
570 INSERT INTO enumtest_parent VALUES ('red');
571 INSERT INTO enumtest_child VALUES ('red');
572 INSERT INTO enumtest_child VALUES ('blue'); -- fail
573 ERROR: insert or update on table "enumtest_child" violates foreign key constraint "enumtest_child_parent_fkey"
574 DETAIL: Key (parent)=(blue) is not present in table "enumtest_parent".
575 DELETE FROM enumtest_parent; -- fail
576 ERROR: update or delete on table "enumtest_parent" violates foreign key constraint "enumtest_child_parent_fkey" on table "enumtest_child"
577 DETAIL: Key (id)=(red) is still referenced from table "enumtest_child".
579 -- cross-type RI should fail
581 CREATE TYPE bogus AS ENUM('good', 'bad', 'ugly');
582 CREATE TABLE enumtest_bogus_child(parent bogus REFERENCES enumtest_parent);
583 ERROR: foreign key constraint "enumtest_bogus_child_parent_fkey" cannot be implemented
584 DETAIL: Key columns "parent" of the referencing table and "id" of the referenced table are of incompatible types: bogus and rainbow.
586 -- check renaming a value
587 ALTER TYPE rainbow RENAME VALUE 'red' TO 'crimson';
588 SELECT enumlabel, enumsortorder
590 WHERE enumtypid = 'rainbow'::regtype
592 enumlabel | enumsortorder
593 -----------+---------------
602 -- check that renaming a non-existent value fails
603 ALTER TYPE rainbow RENAME VALUE 'red' TO 'crimson';
604 ERROR: "red" is not an existing enum label
605 -- check that renaming to an existent value fails
606 ALTER TYPE rainbow RENAME VALUE 'blue' TO 'green';
607 ERROR: enum label "green" already exists
609 -- check transactional behaviour of ALTER TYPE ... ADD VALUE
611 CREATE TYPE bogus AS ENUM('good');
612 -- check that we can add new values to existing enums in a transaction
613 -- but we can't use them
615 ALTER TYPE bogus ADD VALUE 'new';
617 SELECT 'new'::bogus; -- unsafe
618 ERROR: unsafe use of new value "new" of enum type bogus
619 LINE 1: SELECT 'new'::bogus;
621 HINT: New enum values must be committed before they can be used.
623 SELECT enum_first(null::bogus); -- safe
629 SELECT enum_last(null::bogus); -- unsafe
630 ERROR: unsafe use of new value "new" of enum type bogus
631 HINT: New enum values must be committed before they can be used.
633 SELECT enum_range(null::bogus); -- unsafe
634 ERROR: unsafe use of new value "new" of enum type bogus
635 HINT: New enum values must be committed before they can be used.
638 SELECT 'new'::bogus; -- now safe
644 SELECT enumlabel, enumsortorder
646 WHERE enumtypid = 'bogus'::regtype
648 enumlabel | enumsortorder
649 -----------+---------------
654 -- check that we recognize the case where the enum already existed but was
655 -- modified in the current txn; this should not be considered safe
657 ALTER TYPE bogus RENAME TO bogon;
658 ALTER TYPE bogon ADD VALUE 'bad';
660 ERROR: unsafe use of new value "bad" of enum type bogon
661 LINE 1: SELECT 'bad'::bogon;
663 HINT: New enum values must be committed before they can be used.
665 -- but a renamed value is safe to use later in same transaction
667 ALTER TYPE bogus RENAME VALUE 'good' to 'bad';
676 -- check that values created during CREATE TYPE can be used in any case
678 CREATE TYPE bogus AS ENUM('good','bad','ugly');
679 ALTER TYPE bogus RENAME TO bogon;
680 select enum_range(null::bogon);
687 -- we must allow this usage to support pg_dump in binary upgrade mode
689 CREATE TYPE bogus AS ENUM('good');
690 ALTER TYPE bogus RENAME TO bogon;
691 ALTER TYPE bogon ADD VALUE 'bad';
692 ALTER TYPE bogon ADD VALUE 'ugly';
693 select enum_range(null::bogon);
703 DROP TABLE enumtest_child;
704 DROP TABLE enumtest_parent;
708 -- Verify properly cleaned up
710 SELECT COUNT(*) FROM pg_type WHERE typname = 'rainbow';
716 SELECT * FROM pg_enum WHERE NOT EXISTS
717 (SELECT 1 FROM pg_type WHERE pg_type.oid = enumtypid);
718 oid | enumtypid | enumsortorder | enumlabel
719 -----+-----------+---------------+-----------