aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2011-12-15 16:52:57 +0200
committerPeter Eisentraut <peter_e@gmx.net>2011-12-15 16:52:57 +0200
commitfc9959701b57d11d08a4a8a0788ccbd887ee2e47 (patch)
tree465dcbc579f4f418cfcb31a6a2af7e5dee2f1609
parent5878a328e36b7f59c6c173212b77d0536e8804dd (diff)
downloadpostgresql-fc9959701b57d11d08a4a8a0788ccbd887ee2e47.tar.gz
postgresql-fc9959701b57d11d08a4a8a0788ccbd887ee2e47.zip
PL/Python: Refactor subtransaction handling
Lots of repetitive code was moved into new functions PLy_spi_subtransaction_{begin,commit,abort}. Jan UrbaƄski
-rw-r--r--src/pl/plpython/plpython.c399
1 files changed, 111 insertions, 288 deletions
diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c
index 29e0ac7c454..dce8ff247b6 100644
--- a/src/pl/plpython/plpython.c
+++ b/src/pl/plpython/plpython.c
@@ -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();