Use generic attribute management in PL/Python
authorPeter Eisentraut <peter_e@gmx.net>
Tue, 25 Aug 2009 08:14:42 +0000 (08:14 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Tue, 25 Aug 2009 08:14:42 +0000 (08:14 +0000)
Switch the implementation of the plan and result types to generic attribute
management, as described at <http://docs.python.org/extending/newtypes.html>.
This modernizes and simplifies the code a bit and prepares for Python 3.1,
where the old way doesn't work anymore.

src/pl/plpython/expected/plpython_spi.out
src/pl/plpython/plpython.c
src/pl/plpython/sql/plpython_spi.sql

index 9cef3f2bb0b43a33c3d34412b9d939c449fbc51f..9097262a48dc9c64c8c85fe31b4f250f97f200ab 100644 (file)
@@ -111,3 +111,24 @@ SELECT join_sequences(sequences) FROM sequences
 ----------------
 (0 rows)
 
+--
+-- plan and result objects
+--
+CREATE FUNCTION result_nrows_test() RETURNS int
+AS $$
+plan = plpy.prepare("SELECT 1 UNION SELECT 2")
+plpy.info(plan.status()) # not really documented or useful
+result = plpy.execute(plan)
+if result.status() > 0:
+   return result.nrows()
+else:
+   return None
+$$ LANGUAGE plpythonu;
+SELECT result_nrows_test();
+INFO:  (True,)
+CONTEXT:  PL/Python function "result_nrows_test"
+ result_nrows_test 
+-------------------
+                 2
+(1 row)
+
index ee94b637fe7cdd343d957e0b9cf0bebfabed405b..eec0288e493fcdc0cf4a593e84643eaf289ca064 100644 (file)
@@ -1,7 +1,7 @@
 /**********************************************************************
  * plpython.c - python as a procedural language for PostgreSQL
  *
- * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.125 2009/08/14 13:12:21 petere Exp $
+ * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.126 2009/08/25 08:14:42 petere Exp $
  *
  *********************************************************************
  */
@@ -2050,12 +2050,10 @@ static PyObject *PLy_fatal(PyObject *, PyObject *);
 #define is_PLyPlanObject(x) ((x)->ob_type == &PLy_PlanType)
 static PyObject *PLy_plan_new(void);
 static void PLy_plan_dealloc(PyObject *);
-static PyObject *PLy_plan_getattr(PyObject *, char *);
 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 *);
 static PyObject *PLy_result_nrows(PyObject *, PyObject *);
 static PyObject *PLy_result_status(PyObject *, PyObject *);
 static Py_ssize_t PLy_result_length(PyObject *);
@@ -2072,6 +2070,11 @@ static PyObject *PLy_spi_execute_plan(PyObject *, PyObject *, long);
 static PyObject *PLy_spi_execute_fetch_result(SPITupleTable *, int, int);
 
 
+static PyMethodDef PLy_plan_methods[] = {
+   {"status", PLy_plan_status, METH_VARARGS, NULL},
+   {NULL, NULL, 0, NULL}
+};
+
 static PyTypeObject PLy_PlanType = {
    PyObject_HEAD_INIT(NULL)
    0,                          /* ob_size */
@@ -2084,7 +2087,7 @@ static PyTypeObject PLy_PlanType = {
     */
    PLy_plan_dealloc,           /* tp_dealloc */
    0,                          /* tp_print */
-   PLy_plan_getattr,           /* tp_getattr */
+   0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    0,                          /* tp_repr */
@@ -2099,11 +2102,13 @@ static PyTypeObject PLy_PlanType = {
    0,                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags */
    PLy_plan_doc,               /* tp_doc */
-};
-
-static PyMethodDef PLy_plan_methods[] = {
-   {"status", PLy_plan_status, METH_VARARGS, NULL},
-   {NULL, NULL, 0, NULL}
+   0,                          /* tp_traverse */
+   0,                          /* tp_clear */
+   0,                          /* tp_richcompare */
+   0,                          /* tp_weaklistoffset */
+   0,                          /* tp_iter */
+   0,                          /* tp_iternext */
+   PLy_plan_methods,           /* tp_tpmethods */
 };
 
 static PySequenceMethods PLy_result_as_sequence = {
@@ -2116,6 +2121,12 @@ static PySequenceMethods PLy_result_as_sequence = {
    PLy_result_ass_slice,       /* sq_ass_slice */
 };
 
+static PyMethodDef PLy_result_methods[] = {
+   {"nrows", PLy_result_nrows, METH_VARARGS, NULL},
+   {"status", PLy_result_status, METH_VARARGS, NULL},
+   {NULL, NULL, 0, NULL}
+};
+
 static PyTypeObject PLy_ResultType = {
    PyObject_HEAD_INIT(NULL)
    0,                          /* ob_size */
@@ -2128,7 +2139,7 @@ static PyTypeObject PLy_ResultType = {
     */
    PLy_result_dealloc,         /* tp_dealloc */
    0,                          /* tp_print */
-   PLy_result_getattr,         /* tp_getattr */
+   0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    0,                          /* tp_repr */
@@ -2143,12 +2154,13 @@ static PyTypeObject PLy_ResultType = {
    0,                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags */
    PLy_result_doc,             /* tp_doc */
-};
-
-static PyMethodDef PLy_result_methods[] = {
-   {"nrows", PLy_result_nrows, METH_VARARGS, NULL},
-   {"status", PLy_result_status, METH_VARARGS, NULL},
-   {NULL, NULL, 0, NULL}
+   0,                          /* tp_traverse */
+   0,                          /* tp_clear */
+   0,                          /* tp_richcompare */
+   0,                          /* tp_weaklistoffset */
+   0,                          /* tp_iter */
+   0,                          /* tp_iternext */
+   PLy_result_methods,         /* tp_tpmethods */
 };
 
 static PyMethodDef PLy_methods[] = {
@@ -2217,12 +2229,6 @@ PLy_plan_dealloc(PyObject *arg)
 }
 
 
-static PyObject *
-PLy_plan_getattr(PyObject *self, char *name)
-{
-   return Py_FindMethod(PLy_plan_methods, self, name);
-}
-
 static PyObject *
 PLy_plan_status(PyObject *self, PyObject *args)
 {
@@ -2270,12 +2276,6 @@ PLy_result_dealloc(PyObject *arg)
    arg->ob_type->tp_free(arg);
 }
 
-static PyObject *
-PLy_result_getattr(PyObject *self, char *name)
-{
-   return Py_FindMethod(PLy_result_methods, self, name);
-}
-
 static PyObject *
 PLy_result_nrows(PyObject *self, PyObject *args)
 {
index 2157569f4c78854aec3c7a0fce47d6ab75de30d8..b607cdb939730bbf03149aace7e869be921d4fad 100644 (file)
@@ -87,3 +87,21 @@ SELECT join_sequences(sequences) FROM sequences
    WHERE join_sequences(sequences) ~* '^A';
 SELECT join_sequences(sequences) FROM sequences
    WHERE join_sequences(sequences) ~* '^B';
+
+
+--
+-- plan and result objects
+--
+
+CREATE FUNCTION result_nrows_test() RETURNS int
+AS $$
+plan = plpy.prepare("SELECT 1 UNION SELECT 2")
+plpy.info(plan.status()) # not really documented or useful
+result = plpy.execute(plan)
+if result.status() > 0:
+   return result.nrows()
+else:
+   return None
+$$ LANGUAGE plpythonu;
+
+SELECT result_nrows_test();