Fix plpython to not get totally confused by OUT arguments. (It still doesn't
support multiple OUT arguments, though.) Hannu Krosing
This commit is contained in:
parent
d61eecb5a1
commit
bdc7dd6799
@ -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);
|
|||||||
|
|
|
|
||||||
(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)
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* 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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
argnames = SysCacheGetAttr(PROCOID, procTup, Anum_pg_proc_proargnames, &isnull);
|
Oid *types;
|
||||||
if (!isnull)
|
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 */
|
/* proc->nargs was initialized to 0 above */
|
||||||
deconstruct_array(DatumGetArrayTypeP(argnames), TEXTOID, -1, false, 'i',
|
for (i = 0; i < total; i++)
|
||||||
&elems, NULL, &nelems);
|
{
|
||||||
if (nelems != proc->nargs)
|
if (modes[i] != 'o')
|
||||||
elog(ERROR,
|
(proc->nargs)++;
|
||||||
"proargnames must have the same number of elements "
|
}
|
||||||
"as the function has arguments");
|
}
|
||||||
|
|
||||||
proc->argnames = (char **) PLy_malloc(sizeof(char *) * proc->nargs);
|
proc->argnames = (char **) PLy_malloc(sizeof(char *) * proc->nargs);
|
||||||
memset(proc->argnames, 0, sizeof(char *) * proc->nargs);
|
for (i = pos = 0; i < total; i++)
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i = 0; i < proc->nargs; 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':
|
|||||||
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);
|
|||||||
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');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user