<!--
$Header: /cvsroot/pgsql/doc/src/sgml/plperl.sgml,v 2.9 2001/06/22 21:37:14 momjian Exp $
-->

<chapter id="plperl">
 <title>PL/Perl - Perl Procedural Language</title>

 <indexterm zone="plperl">
  <primary>PL/Perl</primary>
 </indexterm>

 <indexterm zone="plperl">
  <primary>Perl</primary>
 </indexterm>

 <para>
  PL/Perl allows you to write functions in the Perl programming
  language that may be used in SQL queries as if they were built into
  <productname>Postgres</productname>.
 </para>

 <para>
  The PL/Perl interpreter (when installed as trusted interpreter with 
  default name 'plperl') intepreter is a full Perl interpreter. However, certain
  operations have been disabled in order to maintain the security of
  the system.  In general, the operations that are restricted are
  those that interact with the environment. This includes filehandle
  operations, <literal>require</literal>, and <literal>use</literal>
  (for external modules).  It should be noted that this security is
  not absolute. Indeed, several Denial-of-Service attacks are still
  possible - memory exhaustion and endless loops are two examples.

 </para>
 <para>
  When PL/Perl is installed as 'untrusted' interpreter (with name 'plperlu'),
  everything is permitted, and any perl code can be loaded (by superuser only).
 </para>

 <sect1 id="plperl-install">
  <title>Building and Installing</title>

  <para>
   In order to build and install PL/Perl if you are installing
   <productname>Postgres</productname> from source then the
   <option>--with-perl</option> must be supplied to the
   <indexterm><primary><filename>configure</filename></primary></indexterm>
   <filename>configure</filename> script.  PL/Perl requires that, when
   <productname>Perl</productname> was installed, the
   <indexterm><primary>libperl</primary></indexterm>
   <filename>libperl</filename> library was build as a shared object.
   At the time of this writing, this is almost never the case in the
   Perl packages that are distributed with the operating systems.  A
   message like this will appear during the build to point out this
   fact:
<screen>
<computeroutput>
*****
* Cannot build PL/Perl because libperl is not a shared library.
* Skipped.
*****
</computeroutput>
</screen>
   Therefore it is likely that you will have to re-build and install
   <productname>Perl</productname> manually to be able to build
   PL/Perl.
  </para>

  <para>
   When you want to retry to build PL/Perl after having reinstalled
   Perl, then change to the directory
   <filename>src/pl/plperl</filename> in the
   <productname>Postgres</productname> source tree and issue the commands
<programlisting>
gmake clean
gmake all
gmake install
</programlisting>
  </para>

  <para>
   The <command>createlang</command> command is used to install the
   language into a database.
<screen>
<prompt>$</prompt> <userinput>createlang plperl template1</userinput>
</screen>
   Alternatively, to create untrusted interpreter (where functions can only
be created by superuser, but the functions are not restricted), use:
<screen>
<prompt>$</prompt> <userinput>createlang plperlu template1</userinput>
</screen>
   If it is installed into template1, all future databases will have
   the language installed automatically.
  </para>
 </sect1>

 <sect1 id="plperl-use">
  <title>Using PL/Perl</title>

  <para>
   Assume you have the following table:
<programlisting>
CREATE TABLE EMPLOYEE (
    name text,
    basesalary integer,
    bonus integer
);
</programlisting>

   In order to get the total compensation (base + bonus) we could
   define a function as follows:
<programlisting>
CREATE FUNCTION totalcomp(integer, integer) RETURNS integer
    AS 'return $_[0] + $_[1]'
    LANGUAGE 'plperl';
</programlisting>

   Notice that the arguments to the function are passed in
   <varname>@_</varname> as might be expected.
  </para>

  <para>
   We can now use our function like so:
<programlisting>
SELECT name, totalcomp(basesalary, bonus) FROM employee;
</programlisting>
  </para>

  <para>
   But, we can also pass entire tuples to our functions:
<programlisting>
CREATE FUNCTION empcomp(employee) RETURNS integer AS '
    my $emp = shift;
    return $emp->{''basesalary''} + $emp->{''bonus''};
' LANGUAGE 'plperl';
</programlisting>
   A tuple is passed as a reference to a hash. The keys are the names
   of the fields in the tuples. The hash values are values of the
   corresponding fields in the tuple.
  </para>

  <tip>
   <para>
    Because the function body is passed as an SQL string literal to
    <command>CREATE FUNCTION</command> you have to escape single
    quotes within your Perl source, either by doubling them as shown
    above, or by using the extended quoting functions
    (<literal>q[]</literal>, <literal>qq[]</literal>,
    <literal>qw[]</literal>).  Backslashes must be escaped by doubling
    them.
   </para>
  </tip>

  <para>
   The new function <function>empcomp</function> can used like:
<programlisting>
SELECT name, empcomp(employee) FROM employee;
</programlisting>
  </para>

  <para>
   Here is an example of a function that will not work because file
   system operations are not allowed for security reasons:
<programlisting>
CREATE FUNCTION badfunc() RETURNS integer AS '
    open(TEMP, ">/tmp/badfile");
    print TEMP "Gotcha!\n";
    return 1;
' LANGUAGE 'plperl';
</programlisting>
   The creation of the function will succeed, but executing it will not.

   Note that if same function was created by superuser using language 
   'plperlu', execution would succeed.
  </para>
  <para>
   Access to database itself from your perl function can be done via 
   an experimental module DBD::PgSPI, available at <ulink url="http://www.formenos.org/PgSPI/">this site</ulink>. This module makes available a DBI-compliant
   database-handle named $pg_dbh, and you can use that to make queries with
   normal DBI syntax.
  </para>

 </sect1>
</chapter>

<!-- Keep this comment at the end of the file
Local variables:
mode:sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"./reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:("/usr/lib/sgml/catalog")
sgml-local-ecat-files:nil
End:
-->
