Skip to content

Commit 819f22a

Browse files
committed
Allow PL/python to return composite types and result sets
Sven Suursoho
1 parent b1620c5 commit 819f22a

File tree

8 files changed

+1359
-99
lines changed

8 files changed

+1359
-99
lines changed

doc/src/sgml/plpython.sgml

Lines changed: 287 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpython.sgml,v 1.30 2006/05/26 19:23:09 adunstan Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpython.sgml,v 1.31 2006/09/02 12:30:01 momjian Exp $ -->
22

33
<chapter id="plpython">
44
<title>PL/Python - Python Procedural Language</title>
@@ -46,28 +46,211 @@
4646
<title>PL/Python Functions</title>
4747

4848
<para>
49-
Functions in PL/Python are declared via the usual <xref
49+
Functions in PL/Python are declared via the standard <xref
5050
linkend="sql-createfunction" endterm="sql-createfunction-title">
51-
syntax. For example:
51+
syntax:
52+
53+
<programlisting>
54+
CREATE FUNCTION <replaceable>funcname</replaceable> (<replaceable>argument-list</replaceable>)
55+
RETURNS <replaceable>return-type</replaceable>
56+
AS $$
57+
# PL/Python function body
58+
$$ LANGUAGE plpythonu;
59+
</programlisting>
60+
</para>
61+
62+
<para>
63+
The body of a function is simply a Python script. When the function
64+
is called, all unnamed arguments are passed as elements to the array
65+
<varname>args[]</varname> and named arguments as ordinary variables to the
66+
Python script. The result is returned from the Python code in the usual way,
67+
with <literal>return</literal> or <literal>yield</literal> (in case of
68+
a resultset statement).
69+
</para>
70+
71+
<para>
72+
For example, a function to return the greater of two integers can be
73+
defined as:
74+
5275
<programlisting>
53-
CREATE FUNCTION myfunc(text) RETURNS text
54-
AS 'return args[0]'
55-
LANGUAGE plpythonu;
76+
CREATE FUNCTION pymax (a integer, b integer)
77+
RETURNS integer
78+
AS $$
79+
if a &gt; b:
80+
return a
81+
return b
82+
$$ LANGUAGE plpythonu;
5683
</programlisting>
5784

5885
The Python code that is given as the body of the function definition
59-
gets transformed into a Python function.
60-
For example, the above results in
86+
is transformed into a Python function. For example, the above results in
6187

6288
<programlisting>
63-
def __plpython_procedure_myfunc_23456():
64-
return args[0]
89+
def __plpython_procedure_pymax_23456():
90+
if a &gt; b:
91+
return a
92+
return b
6593
</programlisting>
6694

6795
assuming that 23456 is the OID assigned to the function by
6896
<productname>PostgreSQL</productname>.
6997
</para>
7098

