PL/Python: Refactor subtransaction handling
Lots of repetitive code was moved into new functions PLy_spi_subtransaction_{begin,commit,abort}. Jan Urbański
This commit is contained in:
parent
5878a328e3
commit
fc9959701b
@ -2964,6 +2964,12 @@ static int PLy_result_ass_item(PyObject *, Py_ssize_t, PyObject *);
|
||||
static int PLy_result_ass_slice(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *);
|
||||
|
||||
|
||||
/* handling of SPI operations inside subtransactions */
|
||||
static void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner);
|
||||
static void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner);
|
||||
static void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner);
|
||||
|
||||
/* SPI operations */
|
||||
static PyObject *PLy_spi_prepare(PyObject *, PyObject *);
|
||||
static PyObject *PLy_spi_execute(PyObject *, PyObject *);
|
||||
static PyObject *PLy_spi_execute_query(char *query, long limit);
|
||||
@ -3390,6 +3396,90 @@ PLy_result_ass_slice(PyObject *arg, Py_ssize_t lidx, Py_ssize_t hidx, PyObject *
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utilities for running SPI functions in subtransactions.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* MemoryContext oldcontext = CurrentMemoryContext;
|
||||
* ResourceOwner oldowner = CurrentResourceOwner;
|
||||
*
|
||||
* PLy_spi_subtransaction_begin(oldcontext, oldowner);
|
||||
* PG_TRY();
|
||||
* {
|
||||
* <call SPI functions>
|
||||
* PLy_spi_subtransaction_commit(oldcontext, oldowner);
|
||||
* }
|
||||
* PG_CATCH();
|
||||
* {
|
||||
* <do cleanup>
|
||||
* PLy_spi_subtransaction_abort(oldcontext, oldowner);
|
||||
* return NULL;
|
||||
* }
|
||||
* PG_END_TRY();
|
||||
*
|
||||
* These utilities take care of restoring connection to the SPI manager and
|
||||
* setting a Python exception in case of an abort.
|
||||
*/
|
||||
static void
|
||||
PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
|
||||
{
|
||||
BeginInternalSubTransaction(NULL);
|
||||
/* Want to run inside function's memory context */
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
}
|
||||
|
||||
static void
|
||||
PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
|
||||
{
|
||||
/* 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();
|
||||
}
|
||||
|
||||
static void
|
||||
PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* SPI interface */
|
||||
static PyObject *
|
||||
PLy_spi_prepare(PyObject *self, PyObject *args)
|
||||
@ -3425,8 +3515,7 @@ PLy_spi_prepare(PyObject *self, PyObject *args)
|
||||
oldcontext = CurrentMemoryContext;
|
||||
oldowner = CurrentResourceOwner;
|
||||
|
||||
BeginInternalSubTransaction(NULL);
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
PLy_spi_subtransaction_begin(oldcontext, oldowner);
|
||||
|
||||
PG_TRY();
|
||||
{
|
||||
@ -3504,50 +3593,14 @@ PLy_spi_prepare(PyObject *self, PyObject *args)
|
||||
if (SPI_keepplan(plan->plan))
|
||||
elog(ERROR, "SPI_keepplan failed");
|
||||
|
||||
/* 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();
|
||||
PLy_spi_subtransaction_commit(oldcontext, oldowner);
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
ErrorData *edata;
|
||||
PLyExceptionEntry *entry;
|
||||
PyObject *exc;
|
||||
|
||||
/* Save error info */
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
edata = CopyErrorData();
|
||||
FlushErrorState();
|
||||
Py_DECREF(plan);
|
||||
Py_XDECREF(optr);
|
||||
|
||||
/* 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);
|
||||
PLy_spi_subtransaction_abort(oldcontext, oldowner);
|
||||
return NULL;
|
||||
}
|
||||
PG_END_TRY();
|
||||
@ -3626,9 +3679,7 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
|
||||
oldcontext = CurrentMemoryContext;
|
||||
oldowner = CurrentResourceOwner;
|
||||
|
||||
BeginInternalSubTransaction(NULL);
|
||||
/* Want to run inside function's memory context */
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
PLy_spi_subtransaction_begin(oldcontext, oldowner);
|
||||
|
||||
PG_TRY();
|
||||
{
|
||||
@ -3683,28 +3734,11 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
|
||||
if (nargs > 0)
|
||||
pfree(nulls);
|
||||
|
||||
/* 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();
|
||||
PLy_spi_subtransaction_commit(oldcontext, oldowner);
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
int k;
|
||||
ErrorData *edata;
|
||||
PLyExceptionEntry *entry;
|
||||
PyObject *exc;
|
||||
|
||||
/* Save error info */
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
edata = CopyErrorData();
|
||||
FlushErrorState();
|
||||
|
||||
/*
|
||||
* cleanup plan->values array
|
||||
@ -3719,26 +3753,7 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
PLy_spi_subtransaction_abort(oldcontext, oldowner);
|
||||
return NULL;
|
||||
}
|
||||
PG_END_TRY();
|
||||
@ -3775,9 +3790,7 @@ PLy_spi_execute_query(char *query, long limit)
|
||||
oldcontext = CurrentMemoryContext;
|
||||
oldowner = CurrentResourceOwner;
|
||||
|
||||
BeginInternalSubTransaction(NULL);
|
||||
/* Want to run inside function's memory context */
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
PLy_spi_subtransaction_begin(oldcontext, oldowner);
|
||||
|
||||
PG_TRY();
|
||||
{
|
||||
@ -3785,48 +3798,11 @@ PLy_spi_execute_query(char *query, long limit)
|
||||
rv = SPI_execute(query, PLy_curr_procedure->fn_readonly, limit);
|
||||
ret = PLy_spi_execute_fetch_result(SPI_tuptable, SPI_processed, rv);
|
||||
|
||||
/* 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();
|
||||
PLy_spi_subtransaction_commit(oldcontext, oldowner);
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
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);
|
||||
PLy_spi_subtransaction_abort(oldcontext, oldowner);
|
||||
return NULL;
|
||||
}
|
||||
PG_END_TRY();
|
||||
@ -3944,8 +3920,7 @@ PLy_cursor_query(const char *query)
|
||||
oldcontext = CurrentMemoryContext;
|
||||
oldowner = CurrentResourceOwner;
|
||||
|
||||
BeginInternalSubTransaction(NULL);
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
PLy_spi_subtransaction_begin(oldcontext, oldowner);
|
||||
|
||||
PG_TRY();
|
||||
{
|
||||
@ -3969,50 +3944,11 @@ PLy_cursor_query(const char *query)
|
||||
|
||||
cursor->portalname = PLy_strdup(portal->name);
|
||||
|
||||
/* 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();
|
||||
PLy_spi_subtransaction_commit(oldcontext, oldowner);
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
ErrorData *edata;
|
||||
PLyExceptionEntry *entry;
|
||||
PyObject *exc;
|
||||
|
||||
/* Save error info */
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
edata = CopyErrorData();
|
||||
FlushErrorState();
|
||||
|
||||
/* Abort the inner transaction */
|
||||
RollbackAndReleaseCurrentSubTransaction();
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
CurrentResourceOwner = oldowner;
|
||||
|
||||
Py_DECREF(cursor);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
PLy_spi_subtransaction_abort(oldcontext, oldowner);
|
||||
return NULL;
|
||||
}
|
||||
PG_END_TRY();
|
||||
@ -4072,8 +4008,7 @@ PLy_cursor_plan(PyObject *ob, PyObject *args)
|
||||
oldcontext = CurrentMemoryContext;
|
||||
oldowner = CurrentResourceOwner;
|
||||
|
||||
BeginInternalSubTransaction(NULL);
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
PLy_spi_subtransaction_begin(oldcontext, oldowner);
|
||||
|
||||
PG_TRY();
|
||||
{
|
||||
@ -4130,28 +4065,11 @@ PLy_cursor_plan(PyObject *ob, PyObject *args)
|
||||
|
||||
cursor->portalname = PLy_strdup(portal->name);
|
||||
|
||||
/* 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();
|
||||
PLy_spi_subtransaction_commit(oldcontext, oldowner);
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
int k;
|
||||
ErrorData *edata;
|
||||
PLyExceptionEntry *entry;
|
||||
PyObject *exc;
|
||||
|
||||
/* Save error info */
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
edata = CopyErrorData();
|
||||
FlushErrorState();
|
||||
|
||||
/* cleanup plan->values array */
|
||||
for (k = 0; k < nargs; k++)
|
||||
@ -4164,28 +4082,9 @@ PLy_cursor_plan(PyObject *ob, PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
/* Abort the inner transaction */
|
||||
RollbackAndReleaseCurrentSubTransaction();
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
CurrentResourceOwner = oldowner;
|
||||
|
||||
Py_DECREF(cursor);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
PLy_spi_subtransaction_abort(oldcontext, oldowner);
|
||||
return NULL;
|
||||
}
|
||||
PG_END_TRY();
|
||||
@ -4255,8 +4154,7 @@ PLy_cursor_iternext(PyObject *self)
|
||||
oldcontext = CurrentMemoryContext;
|
||||
oldowner = CurrentResourceOwner;
|
||||
|
||||
BeginInternalSubTransaction(NULL);
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
PLy_spi_subtransaction_begin(oldcontext, oldowner);
|
||||
|
||||
PG_TRY();
|
||||
{
|
||||
@ -4277,50 +4175,13 @@ PLy_cursor_iternext(PyObject *self)
|
||||
|
||||
SPI_freetuptable(SPI_tuptable);
|
||||
|
||||
/* 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();
|
||||
PLy_spi_subtransaction_commit(oldcontext, oldowner);
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
ErrorData *edata;
|
||||
PLyExceptionEntry *entry;
|
||||
PyObject *exc;
|
||||
|
||||
/* Save error info */
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
edata = CopyErrorData();
|
||||
FlushErrorState();
|
||||
|
||||
/* Abort the inner transaction */
|
||||
RollbackAndReleaseCurrentSubTransaction();
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
CurrentResourceOwner = oldowner;
|
||||
|
||||
SPI_freetuptable(SPI_tuptable);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
PLy_spi_subtransaction_abort(oldcontext, oldowner);
|
||||
return NULL;
|
||||
}
|
||||
PG_END_TRY();
|
||||
@ -4364,8 +4225,7 @@ PLy_cursor_fetch(PyObject *self, PyObject *args)
|
||||
oldcontext = CurrentMemoryContext;
|
||||
oldowner = CurrentResourceOwner;
|
||||
|
||||
BeginInternalSubTransaction(NULL);
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
PLy_spi_subtransaction_begin(oldcontext, oldowner);
|
||||
|
||||
PG_TRY();
|
||||
{
|
||||
@ -4398,50 +4258,13 @@ PLy_cursor_fetch(PyObject *self, PyObject *args)
|
||||
|
||||
SPI_freetuptable(SPI_tuptable);
|
||||
|
||||
/* 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();
|
||||
PLy_spi_subtransaction_commit(oldcontext, oldowner);
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
ErrorData *edata;
|
||||
PLyExceptionEntry *entry;
|
||||
PyObject *exc;
|
||||
|
||||
/* Save error info */
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
edata = CopyErrorData();
|
||||
FlushErrorState();
|
||||
|
||||
/* Abort the inner transaction */
|
||||
RollbackAndReleaseCurrentSubTransaction();
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
CurrentResourceOwner = oldowner;
|
||||
|
||||
SPI_freetuptable(SPI_tuptable);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
PLy_spi_subtransaction_abort(oldcontext, oldowner);
|
||||
return NULL;
|
||||
}
|
||||
PG_END_TRY();
|
||||
|
Loading…
Reference in New Issue
Block a user