#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().