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':
type_record.second = second
return type_record
$$ 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);
|
(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
*
* $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)
bool isnull;
int i,
rv;
Datum argnames;
Datum *elems;
int nelems;
procStruct = (Form_pg_proc) GETSTRUCT(procTup);
......@@ -1249,58 +1246,83 @@ PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key)
}
/*
* now get information required for input conversion of the
* procedure's arguments.
* Now get information required for input conversion of the
* 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 (proc->nargs)
if (procStruct->pronargs)
{
argnames = SysCacheGetAttr(PROCOID, procTup, Anum_pg_proc_proargnames, &isnull);
if (!isnull)
Oid *types;
char **names,
*modes;
int i,
pos,
total;
/* extract argument type info from the pg_proc tuple */
total = get_func_arg_info(procTup, &types, &names, &modes);
/* count number of in+inout args into proc->nargs */
if (modes == NULL)
proc->nargs = total;
else
{
/* XXX this code is WRONG if there are any output arguments */
deconstruct_array(DatumGetArrayTypeP(argnames), TEXTOID, -1, false, 'i',
&elems, NULL, &nelems);
if (nelems != proc->nargs)
elog(ERROR,
"proargnames must have the same number of elements "
"as the function has arguments");
proc->argnames = (char **) PLy_malloc(sizeof(char *) * proc->nargs);
memset(proc->argnames, 0, sizeof(char *) * proc->nargs);
/* 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++)
{
HeapTuple argTypeTup;
Form_pg_type argTypeStruct;
argTypeTup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(procStruct->proargtypes.values[i]),
0, 0, 0);
if (!HeapTupleIsValid(argTypeTup))
elog(ERROR, "cache lookup failed for type %u",
procStruct->proargtypes.values[i]);
argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
proc->argnames = (char **) PLy_malloc(sizeof(char *) * proc->nargs);
for (i = pos = 0; i < total; i++)
{
HeapTuple argTypeTup;
Form_pg_type argTypeStruct;
/* Disallow pseudotype argument */
if (argTypeStruct->typtype == TYPTYPE_PSEUDO)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("plpython functions cannot take type %s",
format_type_be(procStruct->proargtypes.values[i]))));
if (argTypeStruct->typtype != TYPTYPE_COMPOSITE)
PLy_input_datum_func(&(proc->args[i]),
procStruct->proargtypes.values[i],
argTypeTup);
else
proc->args[i].is_rowtype = 2; /* still need to set I/O funcs */
if (modes && modes[i] == 'o') /* skip OUT arguments */
continue;
Assert(types[i] == procStruct->proargtypes.values[pos]);
argTypeTup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(types[i]),
0, 0, 0);
if (!HeapTupleIsValid(argTypeTup))
elog(ERROR, "cache lookup failed for type %u", types[i]);
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 */
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("plpython functions cannot take type %s",
format_type_be(types[i]))));
break;
case TYPTYPE_COMPOSITE:
/* we'll set IO funcs at first call */
proc->args[pos].is_rowtype = 2;
break;
default:
PLy_input_datum_func(&(proc->args[pos]),
types[i],
argTypeTup);
break;
}
ReleaseSysCache(argTypeTup);
/* get argument name */
proc->argnames[pos] = names ? PLy_strdup(names[i]) : NULL;
/* Fetch argument name */
if (proc->argnames)
proc->argnames[i] = PLy_strdup(TextDatumGetCString(elems[i]));
ReleaseSysCache(argTypeTup);
pos++;
}
}
/*
......
......@@ -480,3 +480,16 @@ elif typ == 'obj':
return type_record
$$ 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);
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', 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