aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNeil Conway <neilc@samurai.com>2006-02-28 20:03:52 +0000
committerNeil Conway <neilc@samurai.com>2006-02-28 20:03:52 +0000
commit87daae1143520309da299b78a8e7a68f141a268f (patch)
tree3ad11f9a73ee33a908d877869f88b79c1afaed63 /src
parentc6b6f7ad6417ea64c4f56507b85287db97ce508c (diff)
downloadpostgresql-87daae1143520309da299b78a8e7a68f141a268f.tar.gz
postgresql-87daae1143520309da299b78a8e7a68f141a268f.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/pl/plpython/expected/plpython_function.out11
-rw-r--r--src/pl/plpython/expected/plpython_test.out16
-rw-r--r--src/pl/plpython/plpython.c32
-rw-r--r--src/pl/plpython/sql/plpython_function.sql15
-rw-r--r--src/pl/plpython/sql/plpython_test.sql5
5 files changed, 72 insertions, 7 deletions
diff --git a/src/pl/plpython/expected/plpython_function.out b/src/pl/plpython/expected/plpython_function.out
index 516d0576899..dc52f4af17d 100644
--- a/src/pl/plpython/expected/plpython_function.out
+++ b/src/pl/plpython/expected/plpython_function.out
@@ -289,3 +289,14 @@ plan = plpy.prepare("SELECT $1 AS testvalue1, $2 AS testvalue2", ["text", "text"
rv = plpy.execute(plan, u"\\x80", 1)
return rv[0]["testvalue1"]
' LANGUAGE plpythonu;
+-- Tests for functions that return void
+CREATE FUNCTION test_void_func1() RETURNS void AS $$
+x = 10
+$$ LANGUAGE plpythonu;
+-- illegal: can't return non-None value in void-returning func
+CREATE FUNCTION test_void_func2() RETURNS void AS $$
+return 10
+$$ LANGUAGE plpythonu;
+CREATE FUNCTION test_return_none() RETURNS int AS $$
+None
+$$ LANGUAGE plpythonu;
diff --git a/src/pl/plpython/expected/plpython_test.out b/src/pl/plpython/expected/plpython_test.out
index 08704cb571d..92243738f66 100644
--- a/src/pl/plpython/expected/plpython_test.out
+++ b/src/pl/plpython/expected/plpython_test.out
@@ -182,3 +182,19 @@ SELECT newline_crlf();
123
(1 row)
+-- Tests for functions returning void
+SELECT test_void_func1(), test_void_func1() IS NULL AS "is null";
+ test_void_func1 | is null
+-----------------+---------
+ | f
+(1 row)
+
+SELECT test_void_func2(); -- should fail
+ERROR: unexpected return value from plpython procedure
+DETAIL: void-returning functions must return "None"
+SELECT test_return_none(), test_return_none() IS NULL AS "is null";
+ test_return_none | is null
+------------------+---------
+ | t
+(1 row)
+
diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c
index 2df1ef39893..14c805a29ef 100644
--- a/src/pl/plpython/plpython.c
+++ b/src/pl/plpython/plpython.c
@@ -29,7 +29,7 @@
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.71 2006/02/20 20:10:37 neilc Exp $
+ * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.72 2006/02/28 20:03:52 neilc Exp $
*
*********************************************************************
*/
@@ -91,7 +91,8 @@ typedef union PLyTypeInput
*/
typedef struct PLyObToDatum
{
- FmgrInfo typfunc;
+ FmgrInfo typfunc; /* The type's input function */
+ Oid typoid; /* The OID of the type */
Oid typioparam;
bool typbyval;
} PLyObToDatum;
@@ -138,7 +139,7 @@ typedef struct PLyProcedure
int nargs;
PyObject *code; /* compiled procedure code */
PyObject *statics; /* data saved across calls, local scope */
- PyObject *globals; /* data saved across calls, global score */
+ PyObject *globals; /* data saved across calls, global scope */
PyObject *me; /* PyCObject containing pointer to this
* PLyProcedure */
} PLyProcedure;
@@ -757,9 +758,24 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
elog(ERROR, "SPI_finish failed");
/*
- * convert the python PyObject to a postgresql Datum
+ * If the function is declared to return void, the Python
+ * return value must be None. For void-returning functions, we
+ * also treat a None return value as a special "void datum"
+ * rather than NULL (as is the case for non-void-returning
+ * functions).
*/
- if (plrv == Py_None)
+ if (proc->result.out.d.typoid == VOIDOID)
+ {
+ if (plrv != Py_None)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("unexpected return value from plpython procedure"),
+ errdetail("void-returning functions must return \"None\"")));
+
+ fcinfo->isnull = false;
+ rv = (Datum) 0;
+ }
+ else if (plrv == Py_None)
{
fcinfo->isnull = true;
rv = PointerGetDatum(NULL);
@@ -1031,8 +1047,9 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
procStruct->prorettype);
rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
- /* Disallow pseudotype result */
- if (rvTypeStruct->typtype == 'p')
+ /* Disallow pseudotype result, except for void */
+ if (rvTypeStruct->typtype == 'p' &&
+ procStruct->prorettype != VOIDOID)
{
if (procStruct->prorettype == TRIGGEROID)
ereport(ERROR,
@@ -1329,6 +1346,7 @@ PLy_output_datum_func2(PLyObToDatum * arg, HeapTuple typeTup)
Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
perm_fmgr_info(typeStruct->typinput, &arg->typfunc);
+ arg->typoid = HeapTupleGetOid(typeTup);
arg->typioparam = getTypeIOParam(typeTup);
arg->typbyval = typeStruct->typbyval;
}
diff --git a/src/pl/plpython/sql/plpython_function.sql b/src/pl/plpython/sql/plpython_function.sql
index e3ec2afe014..7428a599eea 100644
--- a/src/pl/plpython/sql/plpython_function.sql
+++ b/src/pl/plpython/sql/plpython_function.sql
@@ -341,3 +341,18 @@ plan = plpy.prepare("SELECT $1 AS testvalue1, $2 AS testvalue2", ["text", "text"
rv = plpy.execute(plan, u"\\x80", 1)
return rv[0]["testvalue1"]
' LANGUAGE plpythonu;
+
+-- Tests for functions that return void
+
+CREATE FUNCTION test_void_func1() RETURNS void AS $$
+x = 10
+$$ LANGUAGE plpythonu;
+
+-- illegal: can't return non-None value in void-returning func
+CREATE FUNCTION test_void_func2() RETURNS void AS $$
+return 10
+$$ LANGUAGE plpythonu;
+
+CREATE FUNCTION test_return_none() RETURNS int AS $$
+None
+$$ LANGUAGE plpythonu;
diff --git a/src/pl/plpython/sql/plpython_test.sql b/src/pl/plpython/sql/plpython_test.sql
index 17d6b2e7922..2ebdb695a98 100644
--- a/src/pl/plpython/sql/plpython_test.sql
+++ b/src/pl/plpython/sql/plpython_test.sql
@@ -68,3 +68,8 @@ SELECT join_sequences(sequences) FROM sequences
SELECT newline_lf();
SELECT newline_cr();
SELECT newline_crlf();
+
+-- Tests for functions returning void
+SELECT test_void_func1(), test_void_func1() IS NULL AS "is null";
+SELECT test_void_func2(); -- should fail
+SELECT test_return_none(), test_return_none() IS NULL AS "is null";