PL/Python: Add result metadata functions
Add result object functions .colnames, .coltypes, .coltypmods to obtain information about the result column names and types, which was previously not possible in the PL/Python SPI interface. reviewed by Abhijit Menon-Sen
This commit is contained in:
parent
c6ea8ccea6
commit
ee7fa66b19
@ -886,9 +886,12 @@ $$ LANGUAGE plpythonu;
|
|||||||
list or dictionary object. The result object can be accessed by
|
list or dictionary object. The result object can be accessed by
|
||||||
row number and column name. It has these additional methods:
|
row number and column name. It has these additional methods:
|
||||||
<function>nrows</function> which returns the number of rows
|
<function>nrows</function> which returns the number of rows
|
||||||
returned by the query, and <function>status</function> which is the
|
returned by the query, <function>status</function> which is the
|
||||||
<function>SPI_execute()</function> return value. The result object
|
<function>SPI_execute()</function> return value,
|
||||||
can be modified.
|
<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>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -117,16 +117,25 @@ SELECT join_sequences(sequences) FROM sequences
|
|||||||
--
|
--
|
||||||
CREATE FUNCTION result_nrows_test() RETURNS int
|
CREATE FUNCTION result_nrows_test() RETURNS int
|
||||||
AS $$
|
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
|
plpy.info(plan.status()) # not really documented or useful
|
||||||
result = plpy.execute(plan)
|
result = plpy.execute(plan)
|
||||||
if result.status() > 0:
|
if result.status() > 0:
|
||||||
|
plpy.info(result.colnames())
|
||||||
|
plpy.info(result.coltypes())
|
||||||
|
plpy.info(result.coltypmods())
|
||||||
return result.nrows()
|
return result.nrows()
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
$$ LANGUAGE plpythonu;
|
$$ LANGUAGE plpythonu;
|
||||||
SELECT result_nrows_test();
|
SELECT result_nrows_test();
|
||||||
INFO: True
|
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"
|
CONTEXT: PL/Python function "result_nrows_test"
|
||||||
result_nrows_test
|
result_nrows_test
|
||||||
-------------------
|
-------------------
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
|
|
||||||
|
|
||||||
static void PLy_result_dealloc(PyObject *arg);
|
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_nrows(PyObject *self, PyObject *args);
|
||||||
static PyObject *PLy_result_status(PyObject *self, PyObject *args);
|
static PyObject *PLy_result_status(PyObject *self, PyObject *args);
|
||||||
static Py_ssize_t PLy_result_length(PyObject *arg);
|
static Py_ssize_t PLy_result_length(PyObject *arg);
|
||||||
@ -35,6 +38,9 @@ static PySequenceMethods PLy_result_as_sequence = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static PyMethodDef PLy_result_methods[] = {
|
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},
|
{"nrows", PLy_result_nrows, METH_VARARGS, NULL},
|
||||||
{"status", PLy_result_status, METH_VARARGS, NULL},
|
{"status", PLy_result_status, METH_VARARGS, NULL},
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
@ -96,6 +102,7 @@ PLy_result_new(void)
|
|||||||
ob->status = Py_None;
|
ob->status = Py_None;
|
||||||
ob->nrows = PyInt_FromLong(-1);
|
ob->nrows = PyInt_FromLong(-1);
|
||||||
ob->rows = PyList_New(0);
|
ob->rows = PyList_New(0);
|
||||||
|
ob->tupdesc = NULL;
|
||||||
|
|
||||||
return (PyObject *) ob;
|
return (PyObject *) ob;
|
||||||
}
|
}
|
||||||
@ -108,10 +115,57 @@ PLy_result_dealloc(PyObject *arg)
|
|||||||
Py_XDECREF(ob->nrows);
|
Py_XDECREF(ob->nrows);
|
||||||
Py_XDECREF(ob->rows);
|
Py_XDECREF(ob->rows);
|
||||||
Py_XDECREF(ob->status);
|
Py_XDECREF(ob->status);
|
||||||
|
if (ob->tupdesc)
|
||||||
|
{
|
||||||
|
FreeTupleDesc(ob->tupdesc);
|
||||||
|
ob->tupdesc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
arg->ob_type->tp_free(arg);
|
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 *
|
static PyObject *
|
||||||
PLy_result_nrows(PyObject *self, PyObject *args)
|
PLy_result_nrows(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
#ifndef PLPY_RESULTOBJECT_H
|
#ifndef PLPY_RESULTOBJECT_H
|
||||||
#define PLPY_RESULTOBJECT_H
|
#define PLPY_RESULTOBJECT_H
|
||||||
|
|
||||||
|
#include "access/tupdesc.h"
|
||||||
|
|
||||||
|
|
||||||
typedef struct PLyResultObject
|
typedef struct PLyResultObject
|
||||||
{
|
{
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
@ -12,6 +15,7 @@ typedef struct PLyResultObject
|
|||||||
PyObject *nrows; /* number of rows returned by query */
|
PyObject *nrows; /* number of rows returned by query */
|
||||||
PyObject *rows; /* data rows, or None if no data returned */
|
PyObject *rows; /* data rows, or None if no data returned */
|
||||||
PyObject *status; /* query status, SPI_OK_*, or SPI_ERR_* */
|
PyObject *status; /* query status, SPI_OK_*, or SPI_ERR_* */
|
||||||
|
TupleDesc tupdesc;
|
||||||
} PLyResultObject;
|
} PLyResultObject;
|
||||||
|
|
||||||
extern void PLy_result_init_type(void);
|
extern void PLy_result_init_type(void);
|
||||||
|
@ -398,6 +398,8 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
|
|||||||
oldcontext = CurrentMemoryContext;
|
oldcontext = CurrentMemoryContext;
|
||||||
PG_TRY();
|
PG_TRY();
|
||||||
{
|
{
|
||||||
|
result->tupdesc = CreateTupleDescCopy(tuptable->tupdesc);
|
||||||
|
|
||||||
if (rows)
|
if (rows)
|
||||||
{
|
{
|
||||||
Py_DECREF(result->rows);
|
Py_DECREF(result->rows);
|
||||||
|
@ -95,10 +95,13 @@ SELECT join_sequences(sequences) FROM sequences
|
|||||||
|
|
||||||
CREATE FUNCTION result_nrows_test() RETURNS int
|
CREATE FUNCTION result_nrows_test() RETURNS int
|
||||||
AS $$
|
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
|
plpy.info(plan.status()) # not really documented or useful
|
||||||
result = plpy.execute(plan)
|
result = plpy.execute(plan)
|
||||||
if result.status() > 0:
|
if result.status() > 0:
|
||||||
|
plpy.info(result.colnames())
|
||||||
|
plpy.info(result.coltypes())
|
||||||
|
plpy.info(result.coltypmods())
|
||||||
return result.nrows()
|
return result.nrows()
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
Loading…
x
Reference in New Issue
Block a user