diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index bc2a2feb0b..fad49aba82 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -1315,6 +1315,17 @@ SELCT 1/0;
channel name.
+
+ When the parameter listen_transaction_id is enabled, at
+ the begining of a transaction (not a subtransaction) the backend sends a
+ NotificationResponse message containing the transaction ID on the
+ _my_transaction_id channel. This may be useful for the frontend to
+ use after a crash-recovery, to inspect the state of their transaction from
+ before the crash; see pg_xact_status(). Unlike other
+ NotificationResponse messaegs, the process ID in this message is the same as
+ that of the current backend.
+
+
At present, NotificationResponse can only be sent outside a
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 441445927e..e80dfb3a7d 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -68,6 +68,8 @@
#include "utils/timeout.h"
#include "utils/timestamp.h"
+extern char *FullTransactionIdToStr(FullTransactionId fxid);
+
/*
* User-tweakable parameters
*/
@@ -107,6 +109,7 @@ bool bsysscan = false;
* XactTopFullTransactionId stores the XID of our toplevel transaction, which
* will be the same as TopTransactionStateData.fullTransactionId in an
* ordinary backend; but in a parallel backend, which does not have the entire
+ * ordinary backend; but in a parallel backend, which does not have the entire
* transaction state, it will instead be copied from the backend that started
* the parallel operation.
*
@@ -714,6 +717,21 @@ AssignTransactionId(TransactionState s)
TopTransactionStateData.didLogXid = true;
}
}
+
+ // NOTIFY FrontEnd, if it wants to know the top transaction's ID.
+ if (!isSubXact && listen_transaction_id)
+ {
+ char *xidStr;
+
+ Assert(s->parent == NULL);
+
+ // Should we Assert(!IsParallelWorker()) here?
+
+ xidStr = FullTransactionIdToStr(s->fullTransactionId);
+
+ NotifyMyFrontEnd("_my_transaction_id", xidStr, MyProcPid);
+ pfree(xidStr);
+ }
}
/*
@@ -6005,7 +6023,7 @@ xact_redo(XLogReaderState *record)
}
else if (info == XLOG_XACT_COMMIT_PREPARED)
{
- xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
+ xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
xl_xact_parsed_commit parsed;
ParseCommitRecord(XLogRecGetInfo(record), xlrec, &parsed);
diff --git a/src/backend/utils/adt/xid.c b/src/backend/utils/adt/xid.c
index 24c1c93732..755cc53d36 100644
--- a/src/backend/utils/adt/xid.c
+++ b/src/backend/utils/adt/xid.c
@@ -161,13 +161,19 @@ xid8in(PG_FUNCTION_ARGS)
PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(pg_strtouint64(str, NULL, 0)));
}
+char *
+FullTransactionIdToStr(FullTransactionId fxid)
+{
+ char *result = (char *) palloc(21);
+ snprintf(result, 21, UINT64_FORMAT, U64FromFullTransactionId(fxid));
+ return result;
+}
+
Datum
xid8out(PG_FUNCTION_ARGS)
{
FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
- char *result = (char *) palloc(21);
-
- snprintf(result, 21, UINT64_FORMAT, U64FromFullTransactionId(fxid));
+ char *result = FullTransactionIdToStr(fxid);
PG_RETURN_CSTRING(result);
}
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 68b62d523d..1df14b9745 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -947,11 +947,21 @@ static const unit_conversion time_unit_conversion_table[] =
* variable_is_guc_list_quote() in src/bin/pg_dump/dumputils.c.
*/
+bool listen_transaction_id = false;
/******** option records follow ********/
static struct config_bool ConfigureNamesBool[] =
{
+ {
+ {"listen_transaction_id", PGC_USERSET, UNGROUPED,
+ gettext_noop("Emit top-level transaction ID on transaction start."),
+ NULL
+ },
+ &listen_transaction_id,
+ false,
+ NULL, NULL, NULL
+ },
{
{"enable_seqscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of sequential-scan plans."),
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index a7c3a4958e..ed86a7a16d 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -278,6 +278,8 @@ extern int tcp_keepalives_interval;
extern int tcp_keepalives_count;
extern int tcp_user_timeout;
+extern bool listen_transaction_id;
+
#ifdef TRACE_SORT
extern bool trace_sort;
#endif