1--
2-- Tests for PL/pgSQL handling of composite (record) variables
3--
4create type two_int4s as (f1 int4, f2 int4);
5create type two_int8s as (q1 int8, q2 int8);
6-- base-case return of a composite type
7create function retc(int) returns two_int8s language plpgsql as
8$$ begin return row($1,1)::two_int8s; end $$;
9select retc(42);
10  retc
11--------
12 (42,1)
13(1 row)
14
15-- ok to return a matching record type
16create or replace function retc(int) returns two_int8s language plpgsql as
17$$ begin return row($1::int8, 1::int8); end $$;
18select retc(42);
19  retc
20--------
21 (42,1)
22(1 row)
23
24-- we don't currently support implicit casting
25create or replace function retc(int) returns two_int8s language plpgsql as
26$$ begin return row($1,1); end $$;
27select retc(42);
28ERROR:  returned record type does not match expected record type
29DETAIL:  Returned type integer does not match expected type bigint in column 1.
30CONTEXT:  PL/pgSQL function retc(integer) while casting return value to function's return type
31-- nor extra columns
32create or replace function retc(int) returns two_int8s language plpgsql as
33$$ begin return row($1::int8, 1::int8, 42); end $$;
34select retc(42);
35ERROR:  returned record type does not match expected record type
36DETAIL:  Number of returned columns (3) does not match expected column count (2).
37CONTEXT:  PL/pgSQL function retc(integer) while casting return value to function's return type
38-- same cases with an intermediate "record" variable
39create or replace function retc(int) returns two_int8s language plpgsql as
40$$ declare r record; begin r := row($1::int8, 1::int8); return r; end $$;
41select retc(42);
42  retc
43--------
44 (42,1)
45(1 row)
46
47create or replace function retc(int) returns two_int8s language plpgsql as
48$$ declare r record; begin r := row($1,1); return r; end $$;
49select retc(42);
50ERROR:  returned record type does not match expected record type
51DETAIL:  Returned type integer does not match expected type bigint in column 1.
52CONTEXT:  PL/pgSQL function retc(integer) while casting return value to function's return type
53create or replace function retc(int) returns two_int8s language plpgsql as
54$$ declare r record; begin r := row($1::int8, 1::int8, 42); return r; end $$;
55select retc(42);
56ERROR:  returned record type does not match expected record type
57DETAIL:  Number of returned columns (3) does not match expected column count (2).
58CONTEXT:  PL/pgSQL function retc(integer) while casting return value to function's return type
59-- but, for mostly historical reasons, we do convert when assigning
60-- to a named-composite-type variable
61create or replace function retc(int) returns two_int8s language plpgsql as
62$$ declare r two_int8s; begin r := row($1::int8, 1::int8, 42); return r; end $$;
63select retc(42);
64  retc
65--------
66 (42,1)
67(1 row)
68
69do $$ declare c two_int8s;
70begin c := row(1,2); raise notice 'c = %', c; end$$;
71NOTICE:  c = (1,2)
72do $$ declare c two_int8s;
73begin for c in select 1,2 loop raise notice 'c = %', c; end loop; end$$;
74NOTICE:  c = (1,2)
75do $$ declare c4 two_int4s; c8 two_int8s;
76begin
77  c8 := row(1,2);
78  c4 := c8;
79  c8 := c4;
80  raise notice 'c4 = %', c4;
81  raise notice 'c8 = %', c8;
82end$$;
83NOTICE:  c4 = (1,2)
84NOTICE:  c8 = (1,2)
85-- check passing composite result to another function
86create function getq1(two_int8s) returns int8 language plpgsql as $$
87declare r two_int8s; begin r := $1; return r.q1; end $$;
88select getq1(retc(344));
89 getq1
90-------
91   344
92(1 row)
93
94select getq1(row(1,2));
95 getq1
96-------
97     1
98(1 row)
99
100do $$
101declare r1 two_int8s; r2 record; x int8;
102begin
103  r1 := retc(345);
104  perform getq1(r1);
105  x := getq1(r1);
106  raise notice 'x = %', x;
107  r2 := retc(346);
108  perform getq1(r2);
109  x := getq1(r2);
110  raise notice 'x = %', x;
111end$$;
112NOTICE:  x = 345
113NOTICE:  x = 346
114-- check assignments of composites
115do $$
116declare r1 two_int8s; r2 two_int8s; r3 record; r4 record;
117begin
118  r1 := row(1,2);
119  raise notice 'r1 = %', r1;
120  r1 := r1;  -- shouldn't do anything
121  raise notice 'r1 = %', r1;
122  r2 := r1;
123  raise notice 'r1 = %', r1;
124  raise notice 'r2 = %', r2;
125  r2.q2 = r1.q1 + 3;  -- check that r2 has distinct storage
126  raise notice 'r1 = %', r1;
127  raise notice 'r2 = %', r2;
128  r1 := null;
129  raise notice 'r1 = %', r1;
130  raise notice 'r2 = %', r2;
131  r1 := row(7,11)::two_int8s;
132  r2 := r1;
133  raise notice 'r1 = %', r1;
134  raise notice 'r2 = %', r2;
135  r3 := row(1,2);
136  r4 := r3;
137  raise notice 'r3 = %', r3;
138  raise notice 'r4 = %', r4;
139  r4.f1 := r4.f1 + 3;  -- check that r4 has distinct storage
140  raise notice 'r3 = %', r3;
141  raise notice 'r4 = %', r4;
142  r1 := r3;
143  raise notice 'r1 = %', r1;
144  r4 := r1;
145  raise notice 'r4 = %', r4;
146  r4.q2 := r4.q2 + 1;  -- r4's field names have changed
147  raise notice 'r4 = %', r4;
148end$$;
149NOTICE:  r1 = (1,2)
150NOTICE:  r1 = (1,2)
151NOTICE:  r1 = (1,2)
152NOTICE:  r2 = (1,2)
153NOTICE:  r1 = (1,2)
154NOTICE:  r2 = (1,4)
155NOTICE:  r1 = <NULL>
156NOTICE:  r2 = (1,4)
157NOTICE:  r1 = (7,11)
158NOTICE:  r2 = (7,11)
159NOTICE:  r3 = (1,2)
160NOTICE:  r4 = (1,2)
161NOTICE:  r3 = (1,2)
162NOTICE:  r4 = (4,2)
163NOTICE:  r1 = (1,2)
164NOTICE:  r4 = (1,2)
165NOTICE:  r4 = (1,3)
166-- fields of named-type vars read as null if uninitialized
167do $$
168declare r1 two_int8s;
169begin
170  raise notice 'r1 = %', r1;
171  raise notice 'r1.q1 = %', r1.q1;
172  raise notice 'r1.q2 = %', r1.q2;
173  raise notice 'r1 = %', r1;
174end$$;
175NOTICE:  r1 = <NULL>
176NOTICE:  r1.q1 = <NULL>
177NOTICE:  r1.q2 = <NULL>
178NOTICE:  r1 = <NULL>
179do $$
180declare r1 two_int8s;
181begin
182  raise notice 'r1.q1 = %', r1.q1;
183  raise notice 'r1.q2 = %', r1.q2;
184  raise notice 'r1 = %', r1;
185  raise notice 'r1.nosuchfield = %', r1.nosuchfield;
186end$$;
187NOTICE:  r1.q1 = <NULL>
188NOTICE:  r1.q2 = <NULL>
189NOTICE:  r1 = <NULL>
190ERROR:  record "r1" has no field "nosuchfield"
191CONTEXT:  SQL statement "SELECT r1.nosuchfield"
192PL/pgSQL function inline_code_block line 7 at RAISE
193-- records, not so much
194do $$
195declare r1 record;
196begin
197  raise notice 'r1 = %', r1;
198  raise notice 'r1.f1 = %', r1.f1;
199  raise notice 'r1.f2 = %', r1.f2;
200  raise notice 'r1 = %', r1;
201end$$;
202NOTICE:  r1 = <NULL>
203ERROR:  record "r1" is not assigned yet
204DETAIL:  The tuple structure of a not-yet-assigned record is indeterminate.
205CONTEXT:  SQL statement "SELECT r1.f1"
206PL/pgSQL function inline_code_block line 5 at RAISE
207-- but OK if you assign first
208do $$
209declare r1 record;
210begin
211  raise notice 'r1 = %', r1;
212  r1 := row(1,2);
213  raise notice 'r1.f1 = %', r1.f1;
214  raise notice 'r1.f2 = %', r1.f2;
215  raise notice 'r1 = %', r1;
216  raise notice 'r1.nosuchfield = %', r1.nosuchfield;
217end$$;
218NOTICE:  r1 = <NULL>
219NOTICE:  r1.f1 = 1
220NOTICE:  r1.f2 = 2
221NOTICE:  r1 = (1,2)
222ERROR:  record "r1" has no field "nosuchfield"
223CONTEXT:  SQL statement "SELECT r1.nosuchfield"
224PL/pgSQL function inline_code_block line 9 at RAISE
225-- check repeated assignments to composite fields
226create table some_table (id int, data text);
227do $$
228declare r some_table;
229begin
230  r := (23, 'skidoo');
231  for i in 1 .. 10 loop
232    r.id := r.id + i;
233    r.data := r.data || ' ' || i;
234  end loop;
235  raise notice 'r = %', r;
236end$$;
237NOTICE:  r = (78,"skidoo 1 2 3 4 5 6 7 8 9 10")
238-- check behavior of function declared to return "record"
239create function returnsrecord(int) returns record language plpgsql as
240$$ begin return row($1,$1+1); end $$;
241select returnsrecord(42);
242 returnsrecord
243---------------
244 (42,43)
245(1 row)
246
247select * from returnsrecord(42) as r(x int, y int);
248 x  | y
249----+----
250 42 | 43
251(1 row)
252
253select * from returnsrecord(42) as r(x int, y int, z int);  -- fail
254ERROR:  returned record type does not match expected record type
255DETAIL:  Number of returned columns (2) does not match expected column count (3).
256CONTEXT:  PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
257select * from returnsrecord(42) as r(x int, y bigint);  -- fail
258ERROR:  returned record type does not match expected record type
259DETAIL:  Returned type integer does not match expected type bigint in column 2.
260CONTEXT:  PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
261-- same with an intermediate record variable
262create or replace function returnsrecord(int) returns record language plpgsql as
263$$ declare r record; begin r := row($1,$1+1); return r; end $$;
264select returnsrecord(42);
265 returnsrecord
266---------------
267 (42,43)
268(1 row)
269
270select * from returnsrecord(42) as r(x int, y int);
271 x  | y
272----+----
273 42 | 43
274(1 row)
275
276select * from returnsrecord(42) as r(x int, y int, z int);  -- fail
277ERROR:  returned record type does not match expected record type
278DETAIL:  Number of returned columns (2) does not match expected column count (3).
279CONTEXT:  PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
280select * from returnsrecord(42) as r(x int, y bigint);  -- fail
281ERROR:  returned record type does not match expected record type
282DETAIL:  Returned type integer does not match expected type bigint in column 2.
283CONTEXT:  PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
284-- should work the same with a missing column in the actual result value
285create table has_hole(f1 int, f2 int, f3 int);
286alter table has_hole drop column f2;
287create or replace function returnsrecord(int) returns record language plpgsql as
288$$ begin return row($1,$1+1)::has_hole; end $$;
289select returnsrecord(42);
290 returnsrecord
291---------------
292 (42,43)
293(1 row)
294
295select * from returnsrecord(42) as r(x int, y int);
296 x  | y
297----+----
298 42 | 43
299(1 row)
300
301select * from returnsrecord(42) as r(x int, y int, z int);  -- fail
302ERROR:  returned record type does not match expected record type
303DETAIL:  Number of returned columns (2) does not match expected column count (3).
304CONTEXT:  PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
305select * from returnsrecord(42) as r(x int, y bigint);  -- fail
306ERROR:  returned record type does not match expected record type
307DETAIL:  Returned type integer does not match expected type bigint in column 2.
308CONTEXT:  PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
309-- same with an intermediate record variable
310create or replace function returnsrecord(int) returns record language plpgsql as
311$$ declare r record; begin r := row($1,$1+1)::has_hole; return r; end $$;
312select returnsrecord(42);
313 returnsrecord
314---------------
315 (42,43)
316(1 row)
317
318select * from returnsrecord(42) as r(x int, y int);
319 x  | y
320----+----
321 42 | 43
322(1 row)
323
324select * from returnsrecord(42) as r(x int, y int, z int);  -- fail
325ERROR:  returned record type does not match expected record type
326DETAIL:  Number of returned columns (2) does not match expected column count (3).
327CONTEXT:  PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
328select * from returnsrecord(42) as r(x int, y bigint);  -- fail
329ERROR:  returned record type does not match expected record type
330DETAIL:  Returned type integer does not match expected type bigint in column 2.
331CONTEXT:  PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
332-- check access to a field of an argument declared "record"
333create function getf1(x record) returns int language plpgsql as
334$$ begin return x.f1; end $$;
335select getf1(1);
336ERROR:  function getf1(integer) does not exist
337LINE 1: select getf1(1);
338               ^
339HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
340select getf1(row(1,2));
341 getf1
342-------
343     1
344(1 row)
345
346-- a CLOBBER_CACHE_ALWAYS build will report this error with a different
347-- context stack than other builds, so suppress context output
348\set SHOW_CONTEXT never
349select getf1(row(1,2)::two_int8s);
350ERROR:  record "x" has no field "f1"
351\set SHOW_CONTEXT errors
352select getf1(row(1,2));
353 getf1
354-------
355     1
356(1 row)
357
358-- check behavior when assignment to FOR-loop variable requires coercion
359do $$
360declare r two_int8s;
361begin
362  for r in select i, i+1 from generate_series(1,4) i
363  loop
364    raise notice 'r = %', r;
365  end loop;
366end$$;
367NOTICE:  r = (1,2)
368NOTICE:  r = (2,3)
369NOTICE:  r = (3,4)
370NOTICE:  r = (4,5)
371-- check behavior when returning setof composite
372create function returnssetofholes() returns setof has_hole language plpgsql as
373$$
374declare r record;
375  h has_hole;
376begin
377  return next h;
378  r := (1,2);
379  h := (3,4);
380  return next r;
381  return next h;
382  return next row(5,6);
383  return next row(7,8)::has_hole;
384end$$;
385select returnssetofholes();
386 returnssetofholes
387-------------------
388 (,)
389 (1,2)
390 (3,4)
391 (5,6)
392 (7,8)
393(5 rows)
394
395create or replace function returnssetofholes() returns setof has_hole language plpgsql as
396$$
397declare r record;
398begin
399  return next r;  -- fails, not assigned yet
400end$$;
401select returnssetofholes();
402ERROR:  record "r" is not assigned yet
403DETAIL:  The tuple structure of a not-yet-assigned record is indeterminate.
404CONTEXT:  PL/pgSQL function returnssetofholes() line 4 at RETURN NEXT
405create or replace function returnssetofholes() returns setof has_hole language plpgsql as
406$$
407begin
408  return next row(1,2,3);  -- fails
409end$$;
410select returnssetofholes();
411ERROR:  returned record type does not match expected record type
412DETAIL:  Number of returned columns (3) does not match expected column count (2).
413CONTEXT:  PL/pgSQL function returnssetofholes() line 3 at RETURN NEXT
414-- check behavior with changes of a named rowtype
415create table mutable(f1 int, f2 text);
416create function sillyaddone(int) returns int language plpgsql as
417$$ declare r mutable; begin r.f1 := $1; return r.f1 + 1; end $$;
418select sillyaddone(42);
419 sillyaddone
420-------------
421          43
422(1 row)
423
424-- test for change of type of column f1 should be here someday;
425-- for now see plpgsql_cache test
426alter table mutable drop column f1;
427select sillyaddone(42);  -- fail
428ERROR:  record "r" has no field "f1"
429CONTEXT:  PL/pgSQL function sillyaddone(integer) line 1 at assignment
430create function getf3(x mutable) returns int language plpgsql as
431$$ begin return x.f3; end $$;
432select getf3(null::mutable);  -- doesn't work yet
433ERROR:  record "x" has no field "f3"
434CONTEXT:  SQL statement "SELECT x.f3"
435PL/pgSQL function getf3(mutable) line 1 at RETURN
436alter table mutable add column f3 int;
437select getf3(null::mutable);  -- now it works
438 getf3
439-------
440
441(1 row)
442
443alter table mutable drop column f3;
444-- a CLOBBER_CACHE_ALWAYS build will report this error with a different
445-- context stack than other builds, so suppress context output
446\set SHOW_CONTEXT never
447select getf3(null::mutable);  -- fails again
448ERROR:  record "x" has no field "f3"
449\set SHOW_CONTEXT errors
450-- check behavior with creating/dropping a named rowtype
451set check_function_bodies = off;  -- else reference to nonexistent type fails
452create function sillyaddtwo(int) returns int language plpgsql as
453$$ declare r mutable2; begin r.f1 := $1; return r.f1 + 2; end $$;
454reset check_function_bodies;
455select sillyaddtwo(42);  -- fail
456ERROR:  type "mutable2" does not exist
457LINE 1:  declare r mutable2; begin r.f1 := $1; return r.f1 + 2; end
458                   ^
459QUERY:   declare r mutable2; begin r.f1 := $1; return r.f1 + 2; end
460CONTEXT:  compilation of PL/pgSQL function "sillyaddtwo" near line 1
461create table mutable2(f1 int, f2 text);
462select sillyaddtwo(42);
463 sillyaddtwo
464-------------
465          44
466(1 row)
467
468drop table mutable2;
469select sillyaddtwo(42);  -- fail
470ERROR:  type "mutable2" does not exist
471CONTEXT:  PL/pgSQL function sillyaddtwo(integer) line 1 at assignment
472create table mutable2(f0 text, f1 int, f2 text);
473select sillyaddtwo(42);
474 sillyaddtwo
475-------------
476          44
477(1 row)
478
479select sillyaddtwo(43);
480 sillyaddtwo
481-------------
482          45
483(1 row)
484
485-- check access to system columns in a record variable
486create function sillytrig() returns trigger language plpgsql as
487$$begin
488  raise notice 'old.ctid = %', old.ctid;
489  raise notice 'old.tableoid = %', old.tableoid::regclass;
490  return new;
491end$$;
492create trigger mutable_trig before update on mutable for each row
493execute procedure sillytrig();
494insert into mutable values ('foo'), ('bar');
495update mutable set f2 = f2 || ' baz';
496NOTICE:  old.ctid = (0,1)
497NOTICE:  old.tableoid = mutable
498NOTICE:  old.ctid = (0,2)
499NOTICE:  old.tableoid = mutable
500table mutable;
501   f2
502---------
503 foo baz
504 bar baz
505(2 rows)
506
507-- check returning a composite datum from a trigger
508create or replace function sillytrig() returns trigger language plpgsql as
509$$begin
510  return row(new.*);
511end$$;
512update mutable set f2 = f2 || ' baz';
513table mutable;
514     f2
515-------------
516 foo baz baz
517 bar baz baz
518(2 rows)
519
520create or replace function sillytrig() returns trigger language plpgsql as
521$$declare r record;
522begin
523  r := row(new.*);
524  return r;
525end$$;
526update mutable set f2 = f2 || ' baz';
527table mutable;
528       f2
529-----------------
530 foo baz baz baz
531 bar baz baz baz
532(2 rows)
533
534--
535-- Domains of composite
536--
537create domain ordered_int8s as two_int8s check((value).q1 <= (value).q2);
538create function read_ordered_int8s(p ordered_int8s) returns int8 as $$
539begin return p.q1 + p.q2; end
540$$ language plpgsql;
541select read_ordered_int8s(row(1, 2));
542 read_ordered_int8s
543--------------------
544                  3
545(1 row)
546
547select read_ordered_int8s(row(2, 1));  -- fail
548ERROR:  value for domain ordered_int8s violates check constraint "ordered_int8s_check"
549create function build_ordered_int8s(i int8, j int8) returns ordered_int8s as $$
550begin return row(i,j); end
551$$ language plpgsql;
552select build_ordered_int8s(1,2);
553 build_ordered_int8s
554---------------------
555 (1,2)
556(1 row)
557
558select build_ordered_int8s(2,1);  -- fail
559ERROR:  value for domain ordered_int8s violates check constraint "ordered_int8s_check"
560CONTEXT:  PL/pgSQL function build_ordered_int8s(bigint,bigint) while casting return value to function's return type
561create function build_ordered_int8s_2(i int8, j int8) returns ordered_int8s as $$
562declare r record; begin r := row(i,j); return r; end
563$$ language plpgsql;
564select build_ordered_int8s_2(1,2);
565 build_ordered_int8s_2
566-----------------------
567 (1,2)
568(1 row)
569
570select build_ordered_int8s_2(2,1);  -- fail
571ERROR:  value for domain ordered_int8s violates check constraint "ordered_int8s_check"
572CONTEXT:  PL/pgSQL function build_ordered_int8s_2(bigint,bigint) while casting return value to function's return type
573create function build_ordered_int8s_3(i int8, j int8) returns ordered_int8s as $$
574declare r two_int8s; begin r := row(i,j); return r; end
575$$ language plpgsql;
576select build_ordered_int8s_3(1,2);
577 build_ordered_int8s_3
578-----------------------
579 (1,2)
580(1 row)
581
582select build_ordered_int8s_3(2,1);  -- fail
583ERROR:  value for domain ordered_int8s violates check constraint "ordered_int8s_check"
584CONTEXT:  PL/pgSQL function build_ordered_int8s_3(bigint,bigint) while casting return value to function's return type
585create function build_ordered_int8s_4(i int8, j int8) returns ordered_int8s as $$
586declare r ordered_int8s; begin r := row(i,j); return r; end
587$$ language plpgsql;
588select build_ordered_int8s_4(1,2);
589 build_ordered_int8s_4
590-----------------------
591 (1,2)
592(1 row)
593
594select build_ordered_int8s_4(2,1);  -- fail
595ERROR:  value for domain ordered_int8s violates check constraint "ordered_int8s_check"
596CONTEXT:  PL/pgSQL function build_ordered_int8s_4(bigint,bigint) line 2 at assignment
597create function build_ordered_int8s_a(i int8, j int8) returns ordered_int8s[] as $$
598begin return array[row(i,j), row(i,j+1)]; end
599$$ language plpgsql;
600select build_ordered_int8s_a(1,2);
601 build_ordered_int8s_a
602-----------------------
603 {"(1,2)","(1,3)"}
604(1 row)
605
606select build_ordered_int8s_a(2,1);  -- fail
607ERROR:  value for domain ordered_int8s violates check constraint "ordered_int8s_check"
608CONTEXT:  PL/pgSQL function build_ordered_int8s_a(bigint,bigint) while casting return value to function's return type
609-- check field assignment
610do $$
611declare r ordered_int8s;
612begin
613  r.q1 := null;
614  r.q2 := 43;
615  r.q1 := 42;
616  r.q2 := 41;  -- fail
617end$$;
618ERROR:  value for domain ordered_int8s violates check constraint "ordered_int8s_check"
619CONTEXT:  PL/pgSQL function inline_code_block line 7 at assignment
620-- check whole-row assignment
621do $$
622declare r ordered_int8s;
623begin
624  r := null;
625  r := row(null,null);
626  r := row(1,2);
627  r := row(2,1);  -- fail
628end$$;
629ERROR:  value for domain ordered_int8s violates check constraint "ordered_int8s_check"
630CONTEXT:  PL/pgSQL function inline_code_block line 7 at assignment
631-- check assignment in for-loop
632do $$
633declare r ordered_int8s;
634begin
635  for r in values (1,2),(3,4),(6,5) loop
636    raise notice 'r = %', r;
637  end loop;
638end$$;
639NOTICE:  r = (1,2)
640NOTICE:  r = (3,4)
641ERROR:  value for domain ordered_int8s violates check constraint "ordered_int8s_check"
642CONTEXT:  PL/pgSQL function inline_code_block line 4 at FOR over SELECT rows
643-- check behavior with toastable fields, too
644create type two_texts as (f1 text, f2 text);
645create domain ordered_texts as two_texts check((value).f1 <= (value).f2);
646create table sometable (id int, a text, b text);
647-- b should be compressed, but in-line
648insert into sometable values (1, 'a', repeat('ffoob',1000));
649-- this b should be out-of-line
650insert into sometable values (2, 'a', repeat('ffoob',100000));
651-- this pair should fail the domain check
652insert into sometable values (3, 'z', repeat('ffoob',100000));
653do $$
654declare d ordered_texts;
655begin
656  for d in select a, b from sometable loop
657    raise notice 'succeeded at "%"', d.f1;
658  end loop;
659end$$;
660NOTICE:  succeeded at "a"
661NOTICE:  succeeded at "a"
662ERROR:  value for domain ordered_texts violates check constraint "ordered_texts_check"
663CONTEXT:  PL/pgSQL function inline_code_block line 4 at FOR over SELECT rows
664do $$
665declare r record; d ordered_texts;
666begin
667  for r in select * from sometable loop
668    raise notice 'processing row %', r.id;
669    d := row(r.a, r.b);
670  end loop;
671end$$;
672NOTICE:  processing row 1
673NOTICE:  processing row 2
674NOTICE:  processing row 3
675ERROR:  value for domain ordered_texts violates check constraint "ordered_texts_check"
676CONTEXT:  PL/pgSQL function inline_code_block line 6 at assignment
677do $$
678declare r record; d ordered_texts;
679begin
680  for r in select * from sometable loop
681    raise notice 'processing row %', r.id;
682    d := null;
683    d.f1 := r.a;
684    d.f2 := r.b;
685  end loop;
686end$$;
687NOTICE:  processing row 1
688NOTICE:  processing row 2
689NOTICE:  processing row 3
690ERROR:  value for domain ordered_texts violates check constraint "ordered_texts_check"
691CONTEXT:  PL/pgSQL function inline_code_block line 8 at assignment
692-- check coercion of a record result to named-composite function output type
693create function compresult(int8) returns two_int8s language plpgsql as
694$$ declare r record; begin r := row($1,$1); return r; end $$;
695create table two_int8s_tab (f1 two_int8s);
696insert into two_int8s_tab values (compresult(42));
697-- reconnect so we lose any local knowledge of anonymous record types
698\c -
699table two_int8s_tab;
700   f1
701---------
702 (42,42)
703(1 row)
704
705