To create a function in the PL/Perl language, use the standard
- syntax:
+ syntax. A PL/Perl function must always return a scalar value. You
+ can return more complex structures (arrays, records, and sets)
+ in the appropriate context by returning a reference.
+ Never return a list. Here follows an example of a PL/Perl
+ function.
+
CREATE FUNCTION funcname (argument-types) RETURNS return-type AS $$
# PL/Perl function body
- PL/Perl provides two additional Perl commands:
+ PL/Perl provides three additional Perl commands:
spi_exec_query>(query [, max-rows])
spi_exec_query>(command)
+ spi_query>(command)
+ spi_fetchrow>(command)
+
- Executes an SQL command. Here is an example of a query
- (SELECT command) with the optional maximum
- number of rows:
+ spi_exec_query executes an SQL command and
+returns the entire rowset as a reference to an array of hash
+references. You should only use this command when you know
+that the result set will be relatively small. Here is an
+example of a query (SELECT command) with the
+optional maximum number of rows:
+
$rv = spi_exec_query('SELECT * FROM my_table', 5);
INSERT INTO test (i, v) VALUES (3, 'third line');
INSERT INTO test (i, v) VALUES (4, 'immortal');
-CREATE FUNCTION test_munge() RETURNS SETOF test AS $$
+CREATE OR REPLACE FUNCTION test_munge() RETURNS SETOF test AS $$
my $rv = spi_exec_query('select i, v from test;');
my $status = $rv->{status};
my $nrows = $rv->{processed};
SELECT * FROM test_munge();
-
+
+ spi_query and spi_fetchrow
+ work together as a pair for rowsets which may be large, or for cases
+ where you wish to return rows as they arrive.
+ spi_fetchrow works only with
+ spi_query. The following example illustrates how
+ you use them together:
+
+CREATE TYPE foo_type AS (the_num INTEGER, the_text TEXT);
+
+CREATE OR REPLACE FUNCTION lotsa_md5 (INTEGER) RETURNS SETOF foo_type AS $$
+ use Digest::MD5 qw(md5_hex);
+ my $file = '/usr/share/dict/words';
+ my $t = localtime;
+ elog(NOTICE, "opening file $file at $t" );
+ open my $fh, '<', $file # ooh, it's a file access!
+ or elog(ERROR, "Can't open $file for reading: $!");
+ my @words = <$fh>;
+ close $fh;
+ $t = localtime;
+ elog(NOTICE, "closed file $file at $t");
+ chomp(@words);
+ my $row;
+ my $sth = spi_query("SELECT * FROM generate_series(1,$_[0]) AS b(a)");
+ while (defined ($row = spi_fetchrow($sth))) {
+ return_next({
+ the_num => $row->{a},
+ the_text => md5_hex($words[rand @words])
+ });
+ }
+ return;
+$$ LANGUAGE plperlu;
+
+SELECT * from lotsa_md5(500);
+
+
+
- In the current implementation, if you are fetching or returning
- very large data sets, you should be aware that these will all go
- into memory.
+ If you are fetching very large data sets using
+ spi_exec_query, you should be aware that
+ these will all go into memory. You can avoid this by using
+ spi_query/spi_fetchrow as
+ illustrated earlier.
+
+ A similar problem occurs if a set-returning function passes a
+ large set of rows back to postgres via return. You
+ can avoid this problem too by instead using
+ return_next for each row returned, as shown
+ previously.
+