PL/Python

Started by Tom Jenkinsabout 23 years ago4 messagesgeneral
Jump to latest
#1Tom Jenkins
tjenkins@devis.com

Hey all,
In 7.2 we found a bug in PL/Python (i don't know if its still there in 7.3 - i
haven't downloaded the sources yet).

When we create a function like so:

CREATE OR REPLACE FUNCTION jojo (timestamp) RETURNS varchar AS '
pln = plpy.prepare("UPDATE jtab SET jfld = $1",["timestamp"])
rcs = plpy.execute(pln,[args[0]])
return "YES"' LANGUAGE 'PLPYTHON';

SELECT jojo(now());
works fine but

SELECT jojo(NULL);
errors out with
NOTICE: plpython: in function __plpython_procedure_jojo_49818349:
plpy.Error: Unknown error in PLy_spi_execute_plan
ERROR: Bad timestamp external representation 'None'

in plpython.c the function PLy_spi_execute_plan has the following snippet:
elem = PySequence_GetItem(list, i);
so = PyObject_Str(elem);
sv = PyString_AsString(so);
/*
* FIXME -- if this can elog, we have leak
*/
plan->values[i] = FunctionCall3(&(plan->args[i].out.d.typfunc),
CStringGetDatum(sv),
ObjectIdGetDatum(plan->args[i].out.d.typelem),
Int32GetDatum(-1));

this looks to me that the None object is getting converted into 'None'
(through PyString_AsString call).

I tried a quick fix but it crashes the backend:
elem = PySequence_GetItem(list, i);
if ( elem != Py_None )
{
so = PyObject_Str(elem);
sv = PyString_AsString(so);
/*
* FIXME -- if this can elog, we have leak
*/
plan->values[i] = FunctionCall3(&(plan->args[i].out.d.typfunc),
CStringGetDatum(sv),
ObjectIdGetDatum(plan->args[i].out.d.typelem),
Int32GetDatum(-1));

Py_DECREF(so);
}
else
{
plan->values[i] = FunctionCall3(&(plan->args[i].out.d.typfunc),
PointerGetDatum(NULL),
ObjectIdGetDatum(plan->args[i].out.d.typelem),
Int32GetDatum(-1));
}

Py_DECREF(elem);

I believe the logic is correct (if the python object is None then send to the
typfunc a NULL) but I don't know how to code it correctly.

Thanks for any help,

Tom

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Jenkins (#1)
Re: PL/Python

Tom Jenkins <tjenkins@devis.com> writes:

I believe the logic is correct (if the python object is None then send
to the typfunc a NULL) but I don't know how to code it correctly.

You shouldn't call the typfunc at all if you want a NULL --- just set
the null flag for that datum slot.

regards, tom lane

#3Tom Jenkins
tjenkins@devis.com
In reply to: Tom Lane (#2)
Re: PL/Python

On Tuesday 21 January 2003 12:49 pm, Tom Lane wrote:

Tom Jenkins <tjenkins@devis.com> writes:

I believe the logic is correct (if the python object is None then send
to the typfunc a NULL) but I don't know how to code it correctly.

You shouldn't call the typfunc at all if you want a NULL --- just set
the null flag for that datum slot.

regards, tom lane

please pardon me if this is really obvious, but i can't seem to find a null
flag in the structures i have in that function. I don't get how to set the
null flag for the datum slot. I'm still learning how to work with the
backend code.

any help is appreciated,

Tom

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Jenkins (#3)
Re: PL/Python

Tom Jenkins <tjenkins@devis.com> writes:

please pardon me if this is really obvious, but i can't seem to find a null
flag in the structures i have in that function. I don't get how to set the
null flag for the datum slot. I'm still learning how to work with the
backend code.

It looks like whoever wrote the plpython code was still learning, too.
Parts of it handle NULLs correctly, but PLy_spi_execute_plan doesn't
seem to cope at all. It looks like you ought to add a nulls flag array
to PLyPlanObject, fill it during PLy_spi_execute_plan, and pass it to
SPI_execp. IIRC it's a char array, containing 'n' for a null arg and
' ' for not-null, but check SPI_execp to be sure.

Also, the code that explicitly pfree's the typfunc's results here is a
waste of space, if not actively dangerous...

regards, tom lane