who in [ "World", "PostgreSQL", "PL/Python" ]:
yield ( how, who )
$$ LANGUAGE plpython3u;
</programlisting>
</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 plpython3u;
SELECT * FROM multiout_simple_setof(3);
</programlisting>
</para>
</sect2>
</sect1>
<sect1 id="plpython-sharing">
<title>Sharing Data</title>
<para>
The global dictionary <varname>SD</varname> is available to store
private data between repeated calls to the same function.
The global dictionary <varname>GD</varname> is public data,
that is available to all Python functions within a session; use with
care.<indexterm><primary>global data</primary>
<secondary>in PL/Python</secondary></indexterm>
</para>
<para>
Each function gets its own execution environment in the
Python interpreter, so that global data and function arguments from
<function>myfunc</function> are not available to
<function>myfunc2</function>. The exception is the data in the
<varname>GD</varname> dictionary, as mentioned above.
</para>
</sect1>
<sect1 id="plpython-do">
<title>Anonymous Code Blocks</title>
<para>
PL/Python also supports anonymous code blocks called with the
<xref linkend="sql-do"/> statement:
<programlisting>
DO $$
# PL/Python code
$$ LANGUAGE plpython3u;
</programlisting>
An anonymous code block receives no arguments, and whatever value it
might return is discarded. Otherwise it behaves just like a function.
</para>
</sect1>
<sect1 id="plpython-trigger">
<title>Trigger Functions</title>
<indexterm zone="plpython-trigger">
<primary>trigger</primary>
<secondary>in PL/Python</secondary>
</indexterm>
<para>
When a function is used as a trigger, the dictionary
<literal>TD</literal> contains trigger-related values:
<variablelist>
<varlistentry>
<term><literal>TD["event"]</literal></term>
<listitem>
<para>
contains the event as a string:
<literal>INSERT</literal>, <literal>UPDATE</literal>,
<literal>DELETE</literal>, or <literal>TRUNCATE</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>TD["when"]</literal></term>
<listitem>
<para>
contains one of <literal>BEFORE</literal>, <literal>AFTER</literal>, or
<literal>INSTEAD OF</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>TD["level"]</literal></term>
<listitem>
<para>
contains <literal>ROW</literal> or <literal>STATEMENT</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>TD["new"]</literal></term>
<term><literal>TD["old"]</literal></term>
<listitem>
<para>
For a row-level trigger, one or both of these fields contain
the respective trigger rows, depending on the trigger event.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>TD["name"]</literal></term>
<listitem>
<para>
contains the trigger name.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>TD["table_name"]</literal></term>
<listitem>
<para>
contains the name of the table on which the trigger occurred.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>TD["table_schema"]</literal></term>
<listitem>
<para>
contains the schema of the table on which the trigger occurred.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>TD["relid"]</literal></term>