/* * Abort lingering subtransactions that have been explicitly started * by plpy.subtransaction().start() and not properly closed. */ static void PLy_abort_open_subtransactions(int save_subxact_level) { Assert(save_subxact_level >= 0); while (list_length(explicit_subtransactions) > save_subxact_level) { PLySubtransactionData *subtransactiondata; Assert(explicit_subtransactions != NIL); ereport(WARNING, (errmsg("forcibly aborting a subtransaction that has not been exited"))); RollbackAndReleaseCurrentSubTransaction(); SPI_restore_connection(); subtransactiondata = (PLySubtransactionData *) linitial(explicit_subtransactions); explicit_subtransactions = list_delete_first(explicit_subtransactions); MemoryContextSwitchTo(subtransactiondata->oldcontext); CurrentResourceOwner = subtransactiondata->oldowner; pfree(subtransactiondata); } }
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); }
/* * subxact.__exit__(exc_type, exc, tb) or subxact.exit(exc_type, exc, tb) * * Exit an explicit subtransaction. exc_type is an exception type, exc * is the exception object, tb is the traceback. If exc_type is None, * commit the subtransactiony, if not abort it. * * The method signature is chosen to allow subtransaction objects to * be used as context managers as described in * <http://www.python.org/dev/peps/pep-0343/>. */ static PyObject * PLy_subtransaction_exit(PyObject *self, PyObject *args) { PyObject *type; PyObject *value; PyObject *traceback; PLySubtransactionData *subxactdata; PLySubtransactionObject *subxact = (PLySubtransactionObject *) self; if (!PyArg_ParseTuple(args, "OOO", &type, &value, &traceback)) return NULL; if (!subxact->started) { PLy_exception_set(PyExc_ValueError, "this subtransaction has not been entered"); return NULL; } if (subxact->exited) { PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited"); return NULL; } if (explicit_subtransactions == NIL) { PLy_exception_set(PyExc_ValueError, "there is no subtransaction to exit from"); return NULL; } subxact->exited = true; if (type != Py_None) { /* Abort the inner transaction */ RollbackAndReleaseCurrentSubTransaction(); } else { ReleaseCurrentSubTransaction(); } subxactdata = (PLySubtransactionData *) linitial(explicit_subtransactions); explicit_subtransactions = list_delete_first(explicit_subtransactions); MemoryContextSwitchTo(subxactdata->oldcontext); CurrentResourceOwner = subxactdata->oldowner; pfree(subxactdata); /* * AtEOSubXact_SPI() should not have popped any SPI context, but just in * case it did, make sure we remain connected. */ SPI_restore_connection(); Py_INCREF(Py_None); return Py_None; }
static void luaP_throwsqlerr (lua_State *L, ErrorData *ed) { SPI_restore_connection(); lua_pushstring(L, ed->message); FreeErrorData(ed); lua_pushlightuserdata(L, (void *)PLLUA_TXNABORT); lua_pushvalue(L, -2); lua_rawset(L, LUA_REGISTRYINDEX); lua_error(L); }
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(); }
SV * plperl_spi_fetchrow(char *cursor) { SV *row; /* * Execute the FETCH inside a sub-transaction, so we can cope with errors * sanely */ MemoryContext oldcontext = CurrentMemoryContext; ResourceOwner oldowner = CurrentResourceOwner; BeginInternalSubTransaction(NULL); /* Want to run inside function's memory context */ MemoryContextSwitchTo(oldcontext); PG_TRY(); { Portal p = SPI_cursor_find(cursor); if (!p) row = newSV(0); else { SPI_cursor_fetch(p, true, 1); if (SPI_processed == 0) { SPI_cursor_close(p); row = newSV(0); } else { row = plperl_hash_from_tuple(SPI_tuptable->vals[0], SPI_tuptable->tupdesc); } 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(); } PG_CATCH(); { ErrorData *edata; /* 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(); /* Punt the error to Perl */ croak("%s", edata->message); /* Can't get here, but keep compiler quiet */ return NULL; } PG_END_TRY(); return row; }
SV * plperl_spi_query(char *query) { SV *cursor; /* * Execute the query inside a sub-transaction, so we can cope with errors * sanely */ MemoryContext oldcontext = CurrentMemoryContext; ResourceOwner oldowner = CurrentResourceOwner; BeginInternalSubTransaction(NULL); /* Want to run inside function's memory context */ MemoryContextSwitchTo(oldcontext); PG_TRY(); { void *plan; Portal portal = NULL; /* Create a cursor for the query */ plan = SPI_prepare(query, 0, NULL); if (plan) portal = SPI_cursor_open(NULL, plan, NULL, NULL, false); if (portal) cursor = newSVpv(portal->name, 0); else cursor = newSV(0); /* 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(); } PG_CATCH(); { ErrorData *edata; /* 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(); /* Punt the error to Perl */ croak("%s", edata->message); /* Can't get here, but keep compiler quiet */ return NULL; } PG_END_TRY(); return cursor; }
HV * plperl_spi_exec(char *query, int limit) { HV *ret_hv; /* * Execute the query inside a sub-transaction, so we can cope with errors * sanely */ MemoryContext oldcontext = CurrentMemoryContext; ResourceOwner oldowner = CurrentResourceOwner; BeginInternalSubTransaction(NULL); /* Want to run inside function's memory context */ MemoryContextSwitchTo(oldcontext); PG_TRY(); { int spi_rv; spi_rv = SPI_execute(query, plperl_current_prodesc->fn_readonly, limit); ret_hv = plperl_spi_execute_fetch_result(SPI_tuptable, SPI_processed, spi_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(); } PG_CATCH(); { ErrorData *edata; /* 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(); /* Punt the error to Perl */ croak("%s", edata->message); /* Can't get here, but keep compiler quiet */ return NULL; } PG_END_TRY(); return ret_hv; }
bool pl_ist_abort(unsigned long xid, char state) { bool r = true; PG_TRY(); { if (pl_ist_count != xid) { ereport(ERROR,( errcode(ERRCODE_SAVEPOINT_EXCEPTION), errmsg("out-of-order abort attempt on subtransaction %lu", xid), errdetail("Subtransaction %lu was expected to exit next.", pl_ist_count) )); } /* Prevent wrap around */ if (pl_ist_count == 0) { ereport(ERROR,( errcode(ERRCODE_SAVEPOINT_EXCEPTION), errmsg("no current internal subtransaction"), errhint("Attempt to abort the current IST, when none running.") )); } if (state == pl_ist_committed) { ereport(ERROR,( errcode(ERRCODE_SAVEPOINT_EXCEPTION), errmsg("cannot abort a committed subtransaction") )); } if (state == pl_ist_aborted) { ereport(ERROR,( errcode(ERRCODE_SAVEPOINT_EXCEPTION), errmsg("subtransaction was already aborted") )); } if (state == pl_ist_new) { ereport(ERROR,( errcode(ERRCODE_SAVEPOINT_EXCEPTION), errmsg("cannot abort a subtransaction that has not been started") )); } pl_ist_count = pl_ist_count - 1; RollbackAndReleaseCurrentSubTransaction(); pl_state = pl_ready_for_access; /* No longer in an error state. */ SPI_restore_connection(); } PG_CATCH(); { PyErr_SetPgError(true); pl_state = pl_in_failed_transaction; r = false; } PG_END_TRY(); return(r); }
static void test_spi_exec_utility(int *passed, int *total) { int rc; volatile int caseno = 0; /* Initialize */ rc = SPI_connect(); if (rc != SPI_OK_CONNECT) elog(ERROR, "could not connect SPI: %s", SPI_result_code_string(rc)); /* * *-*-1 * - query error */ caseno++; BeginInternalSubTransaction("test"); PG_TRY(); { spi_exec_utility("RESET dummy_parameter"); elog(WARNING, "*-*-%d failed", caseno); ReleaseCurrentSubTransaction(); } PG_CATCH(); { elog(WARNING, "%s-%d ok", __FUNCTION__, caseno); (*passed)++; RollbackAndReleaseCurrentSubTransaction(); FlushErrorState(); SPI_restore_connection(); } PG_END_TRY(); /* * *-*-2 * - query success */ caseno++; BeginInternalSubTransaction("test"); PG_TRY(); { spi_exec_utility("RESET client_min_messages"); elog(WARNING, "%s-%d ok", __FUNCTION__, caseno); (*passed)++; ReleaseCurrentSubTransaction(); } PG_CATCH(); { elog(WARNING, "*-*-%d failed", caseno); RollbackAndReleaseCurrentSubTransaction(); SPI_restore_connection(); } PG_END_TRY(); /* report # of tests */ (*total) += caseno; /* Cleanup */ rc = SPI_finish(); if (rc != SPI_OK_FINISH && rc != SPI_ERROR_UNCONNECTED) elog(ERROR, "could not finish SPI: %s", SPI_result_code_string(rc)); }
static void test_spi_exec_query(int *passed, int *total) { int rc; volatile int caseno = 0; SPIPlanPtr ptr = NULL; SPIPlanPtr org_ptr; /* Initialize */ rc = SPI_connect(); if (rc != SPI_OK_CONNECT) elog(ERROR, "could not connect SPI: %s", SPI_result_code_string(rc)); /* * *-*-1 * - plan is not cached */ caseno++; BeginInternalSubTransaction("test"); PG_TRY(); { spi_exec_query("SELECT 1", 0, NULL, &ptr, NULL, NULL, SPI_OK_SELECT); if (ptr != NULL && SPI_processed == 1) { elog(WARNING, "%s-%d ok", __FUNCTION__, caseno); (*passed)++; } ReleaseCurrentSubTransaction(); } PG_CATCH(); { elog(WARNING, "*-*-%d failed", caseno); RollbackAndReleaseCurrentSubTransaction(); SPI_restore_connection(); } PG_END_TRY(); /* * *-*-2 * - plan is cached */ caseno++; BeginInternalSubTransaction("test"); PG_TRY(); { org_ptr = ptr; spi_exec_query(NULL, 0, NULL, &ptr, NULL, NULL, SPI_OK_SELECT); if (ptr == org_ptr && SPI_processed == 1) { elog(WARNING, "%s-%d ok", __FUNCTION__, caseno); (*passed)++; } ReleaseCurrentSubTransaction(); } PG_CATCH(); { elog(WARNING, "*-*-%d failed", caseno); RollbackAndReleaseCurrentSubTransaction(); FlushErrorState(); SPI_restore_connection(); } PG_END_TRY(); SPI_freeplan(ptr); ptr = NULL; /* * *-*-3 * - query error */ caseno++; BeginInternalSubTransaction("test"); PG_TRY(); { spi_exec_query("SELECT 1 / 0", 0, NULL, &ptr, NULL, NULL, SPI_OK_SELECT); elog(WARNING, "*-*-%d failed", caseno); ReleaseCurrentSubTransaction(); } PG_CATCH(); { elog(WARNING, "%s-%d ok", __FUNCTION__, caseno); (*passed)++; RollbackAndReleaseCurrentSubTransaction(); FlushErrorState(); SPI_restore_connection(); } PG_END_TRY(); SPI_freeplan(ptr); ptr = NULL; /* * *-*-4 * - query success */ caseno++; BeginInternalSubTransaction("test"); PG_TRY(); { spi_exec_query("SELECT 1", 0, NULL, &ptr, NULL, NULL, SPI_OK_SELECT); if (ptr != NULL && SPI_processed == 1) { elog(WARNING, "%s-%d ok", __FUNCTION__, caseno); (*passed)++; } ReleaseCurrentSubTransaction(); } PG_CATCH(); { elog(WARNING, "*-*-%d failed", caseno); PG_RE_THROW(); RollbackAndReleaseCurrentSubTransaction(); SPI_restore_connection(); } PG_END_TRY(); SPI_freeplan(ptr); ptr = NULL; /* report # of tests */ (*total) += caseno; /* Cleanup */ rc = SPI_finish(); if (rc != SPI_OK_FINISH && rc != SPI_ERROR_UNCONNECTED) elog(ERROR, "could not finish SPI: %s", SPI_result_code_string(rc)); }