From dfdae5d63cd0c7eb75fb419c61a5fd62c7e4b326 Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Fri, 17 Dec 2004 02:14:48 +0000 Subject: [PATCH] Hook up the plpython result-object nrows and status methods correctly. Adjust documentation to match current reality. --- doc/src/sgml/plpython.sgml | 55 ++++++++++++++++---------------------- src/pl/plpython/plpython.c | 30 +++++---------------- 2 files changed, 29 insertions(+), 56 deletions(-) diff --git a/doc/src/sgml/plpython.sgml b/doc/src/sgml/plpython.sgml index 6655219d3e6..a3d64bd353e 100644 --- a/doc/src/sgml/plpython.sgml +++ b/doc/src/sgml/plpython.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/plpython.sgml,v 1.24 2004/09/13 20:05:18 tgl Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/plpython.sgml,v 1.25 2004/12/17 02:14:44 tgl Exp $ --> <chapter id="plpython"> <title>PL/Python - Python Procedural Language</title> @@ -46,7 +46,8 @@ <title>PL/Python Functions</title> <para> - The Python code you write gets transformed into a Python function. E.g., + The Python code you write gets transformed into a Python function. + For example, <programlisting> CREATE FUNCTION myfunc(text) RETURNS text AS 'return args[0]' @@ -60,13 +61,14 @@ def __plpython_procedure_myfunc_23456(): return args[0] </programlisting> - assuming that 23456 is the OID of the function. + assuming that 23456 is the OID assigned to the function by + <productname>PostgreSQL</productname>. </para> <para> If you do not provide a return value, Python returns the default - <symbol>None</symbol>. The language module translates Python's - <symbol>None</symbol> into the SQL null + <symbol>None</symbol>. <application>PL/Python</application> translates + Python's <symbol>None</symbol> into the SQL null value.<indexterm><primary>null value</><secondary sortas="PL/Python">in PL/Python</></indexterm> </para> @@ -108,7 +110,7 @@ def __plpython_procedure_myfunc_23456(): </indexterm> <para> - When a function is used in a trigger, the dictionary + When a function is used as a trigger, the dictionary <literal>TD</literal> contains trigger-related values. The trigger rows are in <literal>TD["new"]</> and/or <literal>TD["old"]</> depending on the trigger event. <literal>TD["event"]</> contains @@ -120,9 +122,9 @@ def __plpython_procedure_myfunc_23456(): <literal>STATEMENT</>, and <literal>UNKNOWN</>. <literal>TD["name"]</> contains the trigger name, and <literal>TD["relid"]</> contains the OID of the table on - which the trigger occurred. If the trigger was called with - arguments they are available in <literal>TD["args"][0]</> to - <literal>TD["args"][(n-1)]</>. + which the trigger occurred. If the <command>CREATE TRIGGER</> command + included arguments, they are available in <literal>TD["args"][0]</> to + <literal>TD["args"][(<replaceable>n</>-1)]</>. </para> <para> @@ -143,23 +145,23 @@ def __plpython_procedure_myfunc_23456(): this module are available to you in the Python code as <literal>plpy.<replaceable>foo</replaceable></literal>. At present <literal>plpy</literal> implements the functions - <literal>plpy.debug("msg")</literal>, - <literal>plpy.log("msg")</literal>, - <literal>plpy.info("msg")</literal>, - <literal>plpy.notice("msg")</literal>, - <literal>plpy.warning("msg")</literal>, - <literal>plpy.error("msg")</literal>, and - <literal>plpy.fatal("msg")</literal>. They are mostly equivalent - to calling <literal>elog(<replaceable>LEVEL</>, "msg")</literal> + <literal>plpy.debug(<replaceable>msg</>)</literal>, + <literal>plpy.log(<replaceable>msg</>)</literal>, + <literal>plpy.info(<replaceable>msg</>)</literal>, + <literal>plpy.notice(<replaceable>msg</>)</literal>, + <literal>plpy.warning(<replaceable>msg</>)</literal>, + <literal>plpy.error(<replaceable>msg</>)</literal>, and + <literal>plpy.fatal(<replaceable>msg</>)</literal>. + These are mostly equivalent to calling + <literal>elog(<replaceable>level</>, <replaceable>msg</>)</literal> from C code.<indexterm><primary>elog</><secondary>in PL/Python</></indexterm> <function>plpy.error</function> and <function>plpy.fatal</function> actually raise a Python exception which, if uncaught, causes the PL/Python module to call <literal>elog(ERROR, msg)</literal> when the function handler - returns from the Python interpreter. Long-jumping out of the - Python interpreter is probably not good. <literal>raise - plpy.ERROR("msg")</literal> and <literal>raise - plpy.FATAL("msg")</literal> are equivalent to calling + returns from the Python interpreter. <literal>raise + plpy.ERROR(<replaceable>msg</>)</literal> and <literal>raise + plpy.FATAL(<replaceable>msg</>)</literal> are equivalent to calling <function>plpy.error</function> and <function>plpy.fatal</function>, respectively. </para> @@ -210,17 +212,6 @@ rv = plpy.execute(plan, [ "name" ], 5) The third argument is the limit and is optional. </para> - <para> - In the current version, any database error encountered while - running a <application>PL/Python</application> function will result - in the immediate termination of that function by the server; it is - not possible to trap error conditions using Python <literal>try - ... catch</literal> constructs. For example, a syntax error in an - SQL statement passed to the <literal>plpy.execute</literal> call - will terminate the function. This behavior may be changed in a - future release. - </para> - <para> When you prepare a plan using the PL/Python module it is automatically saved. Read the SPI documentation (<xref diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c index 5826ad48c62..5f5b36b0a50 100644 --- a/src/pl/plpython/plpython.c +++ b/src/pl/plpython/plpython.c @@ -29,7 +29,7 @@ * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.57 2004/09/19 23:38:21 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.58 2004/12/17 02:14:48 tgl Exp $ * ********************************************************************* */ @@ -1531,13 +1531,8 @@ static PyObject *PLy_plan_status(PyObject *, PyObject *); static PyObject *PLy_result_new(void); static void PLy_result_dealloc(PyObject *); static PyObject *PLy_result_getattr(PyObject *, char *); - -#ifdef NOT_USED -/* Appear to be unused */ -static PyObject *PLy_result_fetch(PyObject *, PyObject *); static PyObject *PLy_result_nrows(PyObject *, PyObject *); static PyObject *PLy_result_status(PyObject *, PyObject *); -#endif static int PLy_result_length(PyObject *); static PyObject *PLy_result_item(PyObject *, int); static PyObject *PLy_result_slice(PyObject *, int, int); @@ -1582,7 +1577,7 @@ static PyTypeObject PLy_PlanType = { }; static PyMethodDef PLy_plan_methods[] = { - {"status", (PyCFunction) PLy_plan_status, METH_VARARGS, NULL}, + {"status", PLy_plan_status, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} }; @@ -1626,15 +1621,11 @@ static PyTypeObject PLy_ResultType = { PLy_result_doc, /* tp_doc */ }; -#ifdef NOT_USED -/* Appear to be unused */ static PyMethodDef PLy_result_methods[] = { - {"fetch", (PyCFunction) PLy_result_fetch, METH_VARARGS, NULL,}, - {"nrows", (PyCFunction) PLy_result_nrows, METH_VARARGS, NULL}, - {"status", (PyCFunction) PLy_result_status, METH_VARARGS, NULL}, + {"nrows", PLy_result_nrows, METH_VARARGS, NULL}, + {"status", PLy_result_status, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} }; -#endif static PyMethodDef PLy_methods[] = { /* @@ -1758,17 +1749,9 @@ PLy_result_dealloc(PyObject * arg) } static PyObject * -PLy_result_getattr(PyObject * self, char *attr) +PLy_result_getattr(PyObject * self, char *name) { - return NULL; -} - -#ifdef NOT_USED -/* Appear to be unused */ -static PyObject * -PLy_result_fetch(PyObject * self, PyObject * args) -{ - return NULL; + return Py_FindMethod(PLy_result_methods, self, name); } static PyObject * @@ -1788,7 +1771,6 @@ PLy_result_status(PyObject * self, PyObject * args) Py_INCREF(ob->status); return ob->status; } -#endif static int PLy_result_length(PyObject * arg) -- GitLab