Обсуждение: PL/Python
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
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
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
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