#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();
}
1.7.1