|
|
@ -14,8 +14,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
<para>
|
|
|
|
To install PL/Python in a particular database, use
|
|
|
|
To install PL/Python in a particular database, use
|
|
|
|
<literal>CREATE EXTENSION plpythonu</literal> (but
|
|
|
|
<literal>CREATE EXTENSION plpython3u</literal>.
|
|
|
|
see also <xref linkend="plpython-python23"/>).
|
|
|
|
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
|
|
<tip>
|
|
|
|
<tip>
|
|
|
@ -28,14 +27,14 @@
|
|
|
|
<para>
|
|
|
|
<para>
|
|
|
|
PL/Python is only available as an <quote>untrusted</quote> language, meaning
|
|
|
|
PL/Python is only available as an <quote>untrusted</quote> language, meaning
|
|
|
|
it does not offer any way of restricting what users can do in it and
|
|
|
|
it does not offer any way of restricting what users can do in it and
|
|
|
|
is therefore named <literal>plpythonu</literal>. A trusted
|
|
|
|
is therefore named <literal>plpython3u</literal>. A trusted
|
|
|
|
variant <literal>plpython</literal> might become available in the future
|
|
|
|
variant <literal>plpython</literal> might become available in the future
|
|
|
|
if a secure execution mechanism is developed in Python. The
|
|
|
|
if a secure execution mechanism is developed in Python. The
|
|
|
|
writer of a function in untrusted PL/Python must take care that 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
|
|
|
|
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
|
|
|
|
able to do anything that could be done by a user logged in as the
|
|
|
|
database administrator. Only superusers can create functions in
|
|
|
|
database administrator. Only superusers can create functions in
|
|
|
|
untrusted languages such as <literal>plpythonu</literal>.
|
|
|
|
untrusted languages such as <literal>plpython3u</literal>.
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
|
|
<note>
|
|
|
|
<note>
|
|
|
@ -47,140 +46,6 @@
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
</note>
|
|
|
|
</note>
|
|
|
|
|
|
|
|
|
|
|
|
<sect1 id="plpython-python23">
|
|
|
|
|
|
|
|
<title>Python 2 vs. Python 3</title>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
|
|
|
PL/Python supports both the Python 2 and Python 3 language
|
|
|
|
|
|
|
|
variants. (The PostgreSQL installation instructions might contain
|
|
|
|
|
|
|
|
more precise information about the exact supported minor versions
|
|
|
|
|
|
|
|
of Python.) Because the Python 2 and Python 3 language variants
|
|
|
|
|
|
|
|
are incompatible in some important aspects, the following naming
|
|
|
|
|
|
|
|
and transitioning scheme is used by PL/Python to avoid mixing them:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<itemizedlist>
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
|
|
|
The PostgreSQL language named <literal>plpython2u</literal>
|
|
|
|
|
|
|
|
implements PL/Python based on the Python 2 language variant.
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
|
|
|
The PostgreSQL language named <literal>plpython3u</literal>
|
|
|
|
|
|
|
|
implements PL/Python based on the Python 3 language variant.
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
|
|
|
The language named <literal>plpythonu</literal> implements
|
|
|
|
|
|
|
|
PL/Python based on the default Python language variant, which is
|
|
|
|
|
|
|
|
currently Python 2. (This default is independent of what any
|
|
|
|
|
|
|
|
local Python installations might consider to be
|
|
|
|
|
|
|
|
their <quote>default</quote>, for example,
|
|
|
|
|
|
|
|
what <filename>/usr/bin/python</filename> might be.) The
|
|
|
|
|
|
|
|
default will probably be changed to Python 3 in a distant future
|
|
|
|
|
|
|
|
release of PostgreSQL, depending on the progress of the
|
|
|
|
|
|
|
|
migration to Python 3 in the Python community.
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This scheme is analogous to the recommendations in <ulink
|
|
|
|
|
|
|
|
url="https://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>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<tip>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
|
|
|
The built variant depends on which Python version was found during
|
|
|
|
|
|
|
|
the installation or which version was explicitly set using
|
|
|
|
|
|
|
|
the <envar>PYTHON</envar> environment variable;
|
|
|
|
|
|
|
|
see <xref linkend="install-procedure"/>. To make both variants of
|
|
|
|
|
|
|
|
PL/Python available in one installation, the source tree has to be
|
|
|
|
|
|
|
|
configured and built twice.
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
</tip>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
|
|
|
This results in the following usage and migration strategy:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<itemizedlist>
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
|
|
|
Existing users and users who are currently not interested in
|
|
|
|
|
|
|
|
Python 3 use the language name <literal>plpythonu</literal> and
|
|
|
|
|
|
|
|
don't have to change anything for the foreseeable future. It is
|
|
|
|
|
|
|
|
recommended to gradually <quote>future-proof</quote> the code
|
|
|
|
|
|
|
|
via migration to Python 2.6/2.7 to simplify the eventual
|
|
|
|
|
|
|
|
migration to Python 3.
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
|
|
|
In practice, many PL/Python functions will migrate to Python 3
|
|
|
|
|
|
|
|
with few or no changes.
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
|
|
|
Users who know that they have heavily Python 2 dependent code
|
|
|
|
|
|
|
|
and don't plan to ever change it can make use of
|
|
|
|
|
|
|
|
the <literal>plpython2u</literal> language name. This will
|
|
|
|
|
|
|
|
continue to work into the very distant future, until Python 2
|
|
|
|
|
|
|
|
support might be completely dropped by PostgreSQL.
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
|
|
|
Users who want to dive into Python 3 can use
|
|
|
|
|
|
|
|
the <literal>plpython3u</literal> language name, which will keep
|
|
|
|
|
|
|
|
working forever by today's standards. In the distant future,
|
|
|
|
|
|
|
|
when Python 3 might become the default, they might like to
|
|
|
|
|
|
|
|
remove the <quote>3</quote> for aesthetic reasons.
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
|
|
|
Daredevils, who want to build a Python-3-only operating system
|
|
|
|
|
|
|
|
environment, can change the contents of
|
|
|
|
|
|
|
|
<literal>plpythonu</literal>'s extension control and script files
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
|
|
|
See also the
|
|
|
|
|
|
|
|
document <ulink url="https://docs.python.org/3/whatsnew/3.0.html">What's
|
|
|
|
|
|
|
|
New In Python 3.0</ulink> for more information about porting to
|
|
|
|
|
|
|
|
Python 3.
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
|
|
|
It is not allowed to use PL/Python based on Python 2 and PL/Python
|
|
|
|
|
|
|
|
based on Python 3 in the same session, because the symbols in the
|
|
|
|
|
|
|
|
dynamic modules would clash, which could result in crashes of the
|
|
|
|
|
|
|
|
PostgreSQL server process. There is a check that prevents mixing
|
|
|
|
|
|
|
|
Python major versions in a session, which will abort the session if
|
|
|
|
|
|
|
|
a mismatch is detected. It is possible, however, to use both
|
|
|
|
|
|
|
|
PL/Python variants in the same database, from separate sessions.
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<sect1 id="plpython-funcs">
|
|
|
|
<sect1 id="plpython-funcs">
|
|
|
|
<title>PL/Python Functions</title>
|
|
|
|
<title>PL/Python Functions</title>
|
|
|
|
|
|
|
|
|
|
|
@ -193,7 +58,7 @@ CREATE FUNCTION <replaceable>funcname</replaceable> (<replaceable>argument-list<
|
|
|
|
RETURNS <replaceable>return-type</replaceable>
|
|
|
|
RETURNS <replaceable>return-type</replaceable>
|
|
|
|
AS $$
|
|
|
|
AS $$
|
|
|
|
# PL/Python function body
|
|
|
|
# PL/Python function body
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
|
@ -225,7 +90,7 @@ AS $$
|
|
|
|
if a > b:
|
|
|
|
if a > b:
|
|
|
|
return a
|
|
|
|
return a
|
|
|
|
return b
|
|
|
|
return b
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
|
|
|
|
The Python code that is given as the body of the function definition
|
|
|
|
The Python code that is given as the body of the function definition
|
|
|
@ -255,7 +120,7 @@ CREATE FUNCTION pystrip(x text)
|
|
|
|
AS $$
|
|
|
|
AS $$
|
|
|
|
x = x.strip() # error
|
|
|
|
x = x.strip() # error
|
|
|
|
return x
|
|
|
|
return x
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
because assigning to <varname>x</varname>
|
|
|
|
because assigning to <varname>x</varname>
|
|
|
|
makes <varname>x</varname> a local variable for the entire block,
|
|
|
|
makes <varname>x</varname> a local variable for the entire block,
|
|
|
@ -271,7 +136,7 @@ AS $$
|
|
|
|
global x
|
|
|
|
global x
|
|
|
|
x = x.strip() # ok now
|
|
|
|
x = x.strip() # ok now
|
|
|
|
return x
|
|
|
|
return x
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
But it is advisable not to rely on this implementation detail of
|
|
|
|
But it is advisable not to rely on this implementation detail of
|
|
|
|
PL/Python. It is better to treat the function parameters as
|
|
|
|
PL/Python. It is better to treat the function parameters as
|
|
|
@ -303,11 +168,8 @@ $$ LANGUAGE plpythonu;
|
|
|
|
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
<para>
|
|
|
|
PostgreSQL <type>smallint</type> and <type>int</type> are
|
|
|
|
PostgreSQL <type>smallint</type>, <type>int</type>, <type>bigint</type>
|
|
|
|
converted to Python <type>int</type>.
|
|
|
|
and <type>oid</type> are converted to Python <type>int</type>.
|
|
|
|
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>
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
|
@ -335,19 +197,15 @@ $$ LANGUAGE plpythonu;
|
|
|
|
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
<para>
|
|
|
|
PostgreSQL <type>bytea</type> is converted to
|
|
|
|
PostgreSQL <type>bytea</type> is converted to Python <type>bytes</type>.
|
|
|
|
Python <type>str</type> in Python 2 and to <type>bytes</type>
|
|
|
|
|
|
|
|
in Python 3. In Python 2, the string should be treated as a
|
|
|
|
|
|
|
|
byte sequence without any character encoding.
|
|
|
|
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
<para>
|
|
|
|
All other data types, including the PostgreSQL character string
|
|
|
|
All other data types, including the PostgreSQL character string types,
|
|
|
|
types, are converted to a Python <type>str</type>. In Python
|
|
|
|
are converted to a Python <type>str</type> (in Unicode like all Python
|
|
|
|
2, this string will be in the PostgreSQL server encoding; in
|
|
|
|
strings).
|
|
|
|
Python 3, it will be a Unicode string like all strings.
|
|
|
|
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
|
@ -375,10 +233,10 @@ $$ LANGUAGE plpythonu;
|
|
|
|
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
<para>
|
|
|
|
When the PostgreSQL return type is <type>bytea</type>, the
|
|
|
|
When the PostgreSQL return type is <type>bytea</type>, the return value
|
|
|
|
return value will be converted to a string (Python 2) or bytes
|
|
|
|
will be converted to Python <type>bytes</type> using the respective
|
|
|
|
(Python 3) using the respective Python built-ins, with the
|
|
|
|
Python built-ins, with the result being converted to
|
|
|
|
result being converted to <type>bytea</type>.
|
|
|
|
<type>bytea</type>.
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
|
@ -393,14 +251,8 @@ $$ LANGUAGE plpythonu;
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
<para>
|
|
|
|
Strings in Python 2 are required to be in the PostgreSQL server
|
|
|
|
Strings are automatically converted to the PostgreSQL server encoding
|
|
|
|
encoding when they are passed to PostgreSQL. Strings that are
|
|
|
|
when they are passed to PostgreSQL.
|
|
|
|
not valid in the current server encoding will raise an error,
|
|
|
|
|
|
|
|
but not all encoding mismatches can be detected, so garbage
|
|
|
|
|
|
|
|
data can still result when this is not done correctly. Unicode
|
|
|
|
|
|
|
|
strings are converted to the correct encoding automatically, so
|
|
|
|
|
|
|
|
it can be safer and more convenient to use those. In Python 3,
|
|
|
|
|
|
|
|
all strings are Unicode strings.
|
|
|
|
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
|
@ -440,7 +292,7 @@ AS $$
|
|
|
|
if a > b:
|
|
|
|
if a > b:
|
|
|
|
return a
|
|
|
|
return a
|
|
|
|
return b
|
|
|
|
return b
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
|
|
|
|
As shown above, to return an SQL null value from a PL/Python
|
|
|
|
As shown above, to return an SQL null value from a PL/Python
|
|
|
@ -461,10 +313,10 @@ CREATE FUNCTION return_arr()
|
|
|
|
RETURNS int[]
|
|
|
|
RETURNS int[]
|
|
|
|
AS $$
|
|
|
|
AS $$
|
|
|
|
return [1, 2, 3, 4, 5]
|
|
|
|
return [1, 2, 3, 4, 5]
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
|
|
|
|
|
|
|
|
SELECT return_arr();
|
|
|
|
SELECT return_arr();
|
|
|
|
return_arr
|
|
|
|
return_arr
|
|
|
|
-------------
|
|
|
|
-------------
|
|
|
|
{1,2,3,4,5}
|
|
|
|
{1,2,3,4,5}
|
|
|
|
(1 row)
|
|
|
|
(1 row)
|
|
|
@ -479,11 +331,11 @@ SELECT return_arr();
|
|
|
|
CREATE FUNCTION test_type_conversion_array_int4(x int4[]) RETURNS int4[] AS $$
|
|
|
|
CREATE FUNCTION test_type_conversion_array_int4(x int4[]) RETURNS int4[] AS $$
|
|
|
|
plpy.info(x, type(x))
|
|
|
|
plpy.info(x, type(x))
|
|
|
|
return x
|
|
|
|
return x
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
|
|
|
|
|
|
|
|
SELECT * FROM test_type_conversion_array_int4(ARRAY[[1,2,3],[4,5,6]]);
|
|
|
|
SELECT * FROM test_type_conversion_array_int4(ARRAY[[1,2,3],[4,5,6]]);
|
|
|
|
INFO: ([[1, 2, 3], [4, 5, 6]], <type 'list'>)
|
|
|
|
INFO: ([[1, 2, 3], [4, 5, 6]], <type 'list'>)
|
|
|
|
test_type_conversion_array_int4
|
|
|
|
test_type_conversion_array_int4
|
|
|
|
---------------------------------
|
|
|
|
---------------------------------
|
|
|
|
{{1,2,3},{4,5,6}}
|
|
|
|
{{1,2,3},{4,5,6}}
|
|
|
|
(1 row)
|
|
|
|
(1 row)
|
|
|
@ -506,7 +358,7 @@ CREATE FUNCTION return_str_arr()
|
|
|
|
RETURNS varchar[]
|
|
|
|
RETURNS varchar[]
|
|
|
|
AS $$
|
|
|
|
AS $$
|
|
|
|
return "hello"
|
|
|
|
return "hello"
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
|
|
|
|
|
|
|
|
SELECT return_str_arr();
|
|
|
|
SELECT return_str_arr();
|
|
|
|
return_str_arr
|
|
|
|
return_str_arr
|
|
|
@ -540,7 +392,7 @@ AS $$
|
|
|
|
if (e["age"] < 30) and (e["salary"] > 100000):
|
|
|
|
if (e["age"] < 30) and (e["salary"] > 100000):
|
|
|
|
return True
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
|
@ -574,7 +426,7 @@ CREATE FUNCTION make_pair (name text, value integer)
|
|
|
|
AS $$
|
|
|
|
AS $$
|
|
|
|
return ( name, value )
|
|
|
|
return ( name, value )
|
|
|
|
# or alternatively, as list: return [ name, value ]
|
|
|
|
# or alternatively, as list: return [ name, value ]
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
|
|
|
|
To return an SQL null for any column, insert <symbol>None</symbol> at
|
|
|
|
To return an SQL null for any column, insert <symbol>None</symbol> at
|
|
|
@ -600,7 +452,7 @@ CREATE FUNCTION make_pair (name text, value integer)
|
|
|
|
RETURNS named_value
|
|
|
|
RETURNS named_value
|
|
|
|
AS $$
|
|
|
|
AS $$
|
|
|
|
return { "name": name, "value": value }
|
|
|
|
return { "name": name, "value": value }
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
|
|
|
|
Any extra dictionary key/value pairs are ignored. Missing keys are
|
|
|
|
Any extra dictionary key/value pairs are ignored. Missing keys are
|
|
|
@ -633,7 +485,7 @@ AS $$
|
|
|
|
nv.name = name
|
|
|
|
nv.name = name
|
|
|
|
nv.value = value
|
|
|
|
nv.value = value
|
|
|
|
return nv
|
|
|
|
return nv
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</listitem>
|
|
|
@ -646,7 +498,7 @@ $$ LANGUAGE plpythonu;
|
|
|
|
<programlisting>
|
|
|
|
<programlisting>
|
|
|
|
CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$
|
|
|
|
CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$
|
|
|
|
return (1, 2)
|
|
|
|
return (1, 2)
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
|
|
|
|
|
|
|
|
SELECT * FROM multiout_simple();
|
|
|
|
SELECT * FROM multiout_simple();
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
@ -657,7 +509,7 @@ SELECT * FROM multiout_simple();
|
|
|
|
<programlisting>
|
|
|
|
<programlisting>
|
|
|
|
CREATE PROCEDURE python_triple(INOUT a integer, INOUT b integer) AS $$
|
|
|
|
CREATE PROCEDURE python_triple(INOUT a integer, INOUT b integer) AS $$
|
|
|
|
return (a * 3, b * 3)
|
|
|
|
return (a * 3, b * 3)
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
|
|
|
|
|
|
|
|
CALL python_triple(5, 10);
|
|
|
|
CALL python_triple(5, 10);
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
@ -693,7 +545,7 @@ AS $$
|
|
|
|
# return tuple containing lists as composite types
|
|
|
|
# return tuple containing lists as composite types
|
|
|
|
# all other combinations work also
|
|
|
|
# all other combinations work also
|
|
|
|
return ( [ how, "World" ], [ how, "PostgreSQL" ], [ how, "PL/Python" ] )
|
|
|
|
return ( [ how, "World" ], [ how, "PostgreSQL" ], [ how, "PL/Python" ] )
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</listitem>
|
|
|
@ -724,7 +576,7 @@ AS $$
|
|
|
|
return ( self.how, self.who[self.ndx] )
|
|
|
|
return ( self.how, self.who[self.ndx] )
|
|
|
|
|
|
|
|
|
|
|
|
return producer(how, [ "World", "PostgreSQL", "PL/Python" ])
|
|
|
|
return producer(how, [ "World", "PostgreSQL", "PL/Python" ])
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</listitem>
|
|
|
@ -740,7 +592,7 @@ CREATE FUNCTION greet (how text)
|
|
|
|
AS $$
|
|
|
|
AS $$
|
|
|
|
for who in [ "World", "PostgreSQL", "PL/Python" ]:
|
|
|
|
for who in [ "World", "PostgreSQL", "PL/Python" ]:
|
|
|
|
yield ( how, who )
|
|
|
|
yield ( how, who )
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
@ -756,7 +608,7 @@ $$ LANGUAGE plpythonu;
|
|
|
|
<programlisting>
|
|
|
|
<programlisting>
|
|
|
|
CREATE FUNCTION multiout_simple_setof(n integer, OUT integer, OUT integer) RETURNS SETOF record AS $$
|
|
|
|
CREATE FUNCTION multiout_simple_setof(n integer, OUT integer, OUT integer) RETURNS SETOF record AS $$
|
|
|
|
return [(1, 2)] * n
|
|
|
|
return [(1, 2)] * n
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
|
|
|
|
|
|
|
|
SELECT * FROM multiout_simple_setof(3);
|
|
|
|
SELECT * FROM multiout_simple_setof(3);
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
@ -794,7 +646,7 @@ SELECT * FROM multiout_simple_setof(3);
|
|
|
|
<programlisting>
|
|
|
|
<programlisting>
|
|
|
|
DO $$
|
|
|
|
DO $$
|
|
|
|
# PL/Python code
|
|
|
|
# PL/Python code
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
|
|
|
|
An anonymous code block receives no arguments, and whatever value it
|
|
|
|
An anonymous code block receives no arguments, and whatever value it
|
|
|
@ -1089,7 +941,7 @@ CREATE FUNCTION usesavedplan() RETURNS trigger AS $$
|
|
|
|
plan = plpy.prepare("SELECT 1")
|
|
|
|
plan = plpy.prepare("SELECT 1")
|
|
|
|
SD["plan"] = plan
|
|
|
|
SD["plan"] = plan
|
|
|
|
# rest of function
|
|
|
|
# rest of function
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</listitem>
|
|
|
@ -1132,7 +984,7 @@ for row in plpy.cursor("select num from largetable"):
|
|
|
|
if row['num'] % 2:
|
|
|
|
if row['num'] % 2:
|
|
|
|
odd += 1
|
|
|
|
odd += 1
|
|
|
|
return odd
|
|
|
|
return odd
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE FUNCTION count_odd_fetch(batch_size integer) RETURNS integer AS $$
|
|
|
|
CREATE FUNCTION count_odd_fetch(batch_size integer) RETURNS integer AS $$
|
|
|
|
odd = 0
|
|
|
|
odd = 0
|
|
|
@ -1145,7 +997,7 @@ while True:
|
|
|
|
if row['num'] % 2:
|
|
|
|
if row['num'] % 2:
|
|
|
|
odd += 1
|
|
|
|
odd += 1
|
|
|
|
return odd
|
|
|
|
return odd
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE FUNCTION count_odd_prepared() RETURNS integer AS $$
|
|
|
|
CREATE FUNCTION count_odd_prepared() RETURNS integer AS $$
|
|
|
|
odd = 0
|
|
|
|
odd = 0
|
|
|
@ -1153,7 +1005,7 @@ plan = plpy.prepare("select num from largetable where num % $1 <> 0", ["in
|
|
|
|
rows = list(plpy.cursor(plan, [2])) # or: = list(plan.cursor([2]))
|
|
|
|
rows = list(plpy.cursor(plan, [2])) # or: = list(plan.cursor([2]))
|
|
|
|
|
|
|
|
|
|
|
|
return len(rows)
|
|
|
|
return len(rows)
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
|
@ -1198,7 +1050,7 @@ CREATE FUNCTION try_adding_joe() RETURNS text AS $$
|
|
|
|
return "something went wrong"
|
|
|
|
return "something went wrong"
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
return "Joe added"
|
|
|
|
return "Joe added"
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
|
@ -1231,7 +1083,7 @@ except plpy.SPIError as e:
|
|
|
|
return "other error, SQLSTATE %s" % e.sqlstate
|
|
|
|
return "other error, SQLSTATE %s" % e.sqlstate
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
return "fraction inserted"
|
|
|
|
return "fraction inserted"
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
Note that because all exceptions from
|
|
|
|
Note that because all exceptions from
|
|
|
|
the <literal>plpy.spiexceptions</literal> module inherit
|
|
|
|
the <literal>plpy.spiexceptions</literal> module inherit
|
|
|
@ -1280,7 +1132,7 @@ else:
|
|
|
|
result = "funds transferred correctly"
|
|
|
|
result = "funds transferred correctly"
|
|
|
|
plan = plpy.prepare("INSERT INTO operations (result) VALUES ($1)", ["text"])
|
|
|
|
plan = plpy.prepare("INSERT INTO operations (result) VALUES ($1)", ["text"])
|
|
|
|
plpy.execute(plan, [result])
|
|
|
|
plpy.execute(plan, [result])
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
If the second <literal>UPDATE</literal> statement results in an
|
|
|
|
If the second <literal>UPDATE</literal> statement results in an
|
|
|
|
exception being raised, this function will report the error, but
|
|
|
|
exception being raised, this function will report the error, but
|
|
|
@ -1312,7 +1164,7 @@ else:
|
|
|
|
result = "funds transferred correctly"
|
|
|
|
result = "funds transferred correctly"
|
|
|
|
plan = plpy.prepare("INSERT INTO operations (result) VALUES ($1)", ["text"])
|
|
|
|
plan = plpy.prepare("INSERT INTO operations (result) VALUES ($1)", ["text"])
|
|
|
|
plpy.execute(plan, [result])
|
|
|
|
plpy.execute(plan, [result])
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
</programlisting>
|
|
|
|
</programlisting>
|
|
|
|
Note that the use of <literal>try/catch</literal> is still
|
|
|
|
Note that the use of <literal>try/catch</literal> is still
|
|
|
|
required. Otherwise the exception would propagate to the top of
|
|
|
|
required. Otherwise the exception would propagate to the top of
|
|
|
@ -1329,44 +1181,6 @@ $$ LANGUAGE plpythonu;
|
|
|
|
to be rolled back.
|
|
|
|
to be rolled back.
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
</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. For compatibility with
|
|
|
|
|
|
|
|
older Python versions, 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 as 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>
|
|
|
|
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
</sect1>
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
|
|
<sect1 id="plpython-transactions">
|
|
|
|
<sect1 id="plpython-transactions">
|
|
|
@ -1389,7 +1203,7 @@ $$ LANGUAGE plpythonu;
|
|
|
|
Here is an example:
|
|
|
|
Here is an example:
|
|
|
|
<programlisting>
|
|
|
|
<programlisting>
|
|
|
|
CREATE PROCEDURE transaction_test1()
|
|
|
|
CREATE PROCEDURE transaction_test1()
|
|
|
|
LANGUAGE plpythonu
|
|
|
|
LANGUAGE plpython3u
|
|
|
|
AS $$
|
|
|
|
AS $$
|
|
|
|
for i in range(0, 10):
|
|
|
|
for i in range(0, 10):
|
|
|
|
plpy.execute("INSERT INTO test1 (a) VALUES (%d)" % i)
|
|
|
|
plpy.execute("INSERT INTO test1 (a) VALUES (%d)" % i)
|
|
|
@ -1465,7 +1279,7 @@ CREATE FUNCTION raise_custom_exception() RETURNS void AS $$
|
|
|
|
plpy.error("custom exception message",
|
|
|
|
plpy.error("custom exception message",
|
|
|
|
detail="some info about exception",
|
|
|
|
detail="some info about exception",
|
|
|
|
hint="hint for users")
|
|
|
|
hint="hint for users")
|
|
|
|
$$ LANGUAGE plpythonu;
|
|
|
|
$$ LANGUAGE plpython3u;
|
|
|
|
|
|
|
|
|
|
|
|
=# SELECT raise_custom_exception();
|
|
|
|
=# SELECT raise_custom_exception();
|
|
|
|
ERROR: plpy.Error: custom exception message
|
|
|
|
ERROR: plpy.Error: custom exception message
|
|
|
@ -1496,6 +1310,17 @@ plpy.execute("UPDATE tbl SET %s = %s WHERE key = %s" % (
|
|
|
|
</para>
|
|
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<sect1 id="plpython-python23">
|
|
|
|
|
|
|
|
<title>Python 2 vs. Python 3</title>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
|
|
|
PL/Python supports only Python 3. Past versions of
|
|
|
|
|
|
|
|
<productname>PostgreSQL</productname> supported Python 2, using the
|
|
|
|
|
|
|
|
<literal>plpythonu</literal> and <literal>plpython2u</literal> language
|
|
|
|
|
|
|
|
names.
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
|
|
<sect1 id="plpython-envar">
|
|
|
|
<sect1 id="plpython-envar">
|
|
|
|
<title>Environment Variables</title>
|
|
|
|
<title>Environment Variables</title>
|
|
|
|
|
|
|
|
|
|
|
|