#include "utils/palloc.h"
#include "utils/resowner.h"
Go to the source code of this file.
Data Structures | |
struct | PLyExceptionEntry |
Typedefs | |
typedef struct PLyExceptionEntry | PLyExceptionEntry |
Functions | |
PyObject * | PLy_spi_prepare (PyObject *self, PyObject *args) |
PyObject * | PLy_spi_execute (PyObject *self, PyObject *args) |
void | PLy_spi_subtransaction_begin (MemoryContext oldcontext, ResourceOwner oldowner) |
void | PLy_spi_subtransaction_commit (MemoryContext oldcontext, ResourceOwner oldowner) |
void | PLy_spi_subtransaction_abort (MemoryContext oldcontext, ResourceOwner oldowner) |
typedef struct PLyExceptionEntry PLyExceptionEntry |
PyObject* PLy_spi_execute | ( | PyObject * | self, | |
PyObject * | args | |||
) |
Definition at line 172 of file plpy_spi.c.
References is_PLyPlanObject(), sort-test::list, PLy_exc_error, PLy_exception_set(), PLy_spi_execute_plan(), and PLy_spi_execute_query().
{ char *query; PyObject *plan; PyObject *list = NULL; long limit = 0; if (PyArg_ParseTuple(args, "s|l", &query, &limit)) return PLy_spi_execute_query(query, limit); PyErr_Clear(); if (PyArg_ParseTuple(args, "O|Ol", &plan, &list, &limit) && is_PLyPlanObject(plan)) return PLy_spi_execute_plan(plan, list, limit); PLy_exception_set(PLy_exc_error, "plpy.execute expected a query or a plan"); return NULL; }
PyObject* PLy_spi_prepare | ( | PyObject * | self, | |
PyObject * | args | |||
) |
Definition at line 41 of file plpy_spi.c.
References PLyPlanObject::args, Assert, CurrentMemoryContext, CurrentResourceOwner, elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, HeapTupleIsValid, i, sort-test::list, PLyPlanObject::nargs, NULL, ObjectIdGetDatum, parseTypeString(), PG_CATCH, PG_END_TRY, PG_TRY, pg_verifymbstr(), PLyPlanObject::plan, PLy_exception_set(), PLy_malloc(), PLy_output_datum_func(), PLy_plan_new(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PLy_typeinfo_init(), PLyUnicode_AsString(), PointerGetDatum, ReleaseSysCache(), SearchSysCache1, SPI_keepplan(), SPI_prepare(), SPI_result, SPI_result_code_string(), TYPEOID, PLyPlanObject::types, TYPTYPE_COMPOSITE, and PLyPlanObject::values.
{ PLyPlanObject *plan; PyObject *list = NULL; PyObject *volatile optr = NULL; char *query; volatile MemoryContext oldcontext; volatile ResourceOwner oldowner; volatile int nargs; if (!PyArg_ParseTuple(args, "s|O", &query, &list)) return NULL; if (list && (!PySequence_Check(list))) { PLy_exception_set(PyExc_TypeError, "second argument of plpy.prepare must be a sequence"); return NULL; } if ((plan = (PLyPlanObject *) PLy_plan_new()) == NULL) return NULL; nargs = list ? PySequence_Length(list) : 0; plan->nargs = nargs; plan->types = nargs ? PLy_malloc(sizeof(Oid) * nargs) : NULL; plan->values = nargs ? PLy_malloc(sizeof(Datum) * nargs) : NULL; plan->args = nargs ? PLy_malloc(sizeof(PLyTypeInfo) * nargs) : NULL; oldcontext = CurrentMemoryContext; oldowner = CurrentResourceOwner; PLy_spi_subtransaction_begin(oldcontext, oldowner); PG_TRY(); { int i; /* * the other loop might throw an exception, if PLyTypeInfo member * isn't properly initialized the Py_DECREF(plan) will go boom */ for (i = 0; i < nargs; i++) { PLy_typeinfo_init(&plan->args[i]); plan->values[i] = PointerGetDatum(NULL); } for (i = 0; i < nargs; i++) { char *sptr; HeapTuple typeTup; Oid typeId; int32 typmod; Form_pg_type typeStruct; optr = PySequence_GetItem(list, i); if (PyString_Check(optr)) sptr = PyString_AsString(optr); else if (PyUnicode_Check(optr)) sptr = PLyUnicode_AsString(optr); else { ereport(ERROR, (errmsg("plpy.prepare: type name at ordinal position %d is not a string", i))); sptr = NULL; /* keep compiler quiet */ } /******************************************************** * Resolve argument type names and then look them up by * oid in the system cache, and remember the required *information for input conversion. ********************************************************/ parseTypeString(sptr, &typeId, &typmod); typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeId)); if (!HeapTupleIsValid(typeTup)) elog(ERROR, "cache lookup failed for type %u", typeId); Py_DECREF(optr); /* * set optr to NULL, so we won't try to unref it again in case of * an error */ optr = NULL; plan->types[i] = typeId; typeStruct = (Form_pg_type) GETSTRUCT(typeTup); if (typeStruct->typtype != TYPTYPE_COMPOSITE) PLy_output_datum_func(&plan->args[i], typeTup); else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("plpy.prepare does not support composite types"))); ReleaseSysCache(typeTup); } pg_verifymbstr(query, strlen(query), false); plan->plan = SPI_prepare(query, plan->nargs, plan->types); if (plan->plan == NULL) elog(ERROR, "SPI_prepare failed: %s", SPI_result_code_string(SPI_result)); /* transfer plan from procCxt to topCxt */ if (SPI_keepplan(plan->plan)) elog(ERROR, "SPI_keepplan failed"); PLy_spi_subtransaction_commit(oldcontext, oldowner); } PG_CATCH(); { Py_DECREF(plan); Py_XDECREF(optr); PLy_spi_subtransaction_abort(oldcontext, oldowner); return NULL; } PG_END_TRY(); Assert(plan->plan != NULL); return (PyObject *) plan; }
void PLy_spi_subtransaction_abort | ( | MemoryContext | oldcontext, | |
ResourceOwner | oldowner | |||
) |
Definition at line 504 of file plpy_spi.c.
References Assert, CopyErrorData(), CurrentResourceOwner, PLyExceptionEntry::exc, FlushErrorState(), FreeErrorData(), HASH_FIND, hash_search(), MemoryContextSwitchTo(), NULL, PLy_exc_spi_error, PLy_spi_exception_set(), PLy_spi_exceptions, RollbackAndReleaseCurrentSubTransaction(), SPI_restore_connection(), and ErrorData::sqlerrcode.
Referenced by PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_cursor_plan(), PLy_cursor_query(), PLy_spi_execute_plan(), PLy_spi_execute_query(), and PLy_spi_prepare().
{ ErrorData *edata; PLyExceptionEntry *entry; PyObject *exc; /* Save error info */ MemoryContextSwitchTo(oldcontext); edata = CopyErrorData(); FlushErrorState(); /* Abort the inner transaction */ RollbackAndReleaseCurrentSubTransaction(); MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; /* * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will * have left us in a disconnected state. We need this hack to return to * connected state. */ SPI_restore_connection(); /* Look up the correct exception */ entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode), HASH_FIND, NULL); /* We really should find it, but just in case have a fallback */ Assert(entry != NULL); exc = entry ? entry->exc : PLy_exc_spi_error; /* Make Python raise the exception */ PLy_spi_exception_set(exc, edata); FreeErrorData(edata); }
void PLy_spi_subtransaction_begin | ( | MemoryContext | oldcontext, | |
ResourceOwner | oldowner | |||
) |
Definition at line 481 of file plpy_spi.c.
References BeginInternalSubTransaction(), MemoryContextSwitchTo(), and NULL.
Referenced by PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_cursor_plan(), PLy_cursor_query(), PLy_spi_execute_plan(), PLy_spi_execute_query(), and PLy_spi_prepare().
{ BeginInternalSubTransaction(NULL); /* Want to run inside function's memory context */ MemoryContextSwitchTo(oldcontext); }
void PLy_spi_subtransaction_commit | ( | MemoryContext | oldcontext, | |
ResourceOwner | oldowner | |||
) |
Definition at line 489 of file plpy_spi.c.
References CurrentResourceOwner, MemoryContextSwitchTo(), ReleaseCurrentSubTransaction(), and SPI_restore_connection().
Referenced by PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_cursor_plan(), PLy_cursor_query(), PLy_spi_execute_plan(), PLy_spi_execute_query(), and PLy_spi_prepare().
{ /* Commit the inner transaction, return to outer xact context */ ReleaseCurrentSubTransaction(); MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; /* * AtEOSubXact_SPI() should not have popped any SPI context, but just in * case it did, make sure we remain connected. */ SPI_restore_connection(); }