aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/plpython.sgml9
-rw-r--r--src/pl/plpython/expected/plpython_spi.out11
-rw-r--r--src/pl/plpython/plpy_resultobject.c54
-rw-r--r--src/pl/plpython/plpy_resultobject.h4
-rw-r--r--src/pl/plpython/plpy_spi.c2
-rw-r--r--src/pl/plpython/sql/plpython_spi.sql5
6 files changed, 80 insertions, 5 deletions
diff --git a/doc/src/sgml/plpython.sgml b/doc/src/sgml/plpython.sgml
index 5a3c8caa689..237c881a5c1 100644
--- a/doc/src/sgml/plpython.sgml
+++ b/doc/src/sgml/plpython.sgml
@@ -886,9 +886,12 @@ $$ LANGUAGE plpythonu;
list or dictionary object. The result object can be accessed by
row number and column name. It has these additional methods:
<function>nrows</function> which returns the number of rows
- returned by the query, and <function>status</function> which is the
- <function>SPI_execute()</function> return value. The result object
- can be modified.
+ returned by the query, <function>status</function> which is the
+ <function>SPI_execute()</function> return value,
+ <function>colnames</function> which is the list of column names,
+ <function>coltypes</function> which is the list of column type OIDs,
+ and <function>coltypmods</function> which is the list of type-specific type
+ modifiers for the columns. The result object can be modified.
</para>
<para>
diff --git a/src/pl/plpython/expected/plpython_spi.out b/src/pl/plpython/expected/plpython_spi.out
index 3b4d7a30105..9ed081b184b 100644
--- a/src/pl/plpython/expected/plpython_spi.out
+++ b/src/pl/plpython/expected/plpython_spi.out
@@ -117,10 +117,13 @@ SELECT join_sequences(sequences) FROM sequences
--
CREATE FUNCTION result_nrows_test() RETURNS int
AS $$
-plan = plpy.prepare("SELECT 1 UNION SELECT 2")
+plan = plpy.prepare("SELECT 1 AS foo, '11'::text AS bar UNION SELECT 2, '22'")
plpy.info(plan.status()) # not really documented or useful
result = plpy.execute(plan)
if result.status() > 0:
+ plpy.info(result.colnames())
+ plpy.info(result.coltypes())
+ plpy.info(result.coltypmods())
return result.nrows()
else:
return None
@@ -128,6 +131,12 @@ $$ LANGUAGE plpythonu;
SELECT result_nrows_test();
INFO: True
CONTEXT: PL/Python function "result_nrows_test"
+INFO: ['foo', 'bar']
+CONTEXT: PL/Python function "result_nrows_test"
+INFO: [23, 25]
+CONTEXT: PL/Python function "result_nrows_test"
+INFO: [-1, -1]
+CONTEXT: PL/Python function "result_nrows_test"
result_nrows_test
-------------------
2
diff --git a/src/pl/plpython/plpy_resultobject.c b/src/pl/plpython/plpy_resultobject.c
index bf46a165959..b25e8083b9e 100644
--- a/src/pl/plpython/plpy_resultobject.c
+++ b/src/pl/plpython/plpy_resultobject.c
@@ -12,6 +12,9 @@
static void PLy_result_dealloc(PyObject *arg);
+static PyObject *PLy_result_colnames(PyObject *self, PyObject *unused);
+static PyObject *PLy_result_coltypes(PyObject *self, PyObject *unused);
+static PyObject *PLy_result_coltypmods(PyObject *self, PyObject *unused);
static PyObject *PLy_result_nrows(PyObject *self, PyObject *args);
static PyObject *PLy_result_status(PyObject *self, PyObject *args);
static Py_ssize_t PLy_result_length(PyObject *arg);
@@ -35,6 +38,9 @@ static PySequenceMethods PLy_result_as_sequence = {
};
static PyMethodDef PLy_result_methods[] = {
+ {"colnames", PLy_result_colnames, METH_NOARGS, NULL},
+ {"coltypes", PLy_result_coltypes, METH_NOARGS, NULL},
+ {"coltypmods", PLy_result_coltypmods, METH_NOARGS, NULL},
{"nrows", PLy_result_nrows, METH_VARARGS, NULL},
{"status", PLy_result_status, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
@@ -96,6 +102,7 @@ PLy_result_new(void)
ob->status = Py_None;
ob->nrows = PyInt_FromLong(-1);
ob->rows = PyList_New(0);
+ ob->tupdesc = NULL;
return (PyObject *) ob;
}
@@ -108,11 +115,58 @@ PLy_result_dealloc(PyObject *arg)
Py_XDECREF(ob->nrows);
Py_XDECREF(ob->rows);
Py_XDECREF(ob->status);
+ if (ob->tupdesc)
+ {
+ FreeTupleDesc(ob->tupdesc);
+ ob->tupdesc = NULL;
+ }
arg->ob_type->tp_free(arg);
}
static PyObject *
+PLy_result_colnames(PyObject *self, PyObject *unused)
+{
+ PLyResultObject *ob = (PLyResultObject *) self;
+ PyObject *list;
+ int i;
+
+ list = PyList_New(ob->tupdesc->natts);
+ for (i = 0; i < ob->tupdesc->natts; i++)
+ PyList_SET_ITEM(list, i, PyString_FromString(NameStr(ob->tupdesc->attrs[i]->attname)));
+
+ return list;
+}
+
+static PyObject *
+PLy_result_coltypes(PyObject *self, PyObject *unused)
+{
+ PLyResultObject *ob = (PLyResultObject *) self;
+ PyObject *list;
+ int i;
+
+ list = PyList_New(ob->tupdesc->natts);
+ for (i = 0; i < ob->tupdesc->natts; i++)
+ PyList_SET_ITEM(list, i, PyInt_FromLong(ob->tupdesc->attrs[i]->atttypid));
+
+ return list;
+}
+
+static PyObject *
+PLy_result_coltypmods(PyObject *self, PyObject *unused)
+{
+ PLyResultObject *ob = (PLyResultObject *) self;
+ PyObject *list;
+ int i;
+
+ list = PyList_New(ob->tupdesc->natts);
+ for (i = 0; i < ob->tupdesc->natts; i++)
+ PyList_SET_ITEM(list, i, PyInt_FromLong(ob->tupdesc->attrs[i]->atttypmod));
+
+ return list;
+}
+
+static PyObject *
PLy_result_nrows(PyObject *self, PyObject *args)
{
PLyResultObject *ob = (PLyResultObject *) self;
diff --git a/src/pl/plpython/plpy_resultobject.h b/src/pl/plpython/plpy_resultobject.h
index 719828a3efb..1b37d1d0c0c 100644
--- a/src/pl/plpython/plpy_resultobject.h
+++ b/src/pl/plpython/plpy_resultobject.h
@@ -5,6 +5,9 @@
#ifndef PLPY_RESULTOBJECT_H
#define PLPY_RESULTOBJECT_H
+#include "access/tupdesc.h"
+
+
typedef struct PLyResultObject
{
PyObject_HEAD
@@ -12,6 +15,7 @@ typedef struct PLyResultObject
PyObject *nrows; /* number of rows returned by query */
PyObject *rows; /* data rows, or None if no data returned */
PyObject *status; /* query status, SPI_OK_*, or SPI_ERR_* */
+ TupleDesc tupdesc;
} PLyResultObject;
extern void PLy_result_init_type(void);
diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c
index 3afb1093d57..0d63c4f5ce8 100644
--- a/src/pl/plpython/plpy_spi.c
+++ b/src/pl/plpython/plpy_spi.c
@@ -398,6 +398,8 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
oldcontext = CurrentMemoryContext;
PG_TRY();
{
+ result->tupdesc = CreateTupleDescCopy(tuptable->tupdesc);
+
if (rows)
{
Py_DECREF(result->rows);
diff --git a/src/pl/plpython/sql/plpython_spi.sql b/src/pl/plpython/sql/plpython_spi.sql
index 874b31e6df6..b828744d1f8 100644
--- a/src/pl/plpython/sql/plpython_spi.sql
+++ b/src/pl/plpython/sql/plpython_spi.sql
@@ -95,10 +95,13 @@ SELECT join_sequences(sequences) FROM sequences
CREATE FUNCTION result_nrows_test() RETURNS int
AS $$
-plan = plpy.prepare("SELECT 1 UNION SELECT 2")
+plan = plpy.prepare("SELECT 1 AS foo, '11'::text AS bar UNION SELECT 2, '22'")
plpy.info(plan.status()) # not really documented or useful
result = plpy.execute(plan)
if result.status() > 0:
+ plpy.info(result.colnames())
+ plpy.info(result.coltypes())
+ plpy.info(result.coltypmods())
return result.nrows()
else:
return None