test_munge();
</programlisting>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal><function>spi_query(<replaceable>command</replaceable>)</function></literal>
<indexterm>
<primary>spi_query</primary>
<secondary>in PL/Perl</secondary>
</indexterm>
</term>
<term>
<literal><function>spi_fetchrow(<replaceable>cursor</replaceable>)</function></literal>
<indexterm>
<primary>spi_fetchrow</primary>
<secondary>in PL/Perl</secondary>
</indexterm>
</term>
<term>
<literal><function>spi_cursor_close(<replaceable>cursor</replaceable>)</function></literal>
<indexterm>
<primary>spi_cursor_close</primary>
<secondary>in PL/Perl</secondary>
</indexterm>
</term>
<listitem>
<para>
<literal>spi_query</literal> and <literal>spi_fetchrow</literal>
work together as a pair for row sets which might be large, or for cases
where you wish to return rows as they arrive.
<literal>spi_fetchrow</literal> works <emphasis>only</emphasis> with
<literal>spi_query</literal>. The following example illustrates how
you use them together:
<programlisting>
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, "cannot 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);
</programlisting>
</para>
<para>
Normally, <function>spi_fetchrow</function> should be repeated until it
returns <literal>undef</literal>, indicating that there are no more
rows to read. The cursor returned by <literal>spi_query</literal>
is automatically freed when
<function>spi_fetchrow</function> returns <literal>undef</literal>.
If you do not wish to read all the rows, instead call
<function>spi_cursor_close</function> to free the cursor.
Failure to do so will result in memory leaks.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal><function>spi_prepare(<replaceable>command</replaceable>, <replaceable>argument types</replaceable>)</function></literal>
<indexterm>
<primary>spi_prepare</primary>
<secondary>in PL/Perl</secondary>
</indexterm>
</term>
<term>
<literal><function>spi_query_prepared(<replaceable>plan</replaceable>, <replaceable>arguments</replaceable>)</function></literal>
<indexterm>
<primary>spi_query_prepared</primary>
<secondary>in PL/Perl</secondary>
</indexterm>
</term>
<term>
<literal><function>spi_exec_prepared(<replaceable>plan</replaceable> [, <replaceable>attributes</replaceable>], <replaceable>arguments</replaceable>)</function></literal>
<indexterm>
<primary>spi_exec_prepared</primary>
<secondary>in PL/Perl</secondary>
</indexterm>
</term>
<term>
<literal><function>spi_freeplan(<replaceable>plan</replaceable>)</function></literal>
<indexterm>
<primary>spi_freeplan</primary>
<secondary>in PL/Perl</secondary>
</indexterm>
</term>
<listitem>
<para>
<literal>spi_prepare</literal>, <literal>spi_query_prepared</literal>, <literal>spi_exec_prepared</literal>,
and <literal>spi_freeplan</literal> implement