1--
2-- Test domains.
3--
4-- Test Comment / Drop
5create domain domaindroptest int4;
6comment on domain domaindroptest is 'About to drop this..';
7create domain dependenttypetest domaindroptest;
8-- fail because of dependent type
9drop domain domaindroptest;
10ERROR:  cannot drop type domaindroptest because other objects depend on it
11DETAIL:  type dependenttypetest depends on type domaindroptest
12HINT:  Use DROP ... CASCADE to drop the dependent objects too.
13drop domain domaindroptest cascade;
14NOTICE:  drop cascades to type dependenttypetest
15-- this should fail because already gone
16drop domain domaindroptest cascade;
17ERROR:  type "domaindroptest" does not exist
18-- Test domain input.
19-- Note: the point of checking both INSERT and COPY FROM is that INSERT
20-- exercises CoerceToDomain while COPY exercises domain_in.
21create domain domainvarchar varchar(5);
22create domain domainnumeric numeric(8,2);
23create domain domainint4 int4;
24create domain domaintext text;
25-- Test explicit coercions --- these should succeed (and truncate)
26SELECT cast('123456' as domainvarchar);
27 domainvarchar
28---------------
29 12345
30(1 row)
31
32SELECT cast('12345' as domainvarchar);
33 domainvarchar
34---------------
35 12345
36(1 row)
37
38-- Test tables using domains
39create table basictest
40           ( testint4 domainint4
41           , testtext domaintext
42           , testvarchar domainvarchar
43           , testnumeric domainnumeric
44           );
45INSERT INTO basictest values ('88', 'haha', 'short', '123.12');      -- Good
46INSERT INTO basictest values ('88', 'haha', 'short text', '123.12'); -- Bad varchar
47ERROR:  value too long for type character varying(5)
48INSERT INTO basictest values ('88', 'haha', 'short', '123.1212');    -- Truncate numeric
49-- Test copy
50COPY basictest (testvarchar) FROM stdin; -- fail
51ERROR:  value too long for type character varying(5)
52CONTEXT:  COPY basictest, line 1, column testvarchar: "notsoshorttext"
53COPY basictest (testvarchar) FROM stdin;
54select * from basictest;
55 testint4 | testtext | testvarchar | testnumeric
56----------+----------+-------------+-------------
57       88 | haha     | short       |      123.12
58       88 | haha     | short       |      123.12
59          |          | short       |
60(3 rows)
61
62-- check that domains inherit operations from base types
63select testtext || testvarchar as concat, testnumeric + 42 as sum
64from basictest;
65  concat   |  sum
66-----------+--------
67 hahashort | 165.12
68 hahashort | 165.12
69           |
70(3 rows)
71
72-- check that union/case/coalesce type resolution handles domains properly
73select coalesce(4::domainint4, 7) is of (int4) as t;
74 t
75---
76 t
77(1 row)
78
79select coalesce(4::domainint4, 7) is of (domainint4) as f;
80 f
81---
82 f
83(1 row)
84
85select coalesce(4::domainint4, 7::domainint4) is of (domainint4) as t;
86 t
87---
88 t
89(1 row)
90
91drop table basictest;
92drop domain domainvarchar restrict;
93drop domain domainnumeric restrict;
94drop domain domainint4 restrict;
95drop domain domaintext;
96-- Test domains over array types
97create domain domainint4arr int4[1];
98create domain domainchar4arr varchar(4)[2][3];
99create table domarrtest
100           ( testint4arr domainint4arr
101           , testchar4arr domainchar4arr
102            );
103INSERT INTO domarrtest values ('{2,2}', '{{"a","b"},{"c","d"}}');
104INSERT INTO domarrtest values ('{{2,2},{2,2}}', '{{"a","b"}}');
105INSERT INTO domarrtest values ('{2,2}', '{{"a","b"},{"c","d"},{"e","f"}}');
106INSERT INTO domarrtest values ('{2,2}', '{{"a"},{"c"}}');
107INSERT INTO domarrtest values (NULL, '{{"a","b","c"},{"d","e","f"}}');
108INSERT INTO domarrtest values (NULL, '{{"toolong","b","c"},{"d","e","f"}}');
109ERROR:  value too long for type character varying(4)
110INSERT INTO domarrtest (testint4arr[1], testint4arr[3]) values (11,22);
111select * from domarrtest;
112  testint4arr  |    testchar4arr
113---------------+---------------------
114 {2,2}         | {{a,b},{c,d}}
115 {{2,2},{2,2}} | {{a,b}}
116 {2,2}         | {{a,b},{c,d},{e,f}}
117 {2,2}         | {{a},{c}}
118               | {{a,b,c},{d,e,f}}
119 {11,NULL,22}  |
120(6 rows)
121
122select testint4arr[1], testchar4arr[2:2] from domarrtest;
123 testint4arr | testchar4arr
124-------------+--------------
125           2 | {{c,d}}
126             | {}
127           2 | {{c,d}}
128           2 | {{c}}
129             | {{d,e,f}}
130          11 |
131(6 rows)
132
133select array_dims(testint4arr), array_dims(testchar4arr) from domarrtest;
134 array_dims | array_dims
135------------+------------
136 [1:2]      | [1:2][1:2]
137 [1:2][1:2] | [1:1][1:2]
138 [1:2]      | [1:3][1:2]
139 [1:2]      | [1:2][1:1]
140            | [1:2][1:3]
141 [1:3]      |
142(6 rows)
143
144COPY domarrtest FROM stdin;
145COPY domarrtest FROM stdin;	-- fail
146ERROR:  value too long for type character varying(4)
147CONTEXT:  COPY domarrtest, line 1, column testchar4arr: "{qwerty,w,e}"
148select * from domarrtest;
149  testint4arr  |    testchar4arr
150---------------+---------------------
151 {2,2}         | {{a,b},{c,d}}
152 {{2,2},{2,2}} | {{a,b}}
153 {2,2}         | {{a,b},{c,d},{e,f}}
154 {2,2}         | {{a},{c}}
155               | {{a,b,c},{d,e,f}}
156 {11,NULL,22}  |
157 {3,4}         | {q,w,e}
158               |
159(8 rows)
160
161update domarrtest set
162  testint4arr[1] = testint4arr[1] + 1,
163  testint4arr[3] = testint4arr[3] - 1
164where testchar4arr is null;
165select * from domarrtest where testchar4arr is null;
166   testint4arr    | testchar4arr
167------------------+--------------
168 {12,NULL,21}     |
169 {NULL,NULL,NULL} |
170(2 rows)
171
172drop table domarrtest;
173drop domain domainint4arr restrict;
174drop domain domainchar4arr restrict;
175create domain dia as int[];
176select '{1,2,3}'::dia;
177   dia
178---------
179 {1,2,3}
180(1 row)
181
182select array_dims('{1,2,3}'::dia);
183 array_dims
184------------
185 [1:3]
186(1 row)
187
188select pg_typeof('{1,2,3}'::dia);
189 pg_typeof
190-----------
191 dia
192(1 row)
193
194select pg_typeof('{1,2,3}'::dia || 42); -- should be int[] not dia
195 pg_typeof
196-----------
197 integer[]
198(1 row)
199
200drop domain dia;
201-- Test domains over arrays of composite
202create type comptype as (r float8, i float8);
203create domain dcomptypea as comptype[];
204create table dcomptable (d1 dcomptypea unique);
205insert into dcomptable values (array[row(1,2)]::dcomptypea);
206insert into dcomptable values (array[row(3,4), row(5,6)]::comptype[]);
207insert into dcomptable values (array[row(7,8)::comptype, row(9,10)::comptype]);
208insert into dcomptable values (array[row(1,2)]::dcomptypea);  -- fail on uniqueness
209ERROR:  duplicate key value violates unique constraint "dcomptable_d1_key"
210DETAIL:  Key (d1)=({"(1,2)"}) already exists.
211insert into dcomptable (d1[1]) values(row(9,10));
212insert into dcomptable (d1[1].r) values(11);
213select * from dcomptable;
214         d1
215--------------------
216 {"(1,2)"}
217 {"(3,4)","(5,6)"}
218 {"(7,8)","(9,10)"}
219 {"(9,10)"}
220 {"(11,)"}
221(5 rows)
222
223select d1[2], d1[1].r, d1[1].i from dcomptable;
224   d1   | r  | i
225--------+----+----
226        |  1 |  2
227 (5,6)  |  3 |  4
228 (9,10) |  7 |  8
229        |  9 | 10
230        | 11 |
231(5 rows)
232
233update dcomptable set d1[2] = row(d1[2].i, d1[2].r);
234select * from dcomptable;
235         d1
236--------------------
237 {"(1,2)","(,)"}
238 {"(3,4)","(6,5)"}
239 {"(7,8)","(10,9)"}
240 {"(9,10)","(,)"}
241 {"(11,)","(,)"}
242(5 rows)
243
244update dcomptable set d1[1].r = d1[1].r + 1 where d1[1].i > 0;
245select * from dcomptable;
246         d1
247--------------------
248 {"(11,)","(,)"}
249 {"(2,2)","(,)"}
250 {"(4,4)","(6,5)"}
251 {"(8,8)","(10,9)"}
252 {"(10,10)","(,)"}
253(5 rows)
254
255alter domain dcomptypea add constraint c1 check (value[1].r <= value[1].i);
256alter domain dcomptypea add constraint c2 check (value[1].r > value[1].i);  -- fail
257ERROR:  column "d1" of table "dcomptable" contains values that violate the new constraint
258select array[row(2,1)]::dcomptypea;  -- fail
259ERROR:  value for domain dcomptypea violates check constraint "c1"
260insert into dcomptable values (array[row(1,2)]::comptype[]);
261insert into dcomptable values (array[row(2,1)]::comptype[]);  -- fail
262ERROR:  value for domain dcomptypea violates check constraint "c1"
263insert into dcomptable (d1[1].r) values(99);
264insert into dcomptable (d1[1].r, d1[1].i) values(99, 100);
265insert into dcomptable (d1[1].r, d1[1].i) values(100, 99);  -- fail
266ERROR:  value for domain dcomptypea violates check constraint "c1"
267update dcomptable set d1[1].r = d1[1].r + 1 where d1[1].i > 0;  -- fail
268ERROR:  value for domain dcomptypea violates check constraint "c1"
269update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
270  where d1[1].i > 0;
271select * from dcomptable;
272         d1
273--------------------
274 {"(11,)","(,)"}
275 {"(99,)"}
276 {"(1,3)","(,)"}
277 {"(3,5)","(6,5)"}
278 {"(7,9)","(10,9)"}
279 {"(9,11)","(,)"}
280 {"(0,3)"}
281 {"(98,101)"}
282(8 rows)
283
284explain (verbose, costs off)
285  update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
286    where d1[1].i > 0;
287                                                   QUERY PLAN
288----------------------------------------------------------------------------------------------------------------
289 Update on public.dcomptable
290   ->  Seq Scan on public.dcomptable
291         Output: (d1[1].r := (d1[1].r - '1'::double precision))[1].i := (d1[1].i + '1'::double precision), ctid
292         Filter: (dcomptable.d1[1].i > '0'::double precision)
293(4 rows)
294
295create rule silly as on delete to dcomptable do instead
296  update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
297    where d1[1].i > 0;
298\d+ dcomptable
299                                  Table "public.dcomptable"
300 Column |    Type    | Collation | Nullable | Default | Storage  | Stats target | Description
301--------+------------+-----------+----------+---------+----------+--------------+-------------
302 d1     | dcomptypea |           |          |         | extended |              |
303Indexes:
304    "dcomptable_d1_key" UNIQUE CONSTRAINT, btree (d1)
305Rules:
306    silly AS
307    ON DELETE TO dcomptable DO INSTEAD  UPDATE dcomptable SET d1[1].r = dcomptable.d1[1].r - 1::double precision, d1[1].i = dcomptable.d1[1].i + 1::double precision
308  WHERE dcomptable.d1[1].i > 0::double precision
309
310drop table dcomptable;
311drop type comptype cascade;
312NOTICE:  drop cascades to type dcomptypea
313-- Test not-null restrictions
314create domain dnotnull varchar(15) NOT NULL;
315create domain dnull    varchar(15);
316create domain dcheck   varchar(15) NOT NULL CHECK (VALUE = 'a' OR VALUE = 'c' OR VALUE = 'd');
317create table nulltest
318           ( col1 dnotnull
319           , col2 dnotnull NULL  -- NOT NULL in the domain cannot be overridden
320           , col3 dnull    NOT NULL
321           , col4 dnull
322           , col5 dcheck CHECK (col5 IN ('c', 'd'))
323           );
324INSERT INTO nulltest DEFAULT VALUES;
325ERROR:  domain dnotnull does not allow null values
326INSERT INTO nulltest values ('a', 'b', 'c', 'd', 'c');  -- Good
327insert into nulltest values ('a', 'b', 'c', 'd', NULL);
328ERROR:  domain dcheck does not allow null values
329insert into nulltest values ('a', 'b', 'c', 'd', 'a');
330ERROR:  new row for relation "nulltest" violates check constraint "nulltest_col5_check"
331DETAIL:  Failing row contains (a, b, c, d, a).
332INSERT INTO nulltest values (NULL, 'b', 'c', 'd', 'd');
333ERROR:  domain dnotnull does not allow null values
334INSERT INTO nulltest values ('a', NULL, 'c', 'd', 'c');
335ERROR:  domain dnotnull does not allow null values
336INSERT INTO nulltest values ('a', 'b', NULL, 'd', 'c');
337ERROR:  null value in column "col3" violates not-null constraint
338DETAIL:  Failing row contains (a, b, null, d, c).
339INSERT INTO nulltest values ('a', 'b', 'c', NULL, 'd'); -- Good
340-- Test copy
341COPY nulltest FROM stdin; --fail
342ERROR:  null value in column "col3" violates not-null constraint
343DETAIL:  Failing row contains (a, b, null, d, d).
344CONTEXT:  COPY nulltest, line 1: "a	b	\N	d	d"
345COPY nulltest FROM stdin; --fail
346ERROR:  domain dcheck does not allow null values
347CONTEXT:  COPY nulltest, line 1, column col5: null input
348-- Last row is bad
349COPY nulltest FROM stdin;
350ERROR:  new row for relation "nulltest" violates check constraint "nulltest_col5_check"
351DETAIL:  Failing row contains (a, b, c, null, a).
352CONTEXT:  COPY nulltest, line 3: "a	b	c	\N	a"
353select * from nulltest;
354 col1 | col2 | col3 | col4 | col5
355------+------+------+------+------
356 a    | b    | c    | d    | c
357 a    | b    | c    |      | d
358(2 rows)
359
360-- Test out coerced (casted) constraints
361SELECT cast('1' as dnotnull);
362 dnotnull
363----------
364 1
365(1 row)
366
367SELECT cast(NULL as dnotnull); -- fail
368ERROR:  domain dnotnull does not allow null values
369SELECT cast(cast(NULL as dnull) as dnotnull); -- fail
370ERROR:  domain dnotnull does not allow null values
371SELECT cast(col4 as dnotnull) from nulltest; -- fail
372ERROR:  domain dnotnull does not allow null values
373-- cleanup
374drop table nulltest;
375drop domain dnotnull restrict;
376drop domain dnull restrict;
377drop domain dcheck restrict;
378create domain ddef1 int4 DEFAULT 3;
379create domain ddef2 oid DEFAULT '12';
380-- Type mixing, function returns int8
381create domain ddef3 text DEFAULT 5;
382create sequence ddef4_seq;
383create domain ddef4 int4 DEFAULT nextval('ddef4_seq');
384create domain ddef5 numeric(8,2) NOT NULL DEFAULT '12.12';
385create table defaulttest
386            ( col1 ddef1
387            , col2 ddef2
388            , col3 ddef3
389            , col4 ddef4 PRIMARY KEY
390            , col5 ddef1 NOT NULL DEFAULT NULL
391            , col6 ddef2 DEFAULT '88'
392            , col7 ddef4 DEFAULT 8000
393            , col8 ddef5
394            );
395insert into defaulttest(col4) values(0); -- fails, col5 defaults to null
396ERROR:  null value in column "col5" violates not-null constraint
397DETAIL:  Failing row contains (3, 12, 5, 0, null, 88, 8000, 12.12).
398alter table defaulttest alter column col5 drop default;
399insert into defaulttest default values; -- succeeds, inserts domain default
400-- We used to treat SET DEFAULT NULL as equivalent to DROP DEFAULT; wrong
401alter table defaulttest alter column col5 set default null;
402insert into defaulttest(col4) values(0); -- fails
403ERROR:  null value in column "col5" violates not-null constraint
404DETAIL:  Failing row contains (3, 12, 5, 0, null, 88, 8000, 12.12).
405alter table defaulttest alter column col5 drop default;
406insert into defaulttest default values;
407insert into defaulttest default values;
408-- Test defaults with copy
409COPY defaulttest(col5) FROM stdin;
410select * from defaulttest;
411 col1 | col2 | col3 | col4 | col5 | col6 | col7 | col8
412------+------+------+------+------+------+------+-------
413    3 |   12 | 5    |    1 |    3 |   88 | 8000 | 12.12
414    3 |   12 | 5    |    2 |    3 |   88 | 8000 | 12.12
415    3 |   12 | 5    |    3 |    3 |   88 | 8000 | 12.12
416    3 |   12 | 5    |    4 |   42 |   88 | 8000 | 12.12
417(4 rows)
418
419drop table defaulttest cascade;
420-- Test ALTER DOMAIN .. NOT NULL
421create domain dnotnulltest integer;
422create table domnotnull
423( col1 dnotnulltest
424, col2 dnotnulltest
425);
426insert into domnotnull default values;
427alter domain dnotnulltest set not null; -- fails
428ERROR:  column "col1" of table "domnotnull" contains null values
429update domnotnull set col1 = 5;
430alter domain dnotnulltest set not null; -- fails
431ERROR:  column "col2" of table "domnotnull" contains null values
432update domnotnull set col2 = 6;
433alter domain dnotnulltest set not null;
434update domnotnull set col1 = null; -- fails
435ERROR:  domain dnotnulltest does not allow null values
436alter domain dnotnulltest drop not null;
437update domnotnull set col1 = null;
438drop domain dnotnulltest cascade;
439NOTICE:  drop cascades to 2 other objects
440DETAIL:  drop cascades to table domnotnull column col1
441drop cascades to table domnotnull column col2
442-- Test ALTER DOMAIN .. DEFAULT ..
443create table domdeftest (col1 ddef1);
444insert into domdeftest default values;
445select * from domdeftest;
446 col1
447------
448    3
449(1 row)
450
451alter domain ddef1 set default '42';
452insert into domdeftest default values;
453select * from domdeftest;
454 col1
455------
456    3
457   42
458(2 rows)
459
460alter domain ddef1 drop default;
461insert into domdeftest default values;
462select * from domdeftest;
463 col1
464------
465    3
466   42
467
468(3 rows)
469
470drop table domdeftest;
471-- Test ALTER DOMAIN .. CONSTRAINT ..
472create domain con as integer;
473create table domcontest (col1 con);
474insert into domcontest values (1);
475insert into domcontest values (2);
476alter domain con add constraint t check (VALUE < 1); -- fails
477ERROR:  column "col1" of table "domcontest" contains values that violate the new constraint
478alter domain con add constraint t check (VALUE < 34);
479alter domain con add check (VALUE > 0);
480insert into domcontest values (-5); -- fails
481ERROR:  value for domain con violates check constraint "con_check"
482insert into domcontest values (42); -- fails
483ERROR:  value for domain con violates check constraint "t"
484insert into domcontest values (5);
485alter domain con drop constraint t;
486insert into domcontest values (-5); --fails
487ERROR:  value for domain con violates check constraint "con_check"
488insert into domcontest values (42);
489alter domain con drop constraint nonexistent;
490ERROR:  constraint "nonexistent" of domain "con" does not exist
491alter domain con drop constraint if exists nonexistent;
492NOTICE:  constraint "nonexistent" of domain "con" does not exist, skipping
493-- Test ALTER DOMAIN .. CONSTRAINT .. NOT VALID
494create domain things AS INT;
495CREATE TABLE thethings (stuff things);
496INSERT INTO thethings (stuff) VALUES (55);
497ALTER DOMAIN things ADD CONSTRAINT meow CHECK (VALUE < 11);
498ERROR:  column "stuff" of table "thethings" contains values that violate the new constraint
499ALTER DOMAIN things ADD CONSTRAINT meow CHECK (VALUE < 11) NOT VALID;
500ALTER DOMAIN things VALIDATE CONSTRAINT meow;
501ERROR:  column "stuff" of table "thethings" contains values that violate the new constraint
502UPDATE thethings SET stuff = 10;
503ALTER DOMAIN things VALIDATE CONSTRAINT meow;
504-- Confirm ALTER DOMAIN with RULES.
505create table domtab (col1 integer);
506create domain dom as integer;
507create view domview as select cast(col1 as dom) from domtab;
508insert into domtab (col1) values (null);
509insert into domtab (col1) values (5);
510select * from domview;
511 col1
512------
513
514    5
515(2 rows)
516
517alter domain dom set not null;
518select * from domview; -- fail
519ERROR:  domain dom does not allow null values
520alter domain dom drop not null;
521select * from domview;
522 col1
523------
524
525    5
526(2 rows)
527
528alter domain dom add constraint domchkgt6 check(value > 6);
529select * from domview; --fail
530ERROR:  value for domain dom violates check constraint "domchkgt6"
531alter domain dom drop constraint domchkgt6 restrict;
532select * from domview;
533 col1
534------
535
536    5
537(2 rows)
538
539-- cleanup
540drop domain ddef1 restrict;
541drop domain ddef2 restrict;
542drop domain ddef3 restrict;
543drop domain ddef4 restrict;
544drop domain ddef5 restrict;
545drop sequence ddef4_seq;
546-- Test domains over domains
547create domain vchar4 varchar(4);
548create domain dinter vchar4 check (substring(VALUE, 1, 1) = 'x');
549create domain dtop dinter check (substring(VALUE, 2, 1) = '1');
550select 'x123'::dtop;
551 dtop
552------
553 x123
554(1 row)
555
556select 'x1234'::dtop; -- explicit coercion should truncate
557 dtop
558------
559 x123
560(1 row)
561
562select 'y1234'::dtop; -- fail
563ERROR:  value for domain dtop violates check constraint "dinter_check"
564select 'y123'::dtop; -- fail
565ERROR:  value for domain dtop violates check constraint "dinter_check"
566select 'yz23'::dtop; -- fail
567ERROR:  value for domain dtop violates check constraint "dinter_check"
568select 'xz23'::dtop; -- fail
569ERROR:  value for domain dtop violates check constraint "dtop_check"
570create temp table dtest(f1 dtop);
571insert into dtest values('x123');
572insert into dtest values('x1234'); -- fail, implicit coercion
573ERROR:  value too long for type character varying(4)
574insert into dtest values('y1234'); -- fail, implicit coercion
575ERROR:  value too long for type character varying(4)
576insert into dtest values('y123'); -- fail
577ERROR:  value for domain dtop violates check constraint "dinter_check"
578insert into dtest values('yz23'); -- fail
579ERROR:  value for domain dtop violates check constraint "dinter_check"
580insert into dtest values('xz23'); -- fail
581ERROR:  value for domain dtop violates check constraint "dtop_check"
582drop table dtest;
583drop domain vchar4 cascade;
584NOTICE:  drop cascades to 2 other objects
585DETAIL:  drop cascades to type dinter
586drop cascades to type dtop
587-- Make sure that constraints of newly-added domain columns are
588-- enforced correctly, even if there's no default value for the new
589-- column. Per bug #1433
590create domain str_domain as text not null;
591create table domain_test (a int, b int);
592insert into domain_test values (1, 2);
593insert into domain_test values (1, 2);
594-- should fail
595alter table domain_test add column c str_domain;
596ERROR:  domain str_domain does not allow null values
597create domain str_domain2 as text check (value <> 'foo') default 'foo';
598-- should fail
599alter table domain_test add column d str_domain2;
600ERROR:  value for domain str_domain2 violates check constraint "str_domain2_check"
601-- Check that domain constraints on prepared statement parameters of
602-- unknown type are enforced correctly.
603create domain pos_int as int4 check (value > 0) not null;
604prepare s1 as select $1::pos_int = 10 as "is_ten";
605execute s1(10);
606 is_ten
607--------
608 t
609(1 row)
610
611execute s1(0); -- should fail
612ERROR:  value for domain pos_int violates check constraint "pos_int_check"
613execute s1(NULL); -- should fail
614ERROR:  domain pos_int does not allow null values
615-- Check that domain constraints on plpgsql function parameters, results,
616-- and local variables are enforced correctly.
617create function doubledecrement(p1 pos_int) returns pos_int as $$
618declare v pos_int;
619begin
620    return p1;
621end$$ language plpgsql;
622select doubledecrement(3); -- fail because of implicit null assignment
623ERROR:  domain pos_int does not allow null values
624CONTEXT:  PL/pgSQL function doubledecrement(pos_int) line 3 during statement block local variable initialization
625create or replace function doubledecrement(p1 pos_int) returns pos_int as $$
626declare v pos_int := 0;
627begin
628    return p1;
629end$$ language plpgsql;
630select doubledecrement(3); -- fail at initialization assignment
631ERROR:  value for domain pos_int violates check constraint "pos_int_check"
632CONTEXT:  PL/pgSQL function doubledecrement(pos_int) line 3 during statement block local variable initialization
633create or replace function doubledecrement(p1 pos_int) returns pos_int as $$
634declare v pos_int := 1;
635begin
636    v := p1 - 1;
637    return v - 1;
638end$$ language plpgsql;
639select doubledecrement(null); -- fail before call
640ERROR:  domain pos_int does not allow null values
641select doubledecrement(0); -- fail before call
642ERROR:  value for domain pos_int violates check constraint "pos_int_check"
643select doubledecrement(1); -- fail at assignment to v
644ERROR:  value for domain pos_int violates check constraint "pos_int_check"
645CONTEXT:  PL/pgSQL function doubledecrement(pos_int) line 4 at assignment
646select doubledecrement(2); -- fail at return
647ERROR:  value for domain pos_int violates check constraint "pos_int_check"
648CONTEXT:  PL/pgSQL function doubledecrement(pos_int) while casting return value to function's return type
649select doubledecrement(3); -- good
650 doubledecrement
651-----------------
652               1
653(1 row)
654
655-- Check that ALTER DOMAIN tests columns of derived types
656create domain posint as int4;
657-- Currently, this doesn't work for composite types, but verify it complains
658create type ddtest1 as (f1 posint);
659create table ddtest2(f1 ddtest1);
660insert into ddtest2 values(row(-1));
661alter domain posint add constraint c1 check(value >= 0);
662ERROR:  cannot alter type "posint" because column "ddtest2.f1" uses it
663drop table ddtest2;
664-- Likewise for domains within arrays of composite
665create table ddtest2(f1 ddtest1[]);
666insert into ddtest2 values('{(-1)}');
667alter domain posint add constraint c1 check(value >= 0);
668ERROR:  cannot alter type "posint" because column "ddtest2.f1" uses it
669drop table ddtest2;
670-- Likewise for domains within domains over array of composite
671create domain ddtest1d as ddtest1[];
672create table ddtest2(f1 ddtest1d);
673insert into ddtest2 values('{(-1)}');
674alter domain posint add constraint c1 check(value >= 0);
675ERROR:  cannot alter type "posint" because column "ddtest2.f1" uses it
676drop table ddtest2;
677drop domain ddtest1d;
678-- Doesn't work for ranges, either
679create type rposint as range (subtype = posint);
680create table ddtest2(f1 rposint);
681insert into ddtest2 values('(-1,3]');
682alter domain posint add constraint c1 check(value >= 0);
683ERROR:  cannot alter type "posint" because column "ddtest2.f1" uses it
684drop table ddtest2;
685drop type rposint;
686alter domain posint add constraint c1 check(value >= 0);
687create domain posint2 as posint check (value % 2 = 0);
688create table ddtest2(f1 posint2);
689insert into ddtest2 values(11); -- fail
690ERROR:  value for domain posint2 violates check constraint "posint2_check"
691insert into ddtest2 values(-2); -- fail
692ERROR:  value for domain posint2 violates check constraint "c1"
693insert into ddtest2 values(2);
694alter domain posint add constraint c2 check(value >= 10); -- fail
695ERROR:  column "f1" of table "ddtest2" contains values that violate the new constraint
696alter domain posint add constraint c2 check(value > 0); -- OK
697drop table ddtest2;
698drop type ddtest1;
699drop domain posint cascade;
700NOTICE:  drop cascades to type posint2
701--
702-- Check enforcement of domain-related typmod in plpgsql (bug #5717)
703--
704create or replace function array_elem_check(numeric) returns numeric as $$
705declare
706  x numeric(4,2)[1];
707begin
708  x[1] := $1;
709  return x[1];
710end$$ language plpgsql;
711select array_elem_check(121.00);
712ERROR:  numeric field overflow
713DETAIL:  A field with precision 4, scale 2 must round to an absolute value less than 10^2.
714CONTEXT:  PL/pgSQL function array_elem_check(numeric) line 5 at assignment
715select array_elem_check(1.23456);
716 array_elem_check
717------------------
718             1.23
719(1 row)
720
721create domain mynums as numeric(4,2)[1];
722create or replace function array_elem_check(numeric) returns numeric as $$
723declare
724  x mynums;
725begin
726  x[1] := $1;
727  return x[1];
728end$$ language plpgsql;
729select array_elem_check(121.00);
730ERROR:  numeric field overflow
731DETAIL:  A field with precision 4, scale 2 must round to an absolute value less than 10^2.
732CONTEXT:  PL/pgSQL function array_elem_check(numeric) line 5 at assignment
733select array_elem_check(1.23456);
734 array_elem_check
735------------------
736             1.23
737(1 row)
738
739create domain mynums2 as mynums;
740create or replace function array_elem_check(numeric) returns numeric as $$
741declare
742  x mynums2;
743begin
744  x[1] := $1;
745  return x[1];
746end$$ language plpgsql;
747select array_elem_check(121.00);
748ERROR:  numeric field overflow
749DETAIL:  A field with precision 4, scale 2 must round to an absolute value less than 10^2.
750CONTEXT:  PL/pgSQL function array_elem_check(numeric) line 5 at assignment
751select array_elem_check(1.23456);
752 array_elem_check
753------------------
754             1.23
755(1 row)
756
757drop function array_elem_check(numeric);
758--
759-- Check enforcement of array-level domain constraints
760--
761create domain orderedpair as int[2] check (value[1] < value[2]);
762select array[1,2]::orderedpair;
763 array
764-------
765 {1,2}
766(1 row)
767
768select array[2,1]::orderedpair;  -- fail
769ERROR:  value for domain orderedpair violates check constraint "orderedpair_check"
770create temp table op (f1 orderedpair);
771insert into op values (array[1,2]);
772insert into op values (array[2,1]);  -- fail
773ERROR:  value for domain orderedpair violates check constraint "orderedpair_check"
774update op set f1[2] = 3;
775update op set f1[2] = 0;  -- fail
776ERROR:  value for domain orderedpair violates check constraint "orderedpair_check"
777select * from op;
778  f1
779-------
780 {1,3}
781(1 row)
782
783create or replace function array_elem_check(int) returns int as $$
784declare
785  x orderedpair := '{1,2}';
786begin
787  x[2] := $1;
788  return x[2];
789end$$ language plpgsql;
790select array_elem_check(3);
791 array_elem_check
792------------------
793                3
794(1 row)
795
796select array_elem_check(-1);
797ERROR:  value for domain orderedpair violates check constraint "orderedpair_check"
798CONTEXT:  PL/pgSQL function array_elem_check(integer) line 5 at assignment
799drop function array_elem_check(int);
800--
801-- Check enforcement of changing constraints in plpgsql
802--
803create domain di as int;
804create function dom_check(int) returns di as $$
805declare d di;
806begin
807  d := $1;
808  return d;
809end
810$$ language plpgsql immutable;
811select dom_check(0);
812 dom_check
813-----------
814         0
815(1 row)
816
817alter domain di add constraint pos check (value > 0);
818select dom_check(0); -- fail
819ERROR:  value for domain di violates check constraint "pos"
820CONTEXT:  PL/pgSQL function dom_check(integer) line 4 at assignment
821alter domain di drop constraint pos;
822select dom_check(0);
823 dom_check
824-----------
825         0
826(1 row)
827
828drop function dom_check(int);
829drop domain di;
830--
831-- Check use of a (non-inline-able) SQL function in a domain constraint;
832-- this has caused issues in the past
833--
834create function sql_is_distinct_from(anyelement, anyelement)
835returns boolean language sql
836as 'select $1 is distinct from $2 limit 1';
837create domain inotnull int
838  check (sql_is_distinct_from(value, null));
839select 1::inotnull;
840 inotnull
841----------
842        1
843(1 row)
844
845select null::inotnull;
846ERROR:  value for domain inotnull violates check constraint "inotnull_check"
847create table dom_table (x inotnull);
848insert into dom_table values ('1');
849insert into dom_table values (1);
850insert into dom_table values (null);
851ERROR:  value for domain inotnull violates check constraint "inotnull_check"
852drop table dom_table;
853drop domain inotnull;
854drop function sql_is_distinct_from(anyelement, anyelement);
855--
856-- Renaming
857--
858create domain testdomain1 as int;
859alter domain testdomain1 rename to testdomain2;
860alter type testdomain2 rename to testdomain3;  -- alter type also works
861drop domain testdomain3;
862--
863-- Renaming domain constraints
864--
865create domain testdomain1 as int constraint unsigned check (value > 0);
866alter domain testdomain1 rename constraint unsigned to unsigned_foo;
867alter domain testdomain1 drop constraint unsigned_foo;
868drop domain testdomain1;
869