2 -- Test result value processing
4 CREATE OR REPLACE FUNCTION perl_int(int) RETURNS INTEGER AS $$
13 SELECT * FROM perl_int(42);
19 CREATE OR REPLACE FUNCTION perl_int(int) RETURNS INTEGER AS $$
28 SELECT * FROM perl_int(42);
34 CREATE OR REPLACE FUNCTION perl_set_int(int) RETURNS SETOF INTEGER AS $$
37 SELECT perl_set_int(5);
42 SELECT * FROM perl_set_int(5);
47 CREATE OR REPLACE FUNCTION perl_set_int(int) RETURNS SETOF INTEGER AS $$
50 SELECT perl_set_int(5);
61 SELECT * FROM perl_set_int(5);
72 CREATE TYPE testnestperl AS (f5 integer[]);
73 CREATE TYPE testrowperl AS (f1 integer, f2 text, f3 text, f4 testnestperl);
74 CREATE OR REPLACE FUNCTION perl_row() RETURNS testrowperl AS $$
83 SELECT * FROM perl_row();
89 CREATE OR REPLACE FUNCTION perl_row() RETURNS testrowperl AS $$
90 return {f2 => 'hello', f1 => 1, f3 => 'world', 'f4' => { 'f5' => [[1]] } };
94 ---------------------------
95 (1,hello,world,"({{1}})")
98 SELECT * FROM perl_row();
100 ----+-------+-------+---------
101 1 | hello | world | ({{1}})
104 -- test returning a composite literal
105 CREATE OR REPLACE FUNCTION perl_row_lit() RETURNS testrowperl AS $$
106 return '(1,hello,world,"({{1}})")';
108 SELECT perl_row_lit();
110 ---------------------------
111 (1,hello,world,"({{1}})")
114 CREATE OR REPLACE FUNCTION perl_set() RETURNS SETOF testrowperl AS $$
122 SELECT * FROM perl_set();
127 CREATE OR REPLACE FUNCTION perl_set() RETURNS SETOF testrowperl AS $$
129 { f1 => 1, f2 => 'Hello', f3 => 'World' },
131 { f1 => 3, f2 => 'Hello', f3 => 'PL/Perl', 'f4' => {} },
132 { f1 => 4, f2 => 'Hello', f3 => 'PL/Perl', 'f4' => { 'f5' => undef }},
133 { f1 => 5, f2 => 'Hello', f3 => 'PL/Perl', 'f4' => { 'f5' => '{1}' }},
134 { f1 => 6, f2 => 'Hello', f3 => 'PL/Perl', 'f4' => { 'f5' => [1] }},
138 ERROR: SETOF-composite-returning PL/Perl function must call return_next with reference to hash
139 CONTEXT: PL/Perl function "perl_set"
140 SELECT * FROM perl_set();
141 ERROR: SETOF-composite-returning PL/Perl function must call return_next with reference to hash
142 CONTEXT: PL/Perl function "perl_set"
143 CREATE OR REPLACE FUNCTION perl_set() RETURNS SETOF testrowperl AS $$
145 { f1 => 1, f2 => 'Hello', f3 => 'World' },
146 { f1 => 2, f2 => 'Hello', f3 => 'PostgreSQL', 'f4' => undef },
147 { f1 => 3, f2 => 'Hello', f3 => 'PL/Perl', 'f4' => {} },
148 { f1 => 4, f2 => 'Hello', f3 => 'PL/Perl', 'f4' => { 'f5' => undef }},
149 { f1 => 5, f2 => 'Hello', f3 => 'PL/Perl', 'f4' => { 'f5' => '{1}' }},
150 { f1 => 6, f2 => 'Hello', f3 => 'PL/Perl', 'f4' => { 'f5' => [1] }},
151 { f1 => 7, f2 => 'Hello', f3 => 'PL/Perl', 'f4' => '({1})' },
156 ---------------------------
158 (2,Hello,PostgreSQL,)
159 (3,Hello,PL/Perl,"()")
160 (4,Hello,PL/Perl,"()")
161 (5,Hello,PL/Perl,"({1})")
162 (6,Hello,PL/Perl,"({1})")
163 (7,Hello,PL/Perl,"({1})")
166 SELECT * FROM perl_set();
168 ----+-------+------------+-------
170 2 | Hello | PostgreSQL |
171 3 | Hello | PL/Perl | ()
172 4 | Hello | PL/Perl | ()
173 5 | Hello | PL/Perl | ({1})
174 6 | Hello | PL/Perl | ({1})
175 7 | Hello | PL/Perl | ({1})
178 CREATE OR REPLACE FUNCTION perl_record() RETURNS record AS $$
181 SELECT perl_record();
187 SELECT * FROM perl_record();
188 ERROR: a column definition list is required for functions returning "record"
189 LINE 1: SELECT * FROM perl_record();
191 SELECT * FROM perl_record() AS (f1 integer, f2 text, f3 text, f4 testnestperl);
197 CREATE OR REPLACE FUNCTION perl_record() RETURNS record AS $$
198 return {f2 => 'hello', f1 => 1, f3 => 'world', 'f4' => { 'f5' => [1] } };
200 SELECT perl_record();
201 ERROR: function returning record called in context that cannot accept type record
202 CONTEXT: PL/Perl function "perl_record"
203 SELECT * FROM perl_record();
204 ERROR: a column definition list is required for functions returning "record"
205 LINE 1: SELECT * FROM perl_record();
207 SELECT * FROM perl_record() AS (f1 integer, f2 text, f3 text, f4 testnestperl);
209 ----+-------+-------+-------
210 1 | hello | world | ({1})
213 CREATE OR REPLACE FUNCTION perl_record_set() RETURNS SETOF record AS $$
216 SELECT perl_record_set();
221 SELECT * FROM perl_record_set();
222 ERROR: a column definition list is required for functions returning "record"
223 LINE 1: SELECT * FROM perl_record_set();
225 SELECT * FROM perl_record_set() AS (f1 integer, f2 text, f3 text);
230 CREATE OR REPLACE FUNCTION perl_record_set() RETURNS SETOF record AS $$
232 { f1 => 1, f2 => 'Hello', f3 => 'World' },
234 { f1 => 3, f2 => 'Hello', f3 => 'PL/Perl' }
237 SELECT perl_record_set();
238 ERROR: function returning record called in context that cannot accept type record
239 CONTEXT: PL/Perl function "perl_record_set"
240 SELECT * FROM perl_record_set();
241 ERROR: a column definition list is required for functions returning "record"
242 LINE 1: SELECT * FROM perl_record_set();
244 SELECT * FROM perl_record_set() AS (f1 integer, f2 text, f3 text);
245 ERROR: SETOF-composite-returning PL/Perl function must call return_next with reference to hash
246 CONTEXT: PL/Perl function "perl_record_set"
247 CREATE OR REPLACE FUNCTION perl_record_set() RETURNS SETOF record AS $$
249 { f1 => 1, f2 => 'Hello', f3 => 'World' },
250 { f1 => 2, f2 => 'Hello', f3 => 'PostgreSQL' },
251 { f1 => 3, f2 => 'Hello', f3 => 'PL/Perl' }
254 SELECT perl_record_set();
255 ERROR: function returning record called in context that cannot accept type record
256 CONTEXT: PL/Perl function "perl_record_set"
257 SELECT * FROM perl_record_set();
258 ERROR: a column definition list is required for functions returning "record"
259 LINE 1: SELECT * FROM perl_record_set();
261 SELECT * FROM perl_record_set() AS (f1 integer, f2 text, f3 text);
263 ----+-------+------------
265 2 | Hello | PostgreSQL
269 CREATE OR REPLACE FUNCTION
270 perl_out_params(f1 out integer, f2 out text, f3 out text) AS $$
271 return {f2 => 'hello', f1 => 1, f3 => 'world'};
273 SELECT perl_out_params();
279 SELECT * FROM perl_out_params();
285 SELECT (perl_out_params()).f2;
291 CREATE OR REPLACE FUNCTION
292 perl_out_params_set(out f1 integer, out f2 text, out f3 text)
293 RETURNS SETOF record AS $$
295 { f1 => 1, f2 => 'Hello', f3 => 'World' },
296 { f1 => 2, f2 => 'Hello', f3 => 'PostgreSQL' },
297 { f1 => 3, f2 => 'Hello', f3 => 'PL/Perl' }
300 SELECT perl_out_params_set();
302 ----------------------
308 SELECT * FROM perl_out_params_set();
310 ----+-------+------------
312 2 | Hello | PostgreSQL
316 SELECT (perl_out_params_set()).f3;
325 -- Check behavior with erroneous return values
327 CREATE TYPE footype AS (x INTEGER, y INTEGER);
328 CREATE OR REPLACE FUNCTION foo_good() RETURNS SETOF footype AS $$
334 SELECT * FROM foo_good();
341 CREATE OR REPLACE FUNCTION foo_bad() RETURNS footype AS $$
342 return {y => 3, z => 4};
344 SELECT * FROM foo_bad();
345 ERROR: Perl hash contains nonexistent column "z"
346 CONTEXT: PL/Perl function "foo_bad"
347 CREATE OR REPLACE FUNCTION foo_bad() RETURNS footype AS $$
350 SELECT * FROM foo_bad();
351 ERROR: malformed record literal: "42"
352 DETAIL: Missing left parenthesis.
353 CONTEXT: PL/Perl function "foo_bad"
354 CREATE OR REPLACE FUNCTION foo_bad() RETURNS footype AS $$
360 SELECT * FROM foo_bad();
361 ERROR: cannot convert Perl array to non-array type footype
362 CONTEXT: PL/Perl function "foo_bad"
363 CREATE OR REPLACE FUNCTION foo_set_bad() RETURNS SETOF footype AS $$
366 SELECT * FROM foo_set_bad();
367 ERROR: set-returning PL/Perl function must return reference to array or use return_next
368 CONTEXT: PL/Perl function "foo_set_bad"
369 CREATE OR REPLACE FUNCTION foo_set_bad() RETURNS SETOF footype AS $$
370 return {y => 3, z => 4};
372 SELECT * FROM foo_set_bad();
373 ERROR: set-returning PL/Perl function must return reference to array or use return_next
374 CONTEXT: PL/Perl function "foo_set_bad"
375 CREATE OR REPLACE FUNCTION foo_set_bad() RETURNS SETOF footype AS $$
381 SELECT * FROM foo_set_bad();
382 ERROR: SETOF-composite-returning PL/Perl function must call return_next with reference to hash
383 CONTEXT: PL/Perl function "foo_set_bad"
384 CREATE OR REPLACE FUNCTION foo_set_bad() RETURNS SETOF footype AS $$
389 SELECT * FROM foo_set_bad();
390 ERROR: Perl hash contains nonexistent column "z"
391 CONTEXT: PL/Perl function "foo_set_bad"
392 CREATE DOMAIN orderedfootype AS footype CHECK ((VALUE).x <= (VALUE).y);
393 CREATE OR REPLACE FUNCTION foo_ordered() RETURNS orderedfootype AS $$
394 return {x => 3, y => 4};
396 SELECT * FROM foo_ordered();
402 CREATE OR REPLACE FUNCTION foo_ordered() RETURNS orderedfootype AS $$
403 return {x => 5, y => 4};
405 SELECT * FROM foo_ordered(); -- fail
406 ERROR: value for domain orderedfootype violates check constraint "orderedfootype_check"
407 CONTEXT: PL/Perl function "foo_ordered"
408 CREATE OR REPLACE FUNCTION foo_ordered_set() RETURNS SETOF orderedfootype AS $$
414 SELECT * FROM foo_ordered_set();
421 CREATE OR REPLACE FUNCTION foo_ordered_set() RETURNS SETOF orderedfootype AS $$
427 SELECT * FROM foo_ordered_set(); -- fail
428 ERROR: value for domain orderedfootype violates check constraint "orderedfootype_check"
429 CONTEXT: PL/Perl function "foo_ordered_set"
431 -- Check passing a tuple argument
433 CREATE OR REPLACE FUNCTION perl_get_field(footype, text) RETURNS integer AS $$
434 return $_[0]->{$_[1]};
436 SELECT perl_get_field((11,12), 'x');
442 SELECT perl_get_field((11,12), 'y');
448 SELECT perl_get_field((11,12), 'z');
454 CREATE OR REPLACE FUNCTION perl_get_cfield(orderedfootype, text) RETURNS integer AS $$
455 return $_[0]->{$_[1]};
457 SELECT perl_get_cfield((11,12), 'x');
463 SELECT perl_get_cfield((11,12), 'y');
469 SELECT perl_get_cfield((12,11), 'x'); -- fail
470 ERROR: value for domain orderedfootype violates check constraint "orderedfootype_check"
471 CREATE OR REPLACE FUNCTION perl_get_rfield(record, text) RETURNS integer AS $$
472 return $_[0]->{$_[1]};
474 SELECT perl_get_rfield((11,12), 'f1');
480 SELECT perl_get_rfield((11,12)::footype, 'y');
486 SELECT perl_get_rfield((11,12)::orderedfootype, 'x');
492 SELECT perl_get_rfield((12,11)::orderedfootype, 'x'); -- fail
493 ERROR: value for domain orderedfootype violates check constraint "orderedfootype_check"
497 CREATE OR REPLACE FUNCTION perl_srf_rn() RETURNS SETOF RECORD AS $$
499 for ("World", "PostgreSQL", "PL/Perl") {
500 return_next({f1=>++$i, f2=>'Hello', f3=>$_});
504 SELECT * from perl_srf_rn() AS (f1 INTEGER, f2 TEXT, f3 TEXT);
506 ----+-------+------------
508 2 | Hello | PostgreSQL
513 -- Test spi_query/spi_fetchrow
515 CREATE OR REPLACE FUNCTION perl_spi_func() RETURNS SETOF INTEGER AS $$
516 my $x = spi_query("select 1 as a union select 2 as a");
517 while (defined (my $y = spi_fetchrow($x))) {
518 return_next($y->{a});
522 SELECT * from perl_spi_func();
530 -- Test spi_fetchrow abort
532 CREATE OR REPLACE FUNCTION perl_spi_func2() RETURNS INTEGER AS $$
533 my $x = spi_query("select 1 as a union select 2 as a");
534 spi_cursor_close( $x);
537 SELECT * from perl_spi_func2();
544 --- Test recursion via SPI
546 CREATE OR REPLACE FUNCTION recurse(i int) RETURNS SETOF TEXT LANGUAGE plperl
550 foreach my $x (1..$i)
552 return_next "hello $x";
557 my $cursor = spi_query("select * from recurse($z)");
558 while (defined(my $row = spi_fetchrow($cursor)))
560 return_next "recurse $i: $row->{recurse}";
566 SELECT * FROM recurse(2);
573 SELECT * FROM recurse(3);
584 --- Test array return
586 CREATE OR REPLACE FUNCTION array_of_text() RETURNS TEXT[][]
587 LANGUAGE plperl as $$
588 return [['a"b',undef,'c,d'],['e\\f',undef,'g']];
590 SELECT array_of_text();
592 ---------------------------------------
593 {{"a\"b",NULL,"c,d"},{"e\\f",NULL,g}}
597 -- Test spi_prepare/spi_exec_prepared/spi_freeplan
599 CREATE OR REPLACE FUNCTION perl_spi_prepared(INTEGER) RETURNS INTEGER AS $$
600 my $x = spi_prepare('select $1 AS a', 'INTEGER');
601 my $q = spi_exec_prepared( $x, $_[0] + 1);
603 return $q->{rows}->[0]->{a};
605 SELECT * from perl_spi_prepared(42);
612 -- Test spi_prepare/spi_query_prepared/spi_freeplan
614 CREATE OR REPLACE FUNCTION perl_spi_prepared_set(INTEGER, INTEGER) RETURNS SETOF INTEGER AS $$
615 my $x = spi_prepare('SELECT $1 AS a union select $2 as a', 'INT4', 'INT4');
616 my $q = spi_query_prepared( $x, 1+$_[0], 2+$_[1]);
617 while (defined (my $y = spi_fetchrow($q))) {
623 SELECT * from perl_spi_prepared_set(1,2);
624 perl_spi_prepared_set
625 -----------------------
631 -- Test prepare with a type with spaces
633 CREATE OR REPLACE FUNCTION perl_spi_prepared_double(double precision) RETURNS double precision AS $$
634 my $x = spi_prepare('SELECT 10.0 * $1 AS a', 'DOUBLE PRECISION');
635 my $q = spi_query_prepared($x,$_[0]);
637 while (defined (my $y = spi_fetchrow($q))) {
643 SELECT perl_spi_prepared_double(4.35) as "double precision";
650 -- Test with a bad type
652 CREATE OR REPLACE FUNCTION perl_spi_prepared_bad(double precision) RETURNS double precision AS $$
653 my $x = spi_prepare('SELECT 10.0 * $1 AS a', 'does_not_exist');
654 my $q = spi_query_prepared($x,$_[0]);
656 while (defined (my $y = spi_fetchrow($q))) {
662 SELECT perl_spi_prepared_bad(4.35) as "double precision";
663 ERROR: type "does_not_exist" does not exist at line 2.
664 CONTEXT: PL/Perl function "perl_spi_prepared_bad"
665 -- Test with a row type
666 CREATE OR REPLACE FUNCTION perl_spi_prepared() RETURNS INTEGER AS $$
667 my $x = spi_prepare('select $1::footype AS a', 'footype');
668 my $q = spi_exec_prepared( $x, '(1, 2)');
670 return $q->{rows}->[0]->{a}->{x};
672 SELECT * from perl_spi_prepared();
678 CREATE OR REPLACE FUNCTION perl_spi_prepared_row(footype) RETURNS footype AS $$
680 my $x = spi_prepare('select $1 AS a', 'footype');
681 my $q = spi_exec_prepared( $x, {}, $footype );
683 return $q->{rows}->[0]->{a};
685 SELECT * from perl_spi_prepared_row('(1, 2)');
691 -- simple test of a DO block
693 $a = 'This is a test';
696 NOTICE: This is a test
697 -- check that restricted operations are rejected in a plperl DO block
698 DO $$ system("/nonesuch"); $$ LANGUAGE plperl;
699 ERROR: 'system' trapped by operation mask at line 1.
700 CONTEXT: PL/Perl anonymous code block
701 DO $$ qx("/nonesuch"); $$ LANGUAGE plperl;
702 ERROR: 'quoted execution (``, qx)' trapped by operation mask at line 1.
703 CONTEXT: PL/Perl anonymous code block
704 DO $$ open my $fh, "</nonesuch"; $$ LANGUAGE plperl;
705 ERROR: 'open' trapped by operation mask at line 1.
706 CONTEXT: PL/Perl anonymous code block
707 -- check that eval is allowed and eval'd restricted ops are caught
708 DO $$ eval q{chdir '.';}; warn "Caught: $@"; $$ LANGUAGE plperl;
709 WARNING: Caught: 'chdir' trapped by operation mask at line 1.
710 -- check that compiling do (dofile opcode) is allowed
711 -- but that executing it for a file not already loaded (via require) dies
712 DO $$ warn do "/dev/null"; $$ LANGUAGE plperl;
713 ERROR: Unable to load /dev/null into plperl at line 1.
714 CONTEXT: PL/Perl anonymous code block
715 -- check that we can't "use" a module that's not been loaded already
716 -- compile-time error: "Unable to load blib.pm into plperl"
717 DO $$ use blib; $$ LANGUAGE plperl;
718 ERROR: Unable to load blib.pm into plperl at line 1.
719 BEGIN failed--compilation aborted at line 1.
720 CONTEXT: PL/Perl anonymous code block
721 -- check that we can "use" a module that has already been loaded
722 -- runtime error: "Can't use string ("foo") as a SCALAR ref while "strict refs" in use
723 DO $do$ use strict; my $name = "foo"; my $ref = $$name; $do$ LANGUAGE plperl;
724 ERROR: Can't use string ("foo") as a SCALAR ref while "strict refs" in use at line 1.
725 CONTEXT: PL/Perl anonymous code block
726 -- check that we can "use warnings" (in this case to turn a warn into an error)
727 -- yields "ERROR: Useless use of sort in scalar context."
728 DO $do$ use warnings FATAL => qw(void) ; my @y; my $x = sort @y; 1; $do$ LANGUAGE plperl;
729 ERROR: Useless use of sort in scalar context at line 1.
730 CONTEXT: PL/Perl anonymous code block
731 -- make sure functions marked as VOID without an explicit return work
732 CREATE OR REPLACE FUNCTION myfuncs() RETURNS void AS $$
733 $_SHARED{myquote} = sub {
735 $arg =~ s/(['\\])/\\$1/g;
745 -- make sure we can't return an array as a scalar
746 CREATE OR REPLACE FUNCTION text_arrayref() RETURNS text AS $$
749 SELECT text_arrayref();
750 ERROR: cannot convert Perl array to non-array type text
751 CONTEXT: PL/Perl function "text_arrayref"
752 --- make sure we can't return a hash as a scalar
753 CREATE OR REPLACE FUNCTION text_hashref() RETURNS text AS $$
756 SELECT text_hashref();
757 ERROR: cannot convert Perl hash to non-composite type text
758 CONTEXT: PL/Perl function "text_hashref"
759 ---- make sure we can't return a blessed object as a scalar
760 CREATE OR REPLACE FUNCTION text_obj() RETURNS text AS $$
761 return bless({}, 'Fake::Object');
764 ERROR: cannot convert Perl hash to non-composite type text
765 CONTEXT: PL/Perl function "text_obj"
766 -- test looking through a scalar ref
767 CREATE OR REPLACE FUNCTION text_scalarref() RETURNS text AS $$
771 SELECT text_scalarref();
777 -- check safe behavior when a function body is replaced during execution
778 CREATE OR REPLACE FUNCTION self_modify(INTEGER) RETURNS INTEGER AS $$
779 spi_exec_query('CREATE OR REPLACE FUNCTION self_modify(INTEGER) RETURNS INTEGER AS \'return $_[0] * 3;\' LANGUAGE plperl;');
780 spi_exec_query('select self_modify(42) AS a');
783 SELECT self_modify(42);
789 SELECT self_modify(42);