Home Explore Blog CI



postgresql

11th chunk of `doc/src/sgml/plpython.sgml`
54a9fe000f7c9e6b783976fde5f558e0f887e4e6c4b8655e0000000100000fa0
 <literal>GD</literal> (see
      <xref linkend="plpython-sharing"/>). For example:
<programlisting>
CREATE FUNCTION usesavedplan() RETURNS trigger AS $$
    if "plan" in SD:
        plan = SD["plan"]
    else:
        plan = plpy.prepare("SELECT 1")
        SD["plan"] = plan
    # rest of function
$$ LANGUAGE plpython3u;
</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="https://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 plpython3u;

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 plpython3u;

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 plpython3u;
</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="https://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

Title: PL/Python Cursors and Error Handling
Summary
The plpy.cursor function allows processing large result sets in smaller chunks, providing a fetch method and iterator interface, and can be used with prepared plans and query strings, while also discussing error handling for database access functions, including trapping SPI errors and exceptions.