*/
static bool silent_error_while_idle = false;
+/*
+ * Which error occured while we were idle? We want to rethrow it in
+ * the face of the next query - except if it is a ROLLBACK/COMMIT - it
+ * will silently be swallowed there...
+ */
+ErrorData *silent_error_while_idle_edata;
+
/* ----------------------------------------------------------------
* decls for routines only used in this file
* ----------------------------------------------------------------
*/
if (IsAbortedTransactionBlockState() &&
!IsTransactionExitStmt(parsetree))
- ereport(ERROR,
- (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
- errmsg("current transaction is aborted, "
- "commands ignored until end of transaction block"),
- errdetail_abort()));
+ RaiseInFailedTransactionError();
/* Make sure we are in a transaction command */
start_xact_command();
*/
if (IsAbortedTransactionBlockState() &&
!IsTransactionExitStmt(raw_parse_tree))
- ereport(ERROR,
- (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
- errmsg("current transaction is aborted, "
- "commands ignored until end of transaction block"),
- errdetail_abort()));
-
+ RaiseInFailedTransactionError();
/*
* Set up a snapshot if parse analysis/planning will need one.
*/
if (IsAbortedTransactionBlockState() &&
(!IsTransactionExitStmt(psrc->raw_parse_tree) ||
numParams != 0))
- ereport(ERROR,
- (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
- errmsg("current transaction is aborted, "
- "commands ignored until end of transaction block"),
- errdetail_abort()));
-
+ RaiseInFailedTransactionError();
/*
* Create the portal. Allow silent replacement of an existing portal only
* if the unnamed portal is specified.
*/
if (IsAbortedTransactionBlockState() &&
!IsTransactionExitStmtList(portal->stmts))
- ereport(ERROR,
- (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
- errmsg("current transaction is aborted, "
- "commands ignored until end of transaction block"),
- errdetail_abort()));
+ RaiseInFailedTransactionError();
/* Check for cancel signal before we start execution */
CHECK_FOR_INTERRUPTS();
*/
if (IsAbortedTransactionBlockState() &&
psrc->resultDesc)
- ereport(ERROR,
- (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
- errmsg("current transaction is aborted, "
- "commands ignored until end of transaction block"),
- errdetail_abort()));
+ RaiseInFailedTransactionError();
if (whereToSendOutput != DestRemote)
return; /* can't actually do anything... */
*/
if (IsAbortedTransactionBlockState() &&
portal->tupDesc)
- ereport(ERROR,
- (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
- errmsg("current transaction is aborted, "
- "commands ignored until end of transaction block"),
- errdetail_abort()));
+ RaiseInFailedTransactionError();
if (whereToSendOutput != DestRemote)
return; /* can't actually do anything... */
return false;
}
+void
+RaiseInFailedTransactionError(void){
+ if(silent_error_while_idle_edata){
+ ReThrowError(silent_error_while_idle_edata);
+ }
+ ereport(ERROR,
+ (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
+ errmsg("current transaction is aborted, "
+ "commands ignored until end of transaction block"),
+ errdetail_abort()));
+}
+
/* Release any existing unnamed prepared statement */
static void
drop_unnamed_stmt(void)
* because that would be unexpected as well.
*/
silent_error_while_idle = true;
- error |= LOG_NO_CLIENT;
+ error |= LOG_NO_CLIENT|LOG_RE_THROW_AFTER_SYNC;
}
if (DoingCommandRead)
{
silent_error_while_idle = true;
- error |= LOG_NO_CLIENT;
+ error |= LOG_NO_CLIENT|LOG_RE_THROW_AFTER_SYNC;
}
ImmediateInterruptOK = false; /* not idle anymore */
if (edata->output_to_client && !(edata->eflags & LOG_NO_CLIENT))
send_message_to_frontend(edata);
+ if(silent_error_while_idle_edata){
+ FreeErrorData(silent_error_while_idle_edata);
+ silent_error_while_idle_edata = 0;
+ }
+
+ if (edata->eflags & LOG_RE_THROW_AFTER_SYNC){
+ Assert(edata->elevel >= ERROR);
+
+ /* The old context is already saved above and reset
+ * below... We cannot store the ErrorData in any other context
+ * than TopMemoryContext - they all may get reset inbetween
+ * two EmitErrorReport() calls.
+ * As there is no convenient point to reset the variable using
+ * any transaction bound variable is not possible without
+ * leaving a stray pointer.
+ */
+ MemoryContextSwitchTo(TopMemoryContext);
+ silent_error_while_idle_edata = CopyErrorData();
+
+ /* We dont want to save/rethrow that error again */
+ silent_error_while_idle_edata->eflags &= ~(LOG_RE_THROW_AFTER_SYNC|LOG_NO_CLIENT);
+ }
+
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
}