Skip to content

Commit 87daae1

Browse files
author
Neil Conway
committed
Allow PL/Python functions to return void, per gripe from James Robinson
(I didn't use his patch, however). A void-returning PL/Python function must return None (from Python), which is translated into a void datum (and *not* NULL) for Postgres. I also added some regression tests for this functionality.
1 parent c6b6f7a commit 87daae1

File tree

5 files changed

+72
-7
lines changed

5 files changed

+72
-7
lines changed

src/pl/plpython/expected/plpython_function.out

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,14 @@ plan = plpy.prepare("SELECT $1 AS testvalue1, $2 AS testvalue2", ["text", "text"
289289
rv = plpy.execute(plan, u"\\x80", 1)
290290
return rv[0]["testvalue1"]
291291
' LANGUAGE plpythonu;
292+
-- Tests for functions that return void
293+
CREATE FUNCTION test_void_func1() RETURNS void AS $$
294+
x = 10
295+
$$ LANGUAGE plpythonu;
296+
-- illegal: can't return non-None value in void-returning func
297+
CREATE FUNCTION test_void_func2() RETURNS void AS $$
298+
return 10
299+
$$ LANGUAGE plpythonu;
300+
CREATE FUNCTION test_return_none() RETURNS int AS $$
301+
None
302+
$$ LANGUAGE plpythonu;

src/pl/plpython/expected/plpython_test.out

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,19 @@ SELECT newline_crlf();
182182
123
183183
(1 row)
184184

185+
-- Tests for functions returning void
186+
SELECT test_void_func1(), test_void_func1() IS NULL AS "is null";
187+
test_void_func1 | is null
188+
-----------------+---------
189+
| f
190+
(1 row)
191+
192+
SELECT test_void_func2(); -- should fail
193+
ERROR: unexpected return value from plpython procedure
194+
DETAIL: void-returning functions must return "None"
195+
SELECT test_return_none(), test_return_none() IS NULL AS "is null";
196+
test_return_none | is null
197+
------------------+---------
198+
| t
199+
(1 row)
200+

src/pl/plpython/plpython.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
3030
*
3131
* IDENTIFICATION
32-
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.71 2006/02/20 20:10:37 neilc Exp $
32+
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.72 2006/02/28 20:03:52 neilc Exp $
3333
*
3434
*********************************************************************
3535
*/
@@ -91,7 +91,8 @@ typedef union PLyTypeInput
9191
*/
9292
typedef struct PLyObToDatum
9393
{
94-
FmgrInfo typfunc;
94+
FmgrInfo typfunc; /* The type's input function */
95+
Oid typoid; /* The OID of the type */
9596
Oid typioparam;
9697
bool typbyval;
9798
} PLyObToDatum;
@@ -138,7 +139,7 @@ typedef struct PLyProcedure
138139
int nargs;
139140
PyObject *code; /* compiled procedure code */
140141
PyObject *statics; /* data saved across calls, local scope */
141-
PyObject *globals; /* data saved across calls, global score */
142+
PyObject *globals; /* data saved across calls, global scope */
142143
PyObject *me; /* PyCObject containing pointer to this
143144
* PLyProcedure */
144145
} PLyProcedure;
@@ -757,9 +758,24 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
757758
elog(ERROR, "SPI_finish failed");
758759

759760
/*
760-
* convert the python PyObject to a postgresql Datum
761+
* If the function is declared to return void, the Python
762+
* return value must be None. For void-returning functions, we
763+
* also treat a None return value as a special "void datum"
764+
* rather than NULL (as is the case for non-void-returning
765+
* functions).
761766
*/
762-
if (plrv == Py_None)
767+
if (proc->result.out.d.typoid == VOIDOID)
768+
{
769+
if (plrv != Py_None)
770+
ereport(ERROR,
771+
(errcode(ERRCODE_DATATYPE_MISMATCH),
772+
errmsg("unexpected return value from plpython procedure"),
773+
errdetail("void-returning functions must return \"None\"")));
774+
775+
fcinfo->isnull = false;
776+
rv = (Datum) 0;
777+
}
778+
else if (plrv == Py_None)
763779
{
764780
fcinfo->isnull = true;
765781
rv = PointerGetDatum(NULL);
@@ -1031,8 +1047,9 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
10311047
procStruct->prorettype);
10321048
rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
10331049

1034-
/* Disallow pseudotype result */
1035-
if (rvTypeStruct->typtype == 'p')
1050+
/* Disallow pseudotype result, except for void */
1051+
if (rvTypeStruct->typtype == 'p' &&
1052+
procStruct->prorettype != VOIDOID)
10361053
{
10371054
if (procStruct->prorettype == TRIGGEROID)
10381055
ereport(ERROR,
@@ -1329,6 +1346,7 @@ PLy_output_datum_func2(PLyObToDatum * arg, HeapTuple typeTup)
13291346
Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
13301347

13311348
perm_fmgr_info(typeStruct->typinput, &arg->typfunc);
1349+
arg->typoid = HeapTupleGetOid(typeTup);
13321350
arg->typioparam = getTypeIOParam(typeTup);
13331351
arg->typbyval = typeStruct->typbyval;
13341352
}

src/pl/plpython/sql/plpython_function.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,3 +341,18 @@ plan = plpy.prepare("SELECT $1 AS testvalue1, $2 AS testvalue2", ["text", "text"
341341
rv = plpy.execute(plan, u"\\x80", 1)
342342
return rv[0]["testvalue1"]
343343
' LANGUAGE plpythonu;
344+
345+
-- Tests for functions that return void
346+
347+
CREATE FUNCTION test_void_func1() RETURNS void AS $$
348+
x = 10
349+
$$ LANGUAGE plpythonu;
350+
351+
-- illegal: can't return non-None value in void-returning func
352+
CREATE FUNCTION test_void_func2() RETURNS void AS $$
353+
return 10
354+
$$ LANGUAGE plpythonu;
355+
356+
CREATE FUNCTION test_return_none() RETURNS int AS $$
357+
None
358+
$$ LANGUAGE plpythonu;

src/pl/plpython/sql/plpython_test.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,8 @@ SELECT join_sequences(sequences) FROM sequences
6868
SELECT newline_lf();
6969
SELECT newline_cr();
7070
SELECT newline_crlf();
71+
72+
-- Tests for functions returning void
73+
SELECT test_void_func1(), test_void_func1() IS NULL AS "is null";
74+
SELECT test_void_func2(); -- should fail
75+
SELECT test_return_none(), test_return_none() IS NULL AS "is null";

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy