]> granicus.if.org Git - postgresql/blobdiff - doc/src/sgml/plpython.sgml
Trim trailing whitespace
[postgresql] / doc / src / sgml / plpython.sgml
index 9fc8808776c427b7c7e12f1e6d0946897e89657c..777a7ef780f9aa986606e9497403b6f9d43168ca 100644 (file)
@@ -14,7 +14,7 @@
 
  <para>
   To install PL/Python in a particular database, use
-  <literal>createlang plpythonu <replaceable>dbname</></literal> (but
+  <literal>CREATE EXTENSION plpythonu</> (but
   see also <xref linkend="plpython-python23">).
  </para>
 
   </tip>
 
  <para>
-  As of <productname>PostgreSQL</productname> 7.4, PL/Python is only
-  available as an <quote>untrusted</> language, meaning it does not
-  offer any way of restricting what users can do in it.  It has
-  therefore been renamed to <literal>plpythonu</>.  The trusted
-  variant <literal>plpython</> might become available again in future,
-  if a new secure execution mechanism is developed in Python.  The
+  PL/Python is only available as an <quote>untrusted</> language, meaning
+  it does not offer any way of restricting what users can do in it and
+  is therefore named <literal>plpythonu</>.  A trusted
+  variant <literal>plpython</> might become available in the future
+  if a secure execution mechanism is developed in Python.  The
   writer of a function in untrusted PL/Python must take care that the
   function cannot be used to do anything unwanted, since it will be
   able to do anything that could be done by a user logged in as the
     </listitem>
    </itemizedlist>
 
+   This scheme is analogous to the recommendations in <ulink
+   url="http://www.python.org/dev/peps/pep-0394/">PEP 394</ulink> regarding the
+   naming and transitioning of the <command>python</command> command.
+  </para>
+
+  <para>
    It depends on the build configuration or the installed packages
    whether PL/Python for Python 2 or Python 3 or both are available.
   </para>
     <listitem>
      <para>
       Daredevils, who want to build a Python-3-only operating system
-      environment, can change the build scripts to
-      make <literal>plpythonu</literal> be equivalent
+      environment, can change the contents of
+      <link linkend="catalog-pg-pltemplate"><structname>pg_pltemplate</structname></link>
+      to make <literal>plpythonu</literal> be equivalent
       to <literal>plpython3u</literal>, keeping in mind that this
       would make their installation incompatible with most of the rest
       of the world.
@@ -281,8 +287,9 @@ $$ LANGUAGE plpythonu;
   <sect2>
    <title>Data Type Mapping</title>
    <para>
-    Function arguments are converted from their PostgreSQL type to a
-    corresponding Python type:
+    When a PL/Python function is called, its arguments are converted from
+    their PostgreSQL data type to a corresponding Python type:
+
     <itemizedlist>
      <listitem>
       <para>
@@ -294,7 +301,7 @@ $$ LANGUAGE plpythonu;
       <para>
        PostgreSQL <type>smallint</type> and <type>int</type> are
        converted to Python <type>int</type>.
-       PostgreSQL <type>bigint</type> is converted
+       PostgreSQL <type>bigint</type> and <type>oid</type> are converted
        to <type>long</type> in Python 2 and to <type>int</type> in
        Python 3.
       </para>
@@ -302,12 +309,23 @@ $$ LANGUAGE plpythonu;
 
      <listitem>
       <para>
-       PostgreSQL <type>real</type>, <type>double</type>,
-       and <type>numeric</type> are converted to
-       Python <type>float</type>.  Note that for
-       the <type>numeric</type> this loses information and can lead to
-       incorrect results.  This might be fixed in a future
-       release.
+       PostgreSQL <type>real</type> and <type>double</type> are converted to
+       Python <type>float</type>.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       PostgreSQL <type>numeric</type> is converted to
+       Python <type>Decimal</type>.  This type is imported from
+       the <literal>cdecimal</literal> package if that is available.
+       Otherwise,
+       <literal>decimal.Decimal</literal> from the standard library will be
+       used.  <literal>cdecimal</literal> is significantly faster
+       than <literal>decimal</literal>.  In Python 3.3 and up,
+       however, <literal>cdecimal</literal> has been integrated into the
+       standard library under the name <literal>decimal</literal>, so there is
+       no longer any difference.
       </para>
      </listitem>
 
@@ -338,8 +356,9 @@ $$ LANGUAGE plpythonu;
    </para>
 
    <para>
-    Function return values are converted to the declared PostgreSQL
-    return data type as follows:
+    When a PL/Python function returns, its return value is converted to the
+    function's declared PostgreSQL return data type as follows:
+
     <itemizedlist>
      <listitem>
       <para>
@@ -354,17 +373,19 @@ $$ LANGUAGE plpythonu;
       <para>
        When the PostgreSQL return type is <type>bytea</type>, the
        return value will be converted to a string (Python 2) or bytes
-       (Python 3) using the respective Python builtins, with the
-       result being converted <type>bytea</type>.
+       (Python 3) using the respective Python built-ins, with the
+       result being converted to <type>bytea</type>.
       </para>
      </listitem>
 
      <listitem>
       <para>
-       For all other PostgreSQL return types, the returned Python
-       value is converted to a string using the Python
-       builtin <literal>str</literal>, and the result is passed to the
-       input function of the PostgreSQL data type.
+       For all other PostgreSQL return types, the return value is converted
+       to a string using the Python built-in <literal>str</literal>, and the
+       result is passed to the input function of the PostgreSQL data type.
+       (If the Python value is a <type>float</>, it is converted using
+       the <literal>repr</> built-in instead of <literal>str</literal>, to
+       avoid loss of precision.)
       </para>
 
       <para>
@@ -390,27 +411,16 @@ $$ LANGUAGE plpythonu;
     return type and the Python data type of the actual return object
     are not flagged; the value will be converted in any case.
    </para>
-
-   <tip>
-    <para>
-     <application>PL/Python</application> functions cannot return
-     either type <type>RECORD</type> or <type>SETOF RECORD</type>.  A
-     workaround is to write a <application>PL/pgSQL</application>
-     function that creates a temporary table, have it call the
-     <application>PL/Python</application> function to fill the table,
-     and then have the <application>PL/pgSQL</application> function
-     return the generic <type>RECORD</type> from the temporary table.
-    </para>
-   </tip>
   </sect2>
 
   <sect2>
    <title>Null, None</title>
   <para>
    If an SQL null value<indexterm><primary>null value</primary><secondary
-   sortas="PL/Python">PL/Python</secondary></indexterm> is passed to a
+   sortas="PL/Python">in PL/Python</secondary></indexterm> is passed to a
    function, the argument value will appear as <symbol>None</symbol> in
-   Python. The above function definition will return the wrong answer for null
+   Python. For example, the function definition of <function>pymax</function>
+   shown in <xref linkend="plpython-funcs"> will return the wrong answer for null
    inputs. We could add <literal>STRICT</literal> to the function definition
    to make <productname>PostgreSQL</productname> do something more reasonable:
    if a null value is passed, the function will not be called at all,
@@ -440,13 +450,13 @@ $$ LANGUAGE plpythonu;
   <para>
    SQL array values are passed into PL/Python as a Python list.  To
    return an SQL array value out of a PL/Python function, return a
-   Python sequence, for example a list or tuple:
+   Python list:
 
 <programlisting>
 CREATE FUNCTION return_arr()
   RETURNS int[]
 AS $$
-return (1, 2, 3, 4, 5)
+return [1, 2, 3, 4, 5]
 $$ LANGUAGE plpythonu;
 
 SELECT return_arr();
@@ -456,6 +466,34 @@ SELECT return_arr();
 (1 row)
 </programlisting>
 
+   Multidimensional arrays are passed into PL/Python as nested Python lists.
+   A 2-dimensional array is a list of lists, for example. When returning
+   a multi-dimensional SQL array out of a PL/Python function, the inner
+   lists at each level must all be of the same size. For example:
+
+<programlisting>
+CREATE FUNCTION test_type_conversion_array_int4(x int4[]) RETURNS int4[] AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM test_type_conversion_array_int4(ARRAY[[1,2,3],[4,5,6]]);
+INFO:  ([[1, 2, 3], [4, 5, 6]], &lt;type 'list'&gt;)
+ test_type_conversion_array_int4 
+---------------------------------
+ {{1,2,3},{4,5,6}}
+(1 row)
+</programlisting>
+
+   Other Python sequences, like tuples, are also accepted for
+   backwards-compatibility with PostgreSQL versions 9.6 and below, when
+   multi-dimensional arrays were not supported. However, they are always
+   treated as one-dimensional arrays, because they are ambiguous with
+   composite types. For the same reason, when a composite type is used in a
+   multi-dimensional array, it must be represented by a tuple, rather than a
+   list.
+  </para>
+  <para>
    Note that in Python, strings are sequences, which can have
    undesirable effects that might be familiar to Python programmers:
 
@@ -530,14 +568,19 @@ CREATE TYPE named_value AS (
 CREATE FUNCTION make_pair (name text, value integer)
   RETURNS named_value
 AS $$
-  return [ name, value ]
-  # or alternatively, as tuple: return ( name, value )
+  return ( name, value )
+  # or alternatively, as tuple: return [ name, value ]
 $$ LANGUAGE plpythonu;
 </programlisting>
 
        To return a SQL null for any column, insert <symbol>None</symbol> at
        the corresponding position.
       </para>
+      <para>
+       When an array of composite types is returned, it cannot be returned as a list,
+       because it is ambiguous whether the Python list represents a composite type,
+       or another array dimension.
+      </para>
      </listitem>
     </varlistentry>
 
@@ -593,10 +636,21 @@ $$ LANGUAGE plpythonu;
     </varlistentry>
    </variablelist>
   </para>
+
+   <para>
+    Functions with <literal>OUT</literal> parameters are also supported.  For example:
+<programlisting>
+CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$
+return (1, 2)
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM multiout_simple();
+</programlisting>
+   </para>
   </sect2>
 
   <sect2>
-   <title>Set-Returning Functions</title>
+   <title>Set-returning Functions</title>
   <para>
    A <application>PL/Python</application> function can also return sets of
    scalar or composite types. There are several ways to achieve this because
@@ -674,24 +728,24 @@ AS $$
 $$ LANGUAGE plpythonu;
 </programlisting>
 
-       <warning>
-        <para>
-         Due to Python
-         <ulink url="http://bugs.python.org/issue1483133">bug #1483133</ulink>,
-         some debug versions of Python 2.4
-         (configured and compiled with option <literal>--with-pydebug</literal>)
-         are known to crash the <productname>PostgreSQL</productname> server
-         when using an iterator to return a set result.
-         Unpatched versions of Fedora 4 contain this bug.
-         It does not happen in production versions of Python or on patched
-         versions of Fedora 4.
-        </para>
-       </warning>
       </para>
      </listitem>
     </varlistentry>
    </variablelist>
   </para>
+
+   <para>
+    Set-returning functions with <literal>OUT</literal> parameters
+    (using <literal>RETURNS SETOF record</literal>) are also
+    supported.  For example:
+<programlisting>
+CREATE FUNCTION multiout_simple_setof(n integer, OUT integer, OUT integer) RETURNS SETOF record AS $$
+return [(1, 2)] * n
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM multiout_simple_setof(3);
+</programlisting>
+   </para>
   </sect2>
  </sect1>
 
@@ -702,8 +756,8 @@ $$ LANGUAGE plpythonu;
    data between function calls.  This variable is private static data.
    The global dictionary <varname>GD</varname> is public data,
    available to all Python functions within a session.  Use with
-   care.<indexterm><primary>global data</><secondary>in
-   PL/Python</></indexterm>
+   care.<indexterm><primary>global data</>
+   <secondary>in PL/Python</></indexterm>
   </para>
 
   <para>
@@ -858,77 +912,163 @@ $$ LANGUAGE plpythonu;
    <literal>plpy.<replaceable>foo</replaceable></literal>.
   </para>
 
+  <sect2>
+    <title>Database Access Functions</title>
+
   <para>
-   The <literal>plpy</literal> module provides two
-   functions called <function>execute</function> and
-   <function>prepare</function>.  Calling
-   <function>plpy.execute</function> with a query string and an
-   optional limit argument causes that query to be run and the result
-   to be returned in a result object.  The result object emulates a
-   list or dictionary object.  The result object can be accessed by
-   row number and column name.  It has these additional methods:
-   <function>nrows</function> which returns the number of rows
-   returned by the query, and <function>status</function> which is the
-   <function>SPI_execute()</function> return value.  The result object
-   can be modified.
+   The <literal>plpy</literal> module provides several functions to execute
+   database commands:
   </para>
 
-  <para>
-   For example:
+  <variablelist>
+   <varlistentry>
+    <term><literal>plpy.<function>execute</function>(<replaceable>query</replaceable> [, <replaceable>max-rows</replaceable>])</literal></term>
+    <listitem>
+     <para>
+      Calling <function>plpy.execute</function> with a query string and an
+      optional row limit argument causes that query to be run and the result to
+      be returned in a result object.
+     </para>
+
+     <para>
+      The result object emulates a list or dictionary object.  The result
+      object can be accessed by row number and column name.  For example:
 <programlisting>
 rv = plpy.execute("SELECT * FROM my_table", 5)
 </programlisting>
-   returns up to 5 rows from <literal>my_table</literal>.  If
-   <literal>my_table</literal> has a column
-   <literal>my_column</literal>, it would be accessed as:
+      returns up to 5 rows from <literal>my_table</literal>.  If
+      <literal>my_table</literal> has a column
+      <literal>my_column</literal>, it would be accessed as:
 <programlisting>
 foo = rv[i]["my_column"]
 </programlisting>
-  </para>
+      The number of rows returned can be obtained using the built-in
+      <function>len</function> function.
+     </para>
 
-  <para>
-   <indexterm><primary>preparing a query</><secondary>in PL/Python</></indexterm>
-   The second function, <function>plpy.prepare</function>, prepares
-   the execution plan for a query.  It is called with a query string
-   and a list of parameter types, if you have parameter references in
-   the query.  For example:
+     <para>
+      The result object has these additional methods:
+      <variablelist>
+       <varlistentry>
+        <term><literal><function>nrows</function>()</literal></term>
+        <listitem>
+         <para>
+          Returns the number of rows processed by the command.  Note that this
+          is not necessarily the same as the number of rows returned.  For
+          example, an <command>UPDATE</command> command will set this value but
+          won't return any rows (unless <literal>RETURNING</literal> is used).
+         </para>
+        </listitem>
+       </varlistentry>
+
+       <varlistentry>
+        <term><literal><function>status</function>()</literal></term>
+        <listitem>
+         <para>
+          The <function>SPI_execute()</function> return value.
+         </para>
+        </listitem>
+       </varlistentry>
+
+       <varlistentry>
+        <term><literal><function>colnames</function>()</literal></term>
+        <term><literal><function>coltypes</function>()</literal></term>
+        <term><literal><function>coltypmods</function>()</literal></term>
+        <listitem>
+         <para>
+          Return a list of column names, list of column type OIDs, and list of
+          type-specific type modifiers for the columns, respectively.
+         </para>
+
+         <para>
+          These methods raise an exception when called on a result object from
+          a command that did not produce a result set, e.g.,
+          <command>UPDATE</command> without <literal>RETURNING</literal>, or
+          <command>DROP TABLE</command>.  But it is OK to use these methods on
+          a result set containing zero rows.
+         </para>
+        </listitem>
+       </varlistentry>
+
+       <varlistentry>
+        <term><literal><function>__str__</function>()</literal></term>
+        <listitem>
+         <para>
+          The standard <literal>__str__</literal> method is defined so that it
+          is possible for example to debug query execution results
+          using <literal>plpy.debug(rv)</literal>.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+
+     <para>
+      The result object can be modified.
+     </para>
+
+     <para>
+      Note that calling <literal>plpy.execute</literal> will cause the entire
+      result set to be read into memory.  Only use that function when you are
+      sure that the result set will be relatively small.  If you don't want to
+      risk excessive memory usage when fetching large results,
+      use <literal>plpy.cursor</literal> rather
+      than <literal>plpy.execute</literal>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>plpy.<function>prepare</function>(<replaceable>query</replaceable> [, <replaceable>argtypes</replaceable>])</literal></term>
+    <term><literal>plpy.<function>execute</function>(<replaceable>plan</replaceable> [, <replaceable>arguments</replaceable> [, <replaceable>max-rows</replaceable>]])</literal></term>
+    <listitem>
+     <para>
+      <indexterm><primary>preparing a query</><secondary>in PL/Python</></indexterm>
+      <function>plpy.prepare</function> prepares the execution plan for a
+      query.  It is called with a query string and a list of parameter types,
+      if you have parameter references in the query.  For example:
 <programlisting>
-plan = plpy.prepare("SELECT last_name FROM my_users WHERE first_name = $1", [ "text" ])
+plan = plpy.prepare("SELECT last_name FROM my_users WHERE first_name = $1", ["text"])
 </programlisting>
-   <literal>text</literal> is the type of the variable you will be
-   passing for <literal>$1</literal>.  After preparing a statement, you
-   use the function <function>plpy.execute</function> to run it:
+      <literal>text</literal> is the type of the variable you will be passing
+      for <literal>$1</literal>.  The second argument is optional if you don't
+      want to pass any parameters to the query.
+     </para>
+     <para>
+      After preparing a statement, you use a variant of the
+      function <function>plpy.execute</function> to run it:
 <programlisting>
-rv = plpy.execute(plan, [ "name" ], 5)
+rv = plpy.execute(plan, ["name"], 5)
 </programlisting>
-   The third argument is the limit and is optional.
-  </para>
+      Pass the plan as the first argument (instead of the query string), and a
+      list of values to substitute into the query as the second argument.  The
+      second argument is optional if the query does not expect any parameters.
+      The third argument is the optional row limit as before.
+     </para>
 
-  <para>
-   Query parameters and result row fields are converted between
-   PostgreSQL and Python data types as described
-   in <xref linkend="plpython-data">.  The exception is that composite
-   types are currently not supported: They will be rejected as query
-   parameters and are converted to strings when appearing in a query
-   result.  As a workaround for the latter problem, the query can
-   sometimes be rewritten so that the composite type result appears as
-   a result row rather than as a field of the result row.
-   Alternatively, the resulting string could be parsed apart by hand,
-   but this approach is not recommended because it is not
-   future-proof.
-  </para>
+     <para>
+      Alternatively, you can call the <function>execute</function> method on
+      the plan object:
+<programlisting>
+rv = plan.execute(["name"], 5)
+</programlisting>
+     </para>
 
-  <para>
-   When you prepare a plan using the PL/Python module it is
-   automatically saved.  Read the SPI documentation (<xref
-   linkend="spi">) for a description of what this means.
-   In order to make effective use of this across function calls
-   one needs to use one of the persistent storage dictionaries
-   <literal>SD</literal> or <literal>GD</literal> (see
-   <xref linkend="plpython-sharing">). For example:
+     <para>
+      Query parameters and result row fields are converted between PostgreSQL
+      and Python data types as described in <xref linkend="plpython-data">.
+     </para>
+
+     <para>
+      When you prepare a plan using the PL/Python module it is automatically
+      saved.  Read the SPI documentation (<xref linkend="spi">) for a
+      description of what this means.  In order to make effective use of this
+      across function calls one needs to use one of the persistent storage
+      dictionaries <literal>SD</literal> or <literal>GD</literal> (see
+      <xref linkend="plpython-sharing">). For example:
 <programlisting>
 CREATE FUNCTION usesavedplan() RETURNS trigger AS $$
-    if SD.has_key("plan"):
+    if "plan" in SD:
         plan = SD["plan"]
     else:
         plan = plpy.prepare("SELECT 1")
@@ -936,37 +1076,382 @@ CREATE FUNCTION usesavedplan() RETURNS trigger AS $$
     # rest of function
 $$ LANGUAGE plpythonu;
 </programlisting>
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>plpy.<function>cursor</function>(<replaceable>query</replaceable>)</literal></term>
+    <term><literal>plpy.<function>cursor</function>(<replaceable>plan</replaceable> [, <replaceable>arguments</replaceable>])</literal></term>
+    <listitem>
+     <para>
+      The <literal>plpy.cursor</literal> function accepts the same arguments
+      as <literal>plpy.execute</literal> (except for the row limit) and returns
+      a cursor object, which allows you to process large result sets in smaller
+      chunks.  As with <literal>plpy.execute</literal>, either a query string
+      or a plan object along with a list of arguments can be used, or
+      the <function>cursor</function> function can be called as a method of
+      the plan object.
+     </para>
+
+     <para>
+      The cursor object provides a <literal>fetch</literal> method that accepts
+      an integer parameter and returns a result object.  Each time you
+      call <literal>fetch</literal>, the returned object will contain the next
+      batch of rows, never larger than the parameter value.  Once all rows are
+      exhausted, <literal>fetch</literal> starts returning an empty result
+      object.  Cursor objects also provide an
+      <ulink url="http://docs.python.org/library/stdtypes.html#iterator-types">iterator
+      interface</ulink>, yielding one row at a time until all rows are
+      exhausted.  Data fetched that way is not returned as result objects, but
+      rather as dictionaries, each dictionary corresponding to a single result
+      row.
+     </para>
+
+     <para>
+      An example of two ways of processing data from a large table is:
+<programlisting>
+CREATE FUNCTION count_odd_iterator() RETURNS integer AS $$
+odd = 0
+for row in plpy.cursor("select num from largetable"):
+    if row['num'] % 2:
+         odd += 1
+return odd
+$$ LANGUAGE plpythonu;
+
+CREATE FUNCTION count_odd_fetch(batch_size integer) RETURNS integer AS $$
+odd = 0
+cursor = plpy.cursor("select num from largetable")
+while True:
+    rows = cursor.fetch(batch_size)
+    if not rows:
+        break
+    for row in rows:
+        if row['num'] % 2:
+            odd += 1
+return odd
+$$ LANGUAGE plpythonu;
+
+CREATE FUNCTION count_odd_prepared() RETURNS integer AS $$
+odd = 0
+plan = plpy.prepare("select num from largetable where num % $1 &lt;&gt; 0", ["integer"])
+rows = list(plpy.cursor(plan, [2]))  # or: = list(plan.cursor([2]))
+
+return len(rows)
+$$ LANGUAGE plpythonu;
+</programlisting>
+     </para>
+
+     <para>
+      Cursors are automatically disposed of.  But if you want to explicitly
+      release all resources held by a cursor, use the <literal>close</literal>
+      method.  Once closed, a cursor cannot be fetched from anymore.
+     </para>
+
+     <tip>
+      <para>
+        Do not confuse objects created by <literal>plpy.cursor</literal> with
+        DB-API cursors as defined by
+        the <ulink url="http://www.python.org/dev/peps/pep-0249/">Python
+        Database API specification</ulink>.  They don't have anything in common
+        except for the name.
+      </para>
+     </tip>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+
+  </sect2>
+
+  <sect2 id="plpython-trapping">
+   <title>Trapping Errors</title>
+
+   <para>
+    Functions accessing the database might encounter errors, which
+    will cause them to abort and raise an exception.  Both
+    <function>plpy.execute</function> and
+    <function>plpy.prepare</function> can raise an instance of a subclass of
+    <literal>plpy.SPIError</literal>, which by default will terminate
+    the function.  This error can be handled just like any other
+    Python exception, by using the <literal>try/except</literal>
+    construct.  For example:
+<programlisting>
+CREATE FUNCTION try_adding_joe() RETURNS text AS $$
+    try:
+        plpy.execute("INSERT INTO users(username) VALUES ('joe')")
+    except plpy.SPIError:
+        return "something went wrong"
+    else:
+        return "Joe added"
+$$ LANGUAGE plpythonu;
+</programlisting>
+   </para>
+
+   <para>
+    The actual class of the exception being raised corresponds to the
+    specific condition that caused the error.  Refer
+    to <xref linkend="errcodes-table"> for a list of possible
+    conditions.  The module
+    <literal>plpy.spiexceptions</literal> defines an exception class
+    for each <productname>PostgreSQL</productname> condition, deriving
+    their names from the condition name.  For
+    instance, <literal>division_by_zero</literal>
+    becomes <literal>DivisionByZero</literal>, <literal>unique_violation</literal>
+    becomes <literal>UniqueViolation</literal>, <literal>fdw_error</literal>
+    becomes <literal>FdwError</literal>, and so on.  Each of these
+    exception classes inherits from <literal>SPIError</literal>.  This
+    separation makes it easier to handle specific errors, for
+    instance:
+<programlisting>
+CREATE FUNCTION insert_fraction(numerator int, denominator int) RETURNS text AS $$
+from plpy import spiexceptions
+try:
+    plan = plpy.prepare("INSERT INTO fractions (frac) VALUES ($1 / $2)", ["int", "int"])
+    plpy.execute(plan, [numerator, denominator])
+except spiexceptions.DivisionByZero:
+    return "denominator cannot equal zero"
+except spiexceptions.UniqueViolation:
+    return "already have that fraction"
+except plpy.SPIError, e:
+    return "other error, SQLSTATE %s" % e.sqlstate
+else:
+    return "fraction inserted"
+$$ LANGUAGE plpythonu;
+</programlisting>
+    Note that because all exceptions from
+    the <literal>plpy.spiexceptions</literal> module inherit
+    from <literal>SPIError</literal>, an <literal>except</literal>
+    clause handling it will catch any database access error.
+   </para>
+
+   <para>
+    As an alternative way of handling different error conditions, you
+    can catch the <literal>SPIError</literal> exception and determine
+    the specific error condition inside the <literal>except</literal>
+    block by looking at the <literal>sqlstate</literal> attribute of
+    the exception object.  This attribute is a string value containing
+    the <quote>SQLSTATE</quote> error code.  This approach provides
+    approximately the same functionality
+   </para>
+  </sect2>
+ </sect1>
+
+ <sect1 id="plpython-subtransaction">
+  <title>Explicit Subtransactions</title>
+
+  <para>
+   Recovering from errors caused by database access as described in
+   <xref linkend="plpython-trapping"> can lead to an undesirable
+   situation where some operations succeed before one of them fails,
+   and after recovering from that error the data is left in an
+   inconsistent state.  PL/Python offers a solution to this problem in
+   the form of explicit subtransactions.
   </para>
+
+  <sect2>
+   <title>Subtransaction Context Managers</title>
+
+   <para>
+    Consider a function that implements a transfer between two
+    accounts:
+<programlisting>
+CREATE FUNCTION transfer_funds() RETURNS void AS $$
+try:
+    plpy.execute("UPDATE accounts SET balance = balance - 100 WHERE account_name = 'joe'")
+    plpy.execute("UPDATE accounts SET balance = balance + 100 WHERE account_name = 'mary'")
+except plpy.SPIError, e:
+    result = "error transferring funds: %s" % e.args
+else:
+    result = "funds transferred correctly"
+plan = plpy.prepare("INSERT INTO operations (result) VALUES ($1)", ["text"])
+plpy.execute(plan, [result])
+$$ LANGUAGE plpythonu;
+</programlisting>
+    If the second <literal>UPDATE</literal> statement results in an
+    exception being raised, this function will report the error, but
+    the result of the first <literal>UPDATE</literal> will
+    nevertheless be committed.  In other words, the funds will be
+    withdrawn from Joe's account, but will not be transferred to
+    Mary's account.
+   </para>
+
+   <para>
+    To avoid such issues, you can wrap your
+    <literal>plpy.execute</literal> calls in an explicit
+    subtransaction.  The <literal>plpy</literal> module provides a
+    helper object to manage explicit subtransactions that gets created
+    with the <literal>plpy.subtransaction()</literal> function.
+    Objects created by this function implement the
+    <ulink url="http://docs.python.org/library/stdtypes.html#context-manager-types">
+    context manager interface</ulink>.  Using explicit subtransactions
+    we can rewrite our function as:
+<programlisting>
+CREATE FUNCTION transfer_funds2() RETURNS void AS $$
+try:
+    with plpy.subtransaction():
+        plpy.execute("UPDATE accounts SET balance = balance - 100 WHERE account_name = 'joe'")
+        plpy.execute("UPDATE accounts SET balance = balance + 100 WHERE account_name = 'mary'")
+except plpy.SPIError, e:
+    result = "error transferring funds: %s" % e.args
+else:
+    result = "funds transferred correctly"
+plan = plpy.prepare("INSERT INTO operations (result) VALUES ($1)", ["text"])
+plpy.execute(plan, [result])
+$$ LANGUAGE plpythonu;
+</programlisting>
+    Note that the use of <literal>try/catch</literal> is still
+    required.  Otherwise the exception would propagate to the top of
+    the Python stack and would cause the whole function to abort with
+    a <productname>PostgreSQL</productname> error, so that the
+    <literal>operations</literal> table would not have any row
+    inserted into it.  The subtransaction context manager does not
+    trap errors, it only assures that all database operations executed
+    inside its scope will be atomically committed or rolled back.  A
+    rollback of the subtransaction block occurs on any kind of
+    exception exit, not only ones caused by errors originating from
+    database access.  A regular Python exception raised inside an
+    explicit subtransaction block would also cause the subtransaction
+    to be rolled back.
+   </para>
+  </sect2>
+
+  <sect2>
+   <title>Older Python Versions</title>
+
+   <para>
+    Context managers syntax using the <literal>with</literal> keyword
+    is available by default in Python 2.6.  If using PL/Python with an
+    older Python version, it is still possible to use explicit
+    subtransactions, although not as transparently.  You can call the
+    subtransaction manager's <literal>__enter__</literal> and
+    <literal>__exit__</literal> functions using the
+    <literal>enter</literal> and <literal>exit</literal> convenience
+    aliases.  The example function that transfers funds could be
+    written as:
+<programlisting>
+CREATE FUNCTION transfer_funds_old() RETURNS void AS $$
+try:
+    subxact = plpy.subtransaction()
+    subxact.enter()
+    try:
+        plpy.execute("UPDATE accounts SET balance = balance - 100 WHERE account_name = 'joe'")
+        plpy.execute("UPDATE accounts SET balance = balance + 100 WHERE account_name = 'mary'")
+    except:
+        import sys
+        subxact.exit(*sys.exc_info())
+        raise
+    else:
+        subxact.exit(None, None, None)
+except plpy.SPIError, e:
+    result = "error transferring funds: %s" % e.args
+else:
+    result = "funds transferred correctly"
+
+plan = plpy.prepare("INSERT INTO operations (result) VALUES ($1)", ["text"])
+plpy.execute(plan, [result])
+$$ LANGUAGE plpythonu;
+</programlisting>
+   </para>
+
+   <note>
+    <para>
+     Although context managers were implemented in Python 2.5, to use
+     the <literal>with</literal> syntax in that version you need to
+     use a <ulink
+     url="http://docs.python.org/release/2.5/ref/future.html">future
+     statement</ulink>.  Because of implementation details, however,
+     you cannot use future statements in PL/Python functions.
+    </para>
+   </note>
+  </sect2>
  </sect1>
 
  <sect1 id="plpython-util">
   <title>Utility Functions</title>
   <para>
    The <literal>plpy</literal> module also provides the functions
-   <literal>plpy.debug(<replaceable>msg</>)</literal>,
-   <literal>plpy.log(<replaceable>msg</>)</literal>,
-   <literal>plpy.info(<replaceable>msg</>)</literal>,
-   <literal>plpy.notice(<replaceable>msg</>)</literal>,
-   <literal>plpy.warning(<replaceable>msg</>)</literal>,
-   <literal>plpy.error(<replaceable>msg</>)</literal>, and
-   <literal>plpy.fatal(<replaceable>msg</>)</literal>.<indexterm><primary>elog</><secondary>in PL/Python</></indexterm>
-   <function>plpy.error</function> and
-   <function>plpy.fatal</function> actually raise a Python exception
-   which, if uncaught, propagates out to the calling query, causing
-   the current transaction or subtransaction to be aborted.
-   <literal>raise plpy.Error(<replaceable>msg</>)</literal> and
+   <simplelist>
+    <member><literal>plpy.debug(<replaceable>msg, **kwargs</>)</literal></member>
+    <member><literal>plpy.log(<replaceable>msg, **kwargs</>)</literal></member>
+    <member><literal>plpy.info(<replaceable>msg, **kwargs</>)</literal></member>
+    <member><literal>plpy.notice(<replaceable>msg, **kwargs</>)</literal></member>
+    <member><literal>plpy.warning(<replaceable>msg, **kwargs</>)</literal></member>
+    <member><literal>plpy.error(<replaceable>msg, **kwargs</>)</literal></member>
+    <member><literal>plpy.fatal(<replaceable>msg, **kwargs</>)</literal></member>
+   </simplelist>
+   <indexterm><primary>elog</><secondary>in PL/Python</></indexterm>
+   <function>plpy.error</function> and <function>plpy.fatal</function>
+   actually raise a Python exception which, if uncaught, propagates out to
+   the calling query, causing the current transaction or subtransaction to
+   be aborted.  <literal>raise plpy.Error(<replaceable>msg</>)</literal> and
    <literal>raise plpy.Fatal(<replaceable>msg</>)</literal> are
-   equivalent to calling
-   <function>plpy.error</function> and
-   <function>plpy.fatal</function>, respectively.
-   The other functions only generate messages of different
-   priority levels.
+   equivalent to calling <literal>plpy.error(<replaceable>msg</>)</literal> and
+   <literal>plpy.fatal(<replaceable>msg</>)</literal>, respectively but
+   the <literal>raise</literal> form does not allow passing keyword arguments.
+   The other functions only generate messages of different priority levels.
    Whether messages of a particular priority are reported to the client,
    written to the server log, or both is controlled by the
    <xref linkend="guc-log-min-messages"> and
    <xref linkend="guc-client-min-messages"> configuration
    variables. See <xref linkend="runtime-config"> for more information.
   </para>
+
+  <para>
+   The <replaceable>msg</> argument is given as a positional argument.  For
+   backward compatibility, more than one positional argument can be given. In
+   that case, the string representation of the tuple of positional arguments
+   becomes the message reported to the client.
+  </para>
+
+  <para>
+   The following keyword-only arguments are accepted:
+   <simplelist>
+    <member><literal>detail</literal></member>
+    <member><literal>hint</literal></member>
+    <member><literal>sqlstate</literal></member>
+    <member><literal>schema_name</literal></member>
+    <member><literal>table_name</literal></member>
+    <member><literal>column_name</literal></member>
+    <member><literal>datatype_name</literal></member>
+    <member><literal>constraint_name</literal></member>
+   </simplelist>
+   The string representation of the objects passed as keyword-only arguments
+   is used to enrich the messages reported to the client. For example:
+
+<programlisting>
+CREATE FUNCTION raise_custom_exception() RETURNS void AS $$
+plpy.error("custom exception message",
+           detail="some info about exception",
+           hint="hint for users")
+$$ LANGUAGE plpythonu;
+
+=# SELECT raise_custom_exception();
+ERROR:  plpy.Error: custom exception message
+DETAIL:  some info about exception
+HINT:  hint for users
+CONTEXT:  Traceback (most recent call last):
+  PL/Python function "raise_custom_exception", line 4, in &lt;module&gt;
+    hint="hint for users")
+PL/Python function "raise_custom_exception"
+</programlisting>
+  </para>
+
+  <para>
+   Another set of utility functions are
+   <literal>plpy.quote_literal(<replaceable>string</>)</literal>,
+   <literal>plpy.quote_nullable(<replaceable>string</>)</literal>, and
+   <literal>plpy.quote_ident(<replaceable>string</>)</literal>.  They
+   are equivalent to the built-in quoting functions described in <xref
+   linkend="functions-string">.  They are useful when constructing
+   ad-hoc queries.  A PL/Python equivalent of dynamic SQL from <xref
+   linkend="plpgsql-quote-literal-example"> would be:
+<programlisting>
+plpy.execute("UPDATE tbl SET %s = %s WHERE key = %s" % (
+    plpy.quote_ident(colname),
+    plpy.quote_nullable(newvalue),
+    plpy.quote_literal(keyvalue)))
+</programlisting>
+  </para>
  </sect1>
 
  <sect1 id="plpython-envar">
@@ -1021,6 +1506,10 @@ $$ LANGUAGE plpythonu;
     <listitem>
      <para><envar>PYTHONUSERBASE</envar></para>
     </listitem>
+
+    <listitem>
+     <para><envar>PYTHONHASHSEED</envar></para>
+    </listitem>
    </itemizedlist>
 
    (It appears to be a Python implementation detail beyond the control