99+
<para>
100+
The <productname>PostgreSQL</> function parameters are available in
101+
the global <varname>args</varname> list. In the
102+
<function>pymax</function> example, <varname>args[0]</varname> contains
103+
whatever was passed in as the first argument and
104+
<varname>args[1]</varname> contains the second argument's value. Alternatively,
105+
one can use named parameters as shown in the example above. This greatly simplifies
106+
the reading and writing of <application>PL/Python</application> code.
107+
</para>
108+
109+
<para>
110+
If an SQL null value<indexterm><primary>null value</primary><secondary
111+
sortas="PL/Python">PL/Python</secondary></indexterm> is passed to a
112+
function, the argument value will appear as <symbol>None</symbol> in
113+
Python. The above function definition will return the wrong answer for null
114+
inputs. We could add <literal>STRICT</literal> to the function definition
115+
to make <productname>PostgreSQL</productname> do something more reasonable:
116+
if a null value is passed, the function will not be called at all,
117+
but will just return a null result automatically. Alternatively,
118+
we could check for null inputs in the function body:
119+
120+
<programlisting>
121+
CREATE FUNCTION pymax (a integer, b integer)
122+
RETURNS integer
123+
AS $$
124+
if (a is None) or (b is None):
125+
return None
126+
if a > b:
127+
return a
128+
return b
129+
$$ LANGUAGE plpythonu;
130+
</programlisting>
131+
132+
As shown above, to return an SQL null value from a PL/Python
133+
function, return the value <symbol>None</symbol>. This can be done whether the
134+
function is strict or not.
135+
</para>
136+
137+
<para>
138+
Composite-type arguments are passed to the function as Python mappings. The
139+
element names of the mapping are the attribute names of the composite type.
140+
If an attribute in the passed row has the null value, it has the value
141+
<symbol>None</symbol> in the mapping. Here is an example:
142+
143+
<programlisting>
144+
CREATE TABLE employee (
145+
name text,
146+
salary integer,
147+
age integer
148+
);
149+
150+
CREATE FUNCTION overpaid (e employee)
151+
RETURNS boolean
152+
AS $$
153+
if e["salary"] &gt; 200000:
154+
return True
155+
if (e["age"] &lt; 30) and (e["salary"] &gt; 100000):
156+
return True
157+
return False
158+
$$ LANGUAGE plpythonu;
159+
</programlisting>
160+
</para>
161+
162+
<para>
163+
There are multiple ways to return row or composite types from a Python
164+
scripts. In following examples we assume to have:
165+
166+
<programlisting>
167+
CREATE TABLE named_value (
168+
name text,
169+
value integer
170+
);
171+
</programlisting>
172+
or
173+
<programlisting>
174+
CREATE TYPE named_value AS (
175+
name text,
176+
value integer
177+
);
178+
</programlisting>
179+
180+
<variablelist>
181+
<varlistentry>
182+
<term>Sequence types (tuple or list), but not <literal>set</literal> (because
183+
it is not indexable)</term>
184+
<listitem>
185+
<para>
186+
Returned sequence objects must have the same number of items as
187+
composite types have fields. Item with index 0 is assigned to the first field
188+
of the composite type, 1 to second and so on. For example:
189+
190+
<programlisting>
191+
CREATE FUNCTION make_pair (name text, value integer)
192+
RETURNS named_value
193+
AS $$
194+
return [ name, value ]
195+
# or alternatively, as tuple: return ( name, value )
196+
$$ LANGUAGE plpythonu;
197+
</programlisting>
198+
199+
To return SQL null in any column, insert <symbol>None</symbol> at
200+
the corresponding position.
201+
</para>
202+
</listitem>
203+
204+
<varlistentry>
205+
<term>Mapping (dictionary)</term>
206+
<listitem>
207+
<para>
208+
Value for a composite type's column is retrieved from the mapping with
209+
the column name as key. Example:
210+
211+
<programlisting>
212+
CREATE FUNCTION make_pair (name text, value integer)
213+
RETURNS named_value
214+
AS $$
215+
return { "name": name, "value": value }
216+
$$ LANGUAGE plpythonu;
217+
</programlisting>
218+
219+
Additional dictionary key/value pairs are ignored. Missing keys are
220+
treated as errors, i.e. to return an SQL null value for any column, insert
221+
<symbol>None</symbol> with the corresponding column name as the key.
222+
</para>
223+
</listitem>
224+
225+
<varlistentry>
226+
<term>Object (any object providing method <literal>__getattr__</literal>)</term>
227+
<listitem>
228+
<para>
229+
Example:
230+
231+
<programlisting>
232+
CREATE FUNCTION make_pair (name text, value integer)
233+
RETURNS named_value
234+
AS $$
235+
class named_value:
236+
def __init__ (self, n, v):
237+
self.name = n
238+
self.value = v
239+
return named_value(name, value)
240+
241+
# or simply
242+
class nv: pass
243+
nv.name = name
244+
nv.value = value
245+
return nv
246+
$$ LANGUAGE plpythonu;
247+
</programlisting>
248+
</para>
249+
</listitem>
250+
</varlistentry>
251+
</variablelist>
252+
</para>
253+
71254
<para>
72255
If you do not provide a return value, Python returns the default
73256
<symbol>None</symbol>. <application>PL/Python</application> translates
@@ -77,13 +260,100 @@ def __plpython_procedure_myfunc_23456():
77260
</para>
78261

