Commit bdc7dd67 authored by Tom Lane's avatar Tom Lane

Fix plpython to not get totally confused by OUT arguments. (It still doesn't

support multiple OUT arguments, though.)

Hannu Krosing
parent d61eecb5
...@@ -436,3 +436,14 @@ elif typ == 'obj': ...@@ -436,3 +436,14 @@ elif typ == 'obj':
type_record.second = second type_record.second = second
return type_record return type_record
$$ LANGUAGE plpythonu; $$ LANGUAGE plpythonu;
CREATE FUNCTION test_in_out_params(first in text, second out text) AS $$
return first + '_in_to_out';
$$ LANGUAGE plpythonu;
-- this doesn't work yet :-(
CREATE FUNCTION test_in_out_params_multi(first in text,
second out text, third out text) AS $$
return first + '_record_in_to_out';
$$ LANGUAGE plpythonu;
CREATE FUNCTION test_inout_params(first inout text) AS $$
return first + '_inout';
$$ LANGUAGE plpythonu;
...@@ -539,3 +539,18 @@ SELECT * FROM test_type_record_as('obj', null, null, true); ...@@ -539,3 +539,18 @@ SELECT * FROM test_type_record_as('obj', null, null, true);
| |
(1 row) (1 row)
SELECT * FROM test_in_out_params('test_in');
second
-------------------
test_in_in_to_out
(1 row)
-- this doesn't work yet :-(
SELECT * FROM test_in_out_params_multi('test_in');
ERROR: plpython functions cannot return type record
SELECT * FROM test_inout_params('test_in');
first
---------------
test_in_inout
(1 row)
/********************************************************************** /**********************************************************************
* plpython.c - python as a procedural language for PostgreSQL * plpython.c - python as a procedural language for PostgreSQL
* *
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.108 2008/03/28 00:21:56 tgl Exp $ * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.109 2008/05/03 02:47:47 tgl Exp $
* *
********************************************************************* *********************************************************************
*/ */
...@@ -1161,9 +1161,6 @@ PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key) ...@@ -1161,9 +1161,6 @@ PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key)
bool isnull; bool isnull;
int i, int i,
rv; rv;
Datum argnames;
Datum *elems;
int nelems;
procStruct = (Form_pg_proc) GETSTRUCT(procTup); procStruct = (Form_pg_proc) GETSTRUCT(procTup);
...@@ -1249,58 +1246,83 @@ PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key) ...@@ -1249,58 +1246,83 @@ PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key)
} }
/* /*
* now get information required for input conversion of the * Now get information required for input conversion of the
* procedure's arguments. * procedure's arguments. Note that we ignore output arguments
* here --- since we don't support returning record, and that was
* already checked above, there's no need to worry about multiple
* output arguments.
*/ */
proc->nargs = procStruct->pronargs; if (procStruct->pronargs)
if (proc->nargs) {
{ Oid *types;
argnames = SysCacheGetAttr(PROCOID, procTup, Anum_pg_proc_proargnames, &isnull); char **names,
if (!isnull) *modes;
{ int i,
/* XXX this code is WRONG if there are any output arguments */ pos,
deconstruct_array(DatumGetArrayTypeP(argnames), TEXTOID, -1, false, 'i', total;
&elems, NULL, &nelems);
if (nelems != proc->nargs) /* extract argument type info from the pg_proc tuple */
elog(ERROR, total = get_func_arg_info(procTup, &types, &names, &modes);
"proargnames must have the same number of elements "
"as the function has arguments"); /* count number of in+inout args into proc->nargs */
proc->argnames = (char **) PLy_malloc(sizeof(char *) * proc->nargs); if (modes == NULL)
memset(proc->argnames, 0, sizeof(char *) * proc->nargs); proc->nargs = total;
else
{
/* proc->nargs was initialized to 0 above */
for (i = 0; i < total; i++)
{
if (modes[i] != 'o')
(proc->nargs)++;
} }
} }
for (i = 0; i < proc->nargs; i++)
proc->argnames = (char **) PLy_malloc(sizeof(char *) * proc->nargs);
for (i = pos = 0; i < total; i++)
{ {
HeapTuple argTypeTup; HeapTuple argTypeTup;
Form_pg_type argTypeStruct; Form_pg_type argTypeStruct;
if (modes && modes[i] == 'o') /* skip OUT arguments */
continue;
Assert(types[i] == procStruct->proargtypes.values[pos]);
argTypeTup = SearchSysCache(TYPEOID, argTypeTup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(procStruct->proargtypes.values[i]), ObjectIdGetDatum(types[i]),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(argTypeTup)) if (!HeapTupleIsValid(argTypeTup))
elog(ERROR, "cache lookup failed for type %u", elog(ERROR, "cache lookup failed for type %u", types[i]);
procStruct->proargtypes.values[i]);
argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup); argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
/* check argument type is OK, set up I/O function info */
switch (argTypeStruct->typtype)
{
case TYPTYPE_PSEUDO:
/* Disallow pseudotype argument */ /* Disallow pseudotype argument */
if (argTypeStruct->typtype == TYPTYPE_PSEUDO)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("plpython functions cannot take type %s", errmsg("plpython functions cannot take type %s",
format_type_be(procStruct->proargtypes.values[i])))); format_type_be(types[i]))));
break;
if (argTypeStruct->typtype != TYPTYPE_COMPOSITE) case TYPTYPE_COMPOSITE:
PLy_input_datum_func(&(proc->args[i]), /* we'll set IO funcs at first call */
procStruct->proargtypes.values[i], proc->args[pos].is_rowtype = 2;
break;
default:
PLy_input_datum_func(&(proc->args[pos]),
types[i],
argTypeTup); argTypeTup);
else break;
proc->args[i].is_rowtype = 2; /* still need to set I/O funcs */ }
/* get argument name */
proc->argnames[pos] = names ? PLy_strdup(names[i]) : NULL;
ReleaseSysCache(argTypeTup); ReleaseSysCache(argTypeTup);
/* Fetch argument name */ pos++;
if (proc->argnames) }
proc->argnames[i] = PLy_strdup(TextDatumGetCString(elems[i]));
} }
/* /*
......
...@@ -480,3 +480,16 @@ elif typ == 'obj': ...@@ -480,3 +480,16 @@ elif typ == 'obj':
return type_record return type_record
$$ LANGUAGE plpythonu; $$ LANGUAGE plpythonu;
CREATE FUNCTION test_in_out_params(first in text, second out text) AS $$
return first + '_in_to_out';
$$ LANGUAGE plpythonu;
-- this doesn't work yet :-(
CREATE FUNCTION test_in_out_params_multi(first in text,
second out text, third out text) AS $$
return first + '_record_in_to_out';
$$ LANGUAGE plpythonu;
CREATE FUNCTION test_inout_params(first inout text) AS $$
return first + '_inout';
$$ LANGUAGE plpythonu;
...@@ -143,3 +143,8 @@ SELECT * FROM test_type_record_as('obj', 'one', null, false); ...@@ -143,3 +143,8 @@ SELECT * FROM test_type_record_as('obj', 'one', null, false);
SELECT * FROM test_type_record_as('obj', null, 2, false); SELECT * FROM test_type_record_as('obj', null, 2, false);
SELECT * FROM test_type_record_as('obj', 'three', 3, false); SELECT * FROM test_type_record_as('obj', 'three', 3, false);
SELECT * FROM test_type_record_as('obj', null, null, true); SELECT * FROM test_type_record_as('obj', null, null, true);
SELECT * FROM test_in_out_params('test_in');
-- this doesn't work yet :-(
SELECT * FROM test_in_out_params_multi('test_in');
SELECT * FROM test_inout_params('test_in');
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment