#include "postgres.h"#include "access/xact.h"#include "mb/pg_wchar.h"#include "plpython.h"#include "plpy_cursorobject.h"#include "plpy_elog.h"#include "plpy_main.h"#include "plpy_planobject.h"#include "plpy_procedure.h"#include "plpy_resultobject.h"#include "plpy_spi.h"
Go to the source code of this file.
Functions | |
| static PyObject * | PLy_cursor_query (const char *query) |
| static PyObject * | PLy_cursor_plan (PyObject *ob, PyObject *args) |
| static void | PLy_cursor_dealloc (PyObject *arg) |
| static PyObject * | PLy_cursor_iternext (PyObject *self) |
| static PyObject * | PLy_cursor_fetch (PyObject *self, PyObject *args) |
| static PyObject * | PLy_cursor_close (PyObject *self, PyObject *unused) |
| void | PLy_cursor_init_type (void) |
| PyObject * | PLy_cursor (PyObject *self, PyObject *args) |
Variables | |
| static char | PLy_cursor_doc [] |
| static PyMethodDef | PLy_cursor_methods [] |
| static PyTypeObject | PLy_CursorType |
| PyObject* PLy_cursor | ( | PyObject * | self, | |
| PyObject * | args | |||
| ) |
Definition at line 84 of file plpy_cursorobject.c.
References PLy_cursor_plan(), PLy_cursor_query(), PLy_exc_error, and PLy_exception_set().
{
char *query;
PyObject *plan;
PyObject *planargs = NULL;
if (PyArg_ParseTuple(args, "s", &query))
return PLy_cursor_query(query);
PyErr_Clear();
if (PyArg_ParseTuple(args, "O|O", &plan, &planargs))
return PLy_cursor_plan(plan, planargs);
PLy_exception_set(PLy_exc_error, "plpy.cursor expected a query or a plan");
return NULL;
}
| static PyObject * PLy_cursor_close | ( | PyObject * | self, | |
| PyObject * | unused | |||
| ) | [static] |
Definition at line 475 of file plpy_cursorobject.c.
References PLyCursorObject::closed, GetPortalByName(), PLy_exception_set(), PortalIsValid, PLyCursorObject::portalname, and SPI_cursor_close().
{
PLyCursorObject *cursor = (PLyCursorObject *) self;
if (!cursor->closed)
{
Portal portal = GetPortalByName(cursor->portalname);
if (!PortalIsValid(portal))
{
PLy_exception_set(PyExc_ValueError,
"closing a cursor in an aborted subtransaction");
return NULL;
}
SPI_cursor_close(portal);
cursor->closed = true;
}
Py_INCREF(Py_None);
return Py_None;
}
| static void PLy_cursor_dealloc | ( | PyObject * | arg | ) | [static] |
Definition at line 305 of file plpy_cursorobject.c.
References PLyCursorObject::closed, GetPortalByName(), PLy_free(), PLy_typeinfo_dealloc(), PortalIsValid, PLyCursorObject::portalname, PLyCursorObject::result, and SPI_cursor_close().
{
PLyCursorObject *cursor;
Portal portal;
cursor = (PLyCursorObject *) arg;
if (!cursor->closed)
{
portal = GetPortalByName(cursor->portalname);
if (PortalIsValid(portal))
SPI_cursor_close(portal);
}
PLy_free(cursor->portalname);
cursor->portalname = NULL;
PLy_typeinfo_dealloc(&cursor->result);
arg->ob_type->tp_free(arg);
}
| static PyObject * PLy_cursor_fetch | ( | PyObject * | self, | |
| PyObject * | args | |||
| ) | [static] |
Definition at line 391 of file plpy_cursorobject.c.
References PLyCursorObject::closed, CurrentMemoryContext, CurrentResourceOwner, GetPortalByName(), i, PLyTypeInfo::is_rowtype, PLyResultObject::nrows, NULL, PG_CATCH, PG_END_TRY, PG_TRY, PLy_exception_set(), PLy_input_tuple_funcs(), PLy_result_new(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PLyDict_FromTuple(), PortalIsValid, PLyCursorObject::portalname, PLyCursorObject::result, PLyResultObject::rows, SPI_cursor_fetch(), SPI_freetuptable(), SPI_OK_FETCH, SPI_processed, SPI_tuptable, PLyResultObject::status, SPITupleTable::tupdesc, and SPITupleTable::vals.
{
PLyCursorObject *cursor;
int count;
PLyResultObject *ret;
volatile MemoryContext oldcontext;
volatile ResourceOwner oldowner;
Portal portal;
if (!PyArg_ParseTuple(args, "i", &count))
return NULL;
cursor = (PLyCursorObject *) self;
if (cursor->closed)
{
PLy_exception_set(PyExc_ValueError, "fetch from a closed cursor");
return NULL;
}
portal = GetPortalByName(cursor->portalname);
if (!PortalIsValid(portal))
{
PLy_exception_set(PyExc_ValueError,
"iterating a cursor in an aborted subtransaction");
return NULL;
}
ret = (PLyResultObject *) PLy_result_new();
if (ret == NULL)
return NULL;
oldcontext = CurrentMemoryContext;
oldowner = CurrentResourceOwner;
PLy_spi_subtransaction_begin(oldcontext, oldowner);
PG_TRY();
{
SPI_cursor_fetch(portal, true, count);
if (cursor->result.is_rowtype != 1)
PLy_input_tuple_funcs(&cursor->result, SPI_tuptable->tupdesc);
Py_DECREF(ret->status);
ret->status = PyInt_FromLong(SPI_OK_FETCH);
Py_DECREF(ret->nrows);
ret->nrows = PyInt_FromLong(SPI_processed);
if (SPI_processed != 0)
{
int i;
Py_DECREF(ret->rows);
ret->rows = PyList_New(SPI_processed);
for (i = 0; i < SPI_processed; i++)
{
PyObject *row = PLyDict_FromTuple(&cursor->result,
SPI_tuptable->vals[i],
SPI_tuptable->tupdesc);
PyList_SetItem(ret->rows, i, row);
}
}
SPI_freetuptable(SPI_tuptable);
PLy_spi_subtransaction_commit(oldcontext, oldowner);
}
PG_CATCH();
{
SPI_freetuptable(SPI_tuptable);
PLy_spi_subtransaction_abort(oldcontext, oldowner);
return NULL;
}
PG_END_TRY();
return (PyObject *) ret;
}
| void PLy_cursor_init_type | ( | void | ) |
Definition at line 77 of file plpy_cursorobject.c.
References elog, ERROR, and PLy_CursorType.
Referenced by PLy_init_plpy().
{
if (PyType_Ready(&PLy_CursorType) < 0)
elog(ERROR, "could not initialize PLy_CursorType");
}
| static PyObject * PLy_cursor_iternext | ( | PyObject * | self | ) | [static] |
Definition at line 328 of file plpy_cursorobject.c.
References PLyCursorObject::closed, CurrentMemoryContext, CurrentResourceOwner, GetPortalByName(), PLyTypeInfo::is_rowtype, PG_CATCH, PG_END_TRY, PG_TRY, PLy_exception_set(), PLy_input_tuple_funcs(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PLyDict_FromTuple(), PortalIsValid, PLyCursorObject::portalname, PLyCursorObject::result, SPI_cursor_fetch(), SPI_freetuptable(), SPI_processed, SPI_tuptable, SPITupleTable::tupdesc, and SPITupleTable::vals.
{
PLyCursorObject *cursor;
PyObject *ret;
volatile MemoryContext oldcontext;
volatile ResourceOwner oldowner;
Portal portal;
cursor = (PLyCursorObject *) self;
if (cursor->closed)
{
PLy_exception_set(PyExc_ValueError, "iterating a closed cursor");
return NULL;
}
portal = GetPortalByName(cursor->portalname);
if (!PortalIsValid(portal))
{
PLy_exception_set(PyExc_ValueError,
"iterating a cursor in an aborted subtransaction");
return NULL;
}
oldcontext = CurrentMemoryContext;
oldowner = CurrentResourceOwner;
PLy_spi_subtransaction_begin(oldcontext, oldowner);
PG_TRY();
{
SPI_cursor_fetch(portal, true, 1);
if (SPI_processed == 0)
{
PyErr_SetNone(PyExc_StopIteration);
ret = NULL;
}
else
{
if (cursor->result.is_rowtype != 1)
PLy_input_tuple_funcs(&cursor->result, SPI_tuptable->tupdesc);
ret = PLyDict_FromTuple(&cursor->result, SPI_tuptable->vals[0],
SPI_tuptable->tupdesc);
}
SPI_freetuptable(SPI_tuptable);
PLy_spi_subtransaction_commit(oldcontext, oldowner);
}
PG_CATCH();
{
SPI_freetuptable(SPI_tuptable);
PLy_spi_subtransaction_abort(oldcontext, oldowner);
return NULL;
}
PG_END_TRY();
return ret;
}
| static PyObject * PLy_cursor_plan | ( | PyObject * | ob, | |
| PyObject * | args | |||
| ) | [static] |
Definition at line 158 of file plpy_cursorobject.c.
References PLyPlanObject::args, Assert, PLyCursorObject::closed, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, PLyTypeOutput::d, DatumGetPointer, elog, ERROR, PLyProcedure::fn_readonly, PLyObToDatum::func, i, InputFunctionCall(), PortalData::name, PLyPlanObject::nargs, NULL, PLyTypeInfo::out, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLyPlanObject::plan, PLy_current_execution_context(), PLy_CursorType, PLy_elog(), PLy_exception_set(), PLy_exception_set_plural(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PLy_strdup(), PLy_typeinfo_init(), PointerGetDatum, PLyCursorObject::portalname, PLyCursorObject::result, SPI_cursor_open(), SPI_result, SPI_result_code_string(), PLyObToDatum::typbyval, PLyObToDatum::typfunc, PLyObToDatum::typioparam, and PLyPlanObject::values.
Referenced by PLy_cursor().
{
PLyCursorObject *cursor;
volatile int nargs;
int i;
PLyPlanObject *plan;
volatile MemoryContext oldcontext;
volatile ResourceOwner oldowner;
if (args)
{
if (!PySequence_Check(args) || PyString_Check(args) || PyUnicode_Check(args))
{
PLy_exception_set(PyExc_TypeError, "plpy.cursor takes a sequence as its second argument");
return NULL;
}
nargs = PySequence_Length(args);
}
else
nargs = 0;
plan = (PLyPlanObject *) ob;
if (nargs != plan->nargs)
{
char *sv;
PyObject *so = PyObject_Str(args);
if (!so)
PLy_elog(ERROR, "could not execute plan");
sv = PyString_AsString(so);
PLy_exception_set_plural(PyExc_TypeError,
"Expected sequence of %d argument, got %d: %s",
"Expected sequence of %d arguments, got %d: %s",
plan->nargs,
plan->nargs, nargs, sv);
Py_DECREF(so);
return NULL;
}
if ((cursor = PyObject_New(PLyCursorObject, &PLy_CursorType)) == NULL)
return NULL;
cursor->portalname = NULL;
cursor->closed = false;
PLy_typeinfo_init(&cursor->result);
oldcontext = CurrentMemoryContext;
oldowner = CurrentResourceOwner;
PLy_spi_subtransaction_begin(oldcontext, oldowner);
PG_TRY();
{
PLyExecutionContext *exec_ctx = PLy_current_execution_context();
Portal portal;
char *volatile nulls;
volatile int j;
if (nargs > 0)
nulls = palloc(nargs * sizeof(char));
else
nulls = NULL;
for (j = 0; j < nargs; j++)
{
PyObject *elem;
elem = PySequence_GetItem(args, j);
if (elem != Py_None)
{
PG_TRY();
{
plan->values[j] =
plan->args[j].out.d.func(&(plan->args[j].out.d),
-1,
elem);
}
PG_CATCH();
{
Py_DECREF(elem);
PG_RE_THROW();
}
PG_END_TRY();
Py_DECREF(elem);
nulls[j] = ' ';
}
else
{
Py_DECREF(elem);
plan->values[j] =
InputFunctionCall(&(plan->args[j].out.d.typfunc),
NULL,
plan->args[j].out.d.typioparam,
-1);
nulls[j] = 'n';
}
}
portal = SPI_cursor_open(NULL, plan->plan, plan->values, nulls,
exec_ctx->curr_proc->fn_readonly);
if (portal == NULL)
elog(ERROR, "SPI_cursor_open() failed: %s",
SPI_result_code_string(SPI_result));
cursor->portalname = PLy_strdup(portal->name);
PLy_spi_subtransaction_commit(oldcontext, oldowner);
}
PG_CATCH();
{
int k;
/* cleanup plan->values array */
for (k = 0; k < nargs; k++)
{
if (!plan->args[k].out.d.typbyval &&
(plan->values[k] != PointerGetDatum(NULL)))
{
pfree(DatumGetPointer(plan->values[k]));
plan->values[k] = PointerGetDatum(NULL);
}
}
Py_DECREF(cursor);
PLy_spi_subtransaction_abort(oldcontext, oldowner);
return NULL;
}
PG_END_TRY();
for (i = 0; i < nargs; i++)
{
if (!plan->args[i].out.d.typbyval &&
(plan->values[i] != PointerGetDatum(NULL)))
{
pfree(DatumGetPointer(plan->values[i]));
plan->values[i] = PointerGetDatum(NULL);
}
}
Assert(cursor->portalname != NULL);
return (PyObject *) cursor;
}
| static PyObject * PLy_cursor_query | ( | const char * | query | ) | [static] |
Definition at line 104 of file plpy_cursorobject.c.
References Assert, PLyCursorObject::closed, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, elog, ERROR, PLyProcedure::fn_readonly, PortalData::name, NULL, PG_CATCH, PG_END_TRY, PG_TRY, pg_verifymbstr(), PLy_current_execution_context(), PLy_CursorType, PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PLy_strdup(), PLy_typeinfo_init(), PLyCursorObject::portalname, PLyCursorObject::result, SPI_cursor_open(), SPI_freeplan(), SPI_prepare(), SPI_result, and SPI_result_code_string().
Referenced by PLy_cursor().
{
PLyCursorObject *cursor;
volatile MemoryContext oldcontext;
volatile ResourceOwner oldowner;
if ((cursor = PyObject_New(PLyCursorObject, &PLy_CursorType)) == NULL)
return NULL;
cursor->portalname = NULL;
cursor->closed = false;
PLy_typeinfo_init(&cursor->result);
oldcontext = CurrentMemoryContext;
oldowner = CurrentResourceOwner;
PLy_spi_subtransaction_begin(oldcontext, oldowner);
PG_TRY();
{
PLyExecutionContext *exec_ctx = PLy_current_execution_context();
SPIPlanPtr plan;
Portal portal;
pg_verifymbstr(query, strlen(query), false);
plan = SPI_prepare(query, 0, NULL);
if (plan == NULL)
elog(ERROR, "SPI_prepare failed: %s",
SPI_result_code_string(SPI_result));
portal = SPI_cursor_open(NULL, plan, NULL, NULL,
exec_ctx->curr_proc->fn_readonly);
SPI_freeplan(plan);
if (portal == NULL)
elog(ERROR, "SPI_cursor_open() failed: %s",
SPI_result_code_string(SPI_result));
cursor->portalname = PLy_strdup(portal->name);
PLy_spi_subtransaction_commit(oldcontext, oldowner);
}
PG_CATCH();
{
PLy_spi_subtransaction_abort(oldcontext, oldowner);
return NULL;
}
PG_END_TRY();
Assert(cursor->portalname != NULL);
return (PyObject *) cursor;
}
char PLy_cursor_doc[] [static] |
{
"Wrapper around a PostgreSQL cursor"
}
Definition at line 31 of file plpy_cursorobject.c.
PyMethodDef PLy_cursor_methods[] [static] |
{
{"fetch", PLy_cursor_fetch, METH_VARARGS, NULL},
{"close", PLy_cursor_close, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL}
}
Definition at line 35 of file plpy_cursorobject.c.
PyTypeObject PLy_CursorType [static] |
Definition at line 41 of file plpy_cursorobject.c.
Referenced by PLy_cursor_init_type(), PLy_cursor_plan(), and PLy_cursor_query().
1.7.1