79262
<para>
80-
The <productname>PostgreSQL</> function parameters are available in
81-
the global <varname>args</varname> list. In the
82-
<function>myfunc</function> example, <varname>args[0]</> contains
83-
whatever was passed in as the text argument. For
84-
<literal>myfunc2(text, integer)</literal>, <varname>args[0]</>
85-
would contain the <type>text</type> argument and
86-
<varname>args[1]</varname> the <type>integer</type> argument.
263+
A <application>PL/Python</application> function can also return sets of
264+
scalar or composite types. There are serveral ways to achieve this because
265+
the returned object is internally turned into an iterator. For following
266+
examples, let's assume to have composite type:
267+
268+
<programlisting>
269+
CREATE TYPE greeting AS (
270+
how text,
271+
who text
272+
);
273+
</programlisting>
274+
275+
Currently known iterable types are:
276+
<variablelist>
277+
<varlistentry>
278+
<term>Sequence types (tuple, list, set)</term>
279+
<listitem>
280+
<para>
281+
<programlisting>
282+
CREATE FUNCTION greet (how text)
283+
RETURNS SETOF greeting
284+
AS $$
285+
# return tuple containing lists as composite types
286+
# all other combinations work also
287+
return ( [ how, "World" ], [ how, "PostgreSQL" ], [ how, "PL/Python" ] )
288+
$$ LANGUAGE plpythonu;
289+
</programlisting>
290+
</para>
291+
</listitem>
292+
</varlistentry>
293+
294+
<varlistentry>
295+
<term>Iterator (any object providing <symbol>__iter__</symbol> and
296+
<symbol>next</symbol> methods)</term>
297+
<listitem>
298+
<para>
299+
<programlisting>
300+
CREATE FUNCTION greet (how text)
301+
RETURNS SETOF greeting
302+
AS $$
303+
class producer:
304+
def __init__ (self, how, who):
305+
self.how = how
306+
self.who = who
307+
self.ndx = -1
308+
309+
def __iter__ (self):
310+
return self
311+
312+
def next (self):
313+
self.ndx += 1
314+
if self.ndx == len(self.who):
315+
raise StopIteration
316+
return ( self.how, self.who[self.ndx] )
317+
318+
return producer(how, [ "World", "PostgreSQL", "PL/Python" ])
319+
$$ LANGUAGE plpythonu;
320+
</programlisting>
321+
</para>
322+
</listitem>
323+
</varlistentry>
324+
325+
<varlistentry>
326+
<term>Generator (<literal>yield</literal>)</term>
327+
<listitem>
328+
<para>
329+
<programlisting>
330+
CREATE FUNCTION greet (how text)
331+
RETURNS SETOF greeting
332+
AS $$
333+
for who in [ "World", "PostgreSQL", "PL/Python" ]:
334+
yield ( how, who )
335+
$$ LANGUAGE plpythonu;
336+
</programlisting>
337+
338+
<warning>
339+
<para>
340+
Currently, due to Python
341+
<ulink url="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=1483133&amp;group_id=5470&amp;atid=105470">bug #1483133</ulink>,
342+
some debug versions of Python 2.4
343+
(configured and compiled with option <literal>--with-pydebug</literal>)
344+
are known to crash the <productname>PostgreSQL</productname> server.
345+
Unpatched versions of Fedora 4 contain this bug.
346+
It does not happen in production version of Python or on patched
347+
versions of Fedora 4.
348+
</para>
349+
</warning>
350+
</para>
351+
</listitem>
352+
</varlistentry>
353+
</variablelist>
354+
355+
Whenever new iterable types are added to Python language,
356+
<application>PL/Python</application> is ready to use it.
87357
</para>
88358

89359
<para>

0 commit comments

Comments
 (0)