diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index a632cf98ba..ab4a6e6c7b 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -3008,6 +3008,25 @@ include_dir 'conf.d'
+
+ wal_sessioninfo (boolean)
+
+ wal_sessioninfo configuration parameter
+
+
+
+
+ When this parameter is on, the PostgreSQL
+ server will add information about the user's session onto every
+ commit or abort record. This is intended to provide additional information
+ to trace the changes made by specific sessions, allowing more in-depth
+ investigation during security audits or impact assessment of bugs.
+ The default value is off.
+ Only superusers can change this setting.
+
+
+
+
wal_init_zero (boolean)
diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c
index addd95faec..77af6911e9 100644
--- a/src/backend/access/rmgrdesc/xactdesc.c
+++ b/src/backend/access/rmgrdesc/xactdesc.c
@@ -123,6 +123,20 @@ ParseCommitRecord(uint8 info, xl_xact_commit *xlrec, xl_xact_parsed_commit *pars
data += sizeof(xl_xact_origin);
}
+
+ if (parsed->xinfo & XACT_XINFO_HAS_SESSIONINFO)
+ {
+ xl_xact_sessioninfo xl_sessioninfo;
+
+ /* no alignment is guaranteed, so copy onto stack */
+ memcpy(&xl_sessioninfo, data, sizeof(xl_sessioninfo));
+
+ parsed->session_start_time = xl_sessioninfo.session_start_time;
+ parsed->session_pid = xl_sessioninfo.session_pid;
+ parsed->userid = xl_sessioninfo.userid;
+
+ data += sizeof(xl_xact_sessioninfo);
+ }
}
void
@@ -207,6 +221,20 @@ ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed)
data += sizeof(xl_xact_origin);
}
+
+ if (parsed->xinfo & XACT_XINFO_HAS_SESSIONINFO)
+ {
+ xl_xact_sessioninfo xl_sessioninfo;
+
+ /* no alignment is guaranteed, so copy onto stack */
+ memcpy(&xl_sessioninfo, data, sizeof(xl_sessioninfo));
+
+ parsed->session_start_time = xl_sessioninfo.session_start_time;
+ parsed->session_pid = xl_sessioninfo.session_pid;
+ parsed->userid = xl_sessioninfo.userid;
+
+ data += sizeof(xl_xact_sessioninfo);
+ }
}
/*
@@ -310,6 +338,14 @@ xact_desc_commit(StringInfo buf, uint8 info, xl_xact_commit *xlrec, RepOriginId
(uint32) parsed.origin_lsn,
timestamptz_to_str(parsed.origin_timestamp));
}
+
+ if (parsed.xinfo & XACT_XINFO_HAS_SESSIONINFO)
+ {
+ appendStringInfo(buf, "; session: pid %u, start at %s userid %u",
+ parsed.session_pid,
+ timestamptz_to_str(parsed.session_start_time),
+ parsed.userid);
+ }
}
static void
@@ -327,6 +363,14 @@ xact_desc_abort(StringInfo buf, uint8 info, xl_xact_abort *xlrec)
xact_desc_relations(buf, "rels", parsed.nrels, parsed.xnodes);
xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts);
+
+ if (parsed.xinfo & XACT_XINFO_HAS_SESSIONINFO)
+ {
+ appendStringInfo(buf, "; session: pid %u, start at %s userid %u",
+ parsed.session_pid,
+ timestamptz_to_str(parsed.session_start_time),
+ parsed.userid);
+ }
}
static void
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 03c553e7ea..83022e28f8 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -82,6 +82,8 @@ bool XactDeferrable;
int synchronous_commit = SYNCHRONOUS_COMMIT_ON;
+bool wal_sessioninfo = false;
+
/*
* CheckXidAlive is a xid value pointing to a possibly ongoing (sub)
* transaction. Currently, it is used in logical decoding. It's possible
@@ -5515,6 +5517,7 @@ XactLogCommitRecord(TimestampTz commit_time,
xl_xact_invals xl_invals;
xl_xact_twophase xl_twophase;
xl_xact_origin xl_origin;
+ xl_xact_sessioninfo xl_sessioninfo;
uint8 info;
Assert(CritSectionCount > 0);
@@ -5594,6 +5597,15 @@ XactLogCommitRecord(TimestampTz commit_time,
xl_origin.origin_timestamp = replorigin_session_origin_timestamp;
}
+ if (wal_sessioninfo)
+ {
+ xl_xinfo.xinfo |= XACT_XINFO_HAS_SESSIONINFO;
+
+ xl_sessioninfo.session_start_time = MyStartTimestamp;
+ xl_sessioninfo.session_pid = MyProcPid;
+ xl_sessioninfo.userid = GetUserId();
+ }
+
if (xl_xinfo.xinfo != 0)
info |= XLOG_XACT_HAS_INFO;
@@ -5642,6 +5654,9 @@ XactLogCommitRecord(TimestampTz commit_time,
if (xl_xinfo.xinfo & XACT_XINFO_HAS_ORIGIN)
XLogRegisterData((char *) (&xl_origin), sizeof(xl_xact_origin));
+ if (xl_xinfo.xinfo & XACT_XINFO_HAS_SESSIONINFO)
+ XLogRegisterData((char *) (&xl_sessioninfo), sizeof(xl_xact_sessioninfo));
+
/* we allow filtering by xacts */
XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
@@ -5668,6 +5683,7 @@ XactLogAbortRecord(TimestampTz abort_time,
xl_xact_twophase xl_twophase;
xl_xact_dbinfo xl_dbinfo;
xl_xact_origin xl_origin;
+ xl_xact_sessioninfo xl_sessioninfo;
uint8 info;
@@ -5730,6 +5746,15 @@ XactLogAbortRecord(TimestampTz abort_time,
xl_origin.origin_timestamp = replorigin_session_origin_timestamp;
}
+ if (wal_sessioninfo)
+ {
+ xl_xinfo.xinfo |= XACT_XINFO_HAS_SESSIONINFO;
+
+ xl_sessioninfo.session_start_time = MyStartTimestamp;
+ xl_sessioninfo.session_pid = MyProcPid;
+ xl_sessioninfo.userid = GetUserId();
+ }
+
if (xl_xinfo.xinfo != 0)
info |= XLOG_XACT_HAS_INFO;
@@ -5771,6 +5796,9 @@ XactLogAbortRecord(TimestampTz abort_time,
if (xl_xinfo.xinfo & XACT_XINFO_HAS_ORIGIN)
XLogRegisterData((char *) (&xl_origin), sizeof(xl_xact_origin));
+ if (xl_xinfo.xinfo & XACT_XINFO_HAS_SESSIONINFO)
+ XLogRegisterData((char *) (&xl_sessioninfo), sizeof(xl_xact_sessioninfo));
+
if (TransactionIdIsValid(twophase_xid))
XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
@@ -5870,6 +5898,8 @@ xact_redo_commit(xl_xact_parsed_commit *parsed,
false /* backward */ , false /* WAL */ );
}
+ /* No action if XACT_INFO_HAS_SESSIONINFO */
+
/* Make sure files supposed to be dropped are dropped */
if (parsed->nrels > 0)
{
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index bb34630e8e..c69754531d 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -130,6 +130,7 @@ extern char *temp_tablespaces;
extern bool ignore_checksum_failure;
extern bool ignore_invalid_pages;
extern bool synchronize_seqscans;
+extern bool wal_sessioninfo;
#ifdef TRACE_SYNCSCAN
extern bool trace_syncscan;
@@ -1269,6 +1270,16 @@ static struct config_bool ConfigureNamesBool[] =
NULL, NULL, NULL
},
+ {
+ {"wal_sessioninfo", PGC_SUSET, WAL_SETTINGS,
+ gettext_noop("Includes sessionfo onto the WAL records for transaction completion."),
+ NULL
+ },
+ &wal_sessioninfo,
+ true,
+ NULL, NULL, NULL
+ },
+
{
{"wal_init_zero", PGC_SUSET, WAL_SETTINGS,
gettext_noop("Writes zeroes to new WAL files before first use."),
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 7320de345c..533be43950 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -172,6 +172,7 @@ typedef void (*SubXactCallback) (SubXactEvent event, SubTransactionId mySubid,
#define XACT_XINFO_HAS_ORIGIN (1U << 5)
#define XACT_XINFO_HAS_AE_LOCKS (1U << 6)
#define XACT_XINFO_HAS_GID (1U << 7)
+#define XACT_XINFO_HAS_SESSIONINFO (1U << 8)
/*
* Also stored in xinfo, these indicating a variety of additional actions that
@@ -267,6 +268,13 @@ typedef struct xl_xact_origin
TimestampTz origin_timestamp;
} xl_xact_origin;
+typedef struct xl_xact_sessioninfo
+{
+ TimestampTz session_start_time;
+ int session_pid;
+ Oid userid;
+} xl_xact_sessioninfo;
+
typedef struct xl_xact_commit
{
TimestampTz xact_time; /* time of commit */
@@ -279,6 +287,7 @@ typedef struct xl_xact_commit
/* xl_xact_twophase follows if XINFO_HAS_TWOPHASE */
/* twophase_gid follows if XINFO_HAS_GID. As a null-terminated string. */
/* xl_xact_origin follows if XINFO_HAS_ORIGIN, stored unaligned! */
+ /* xl_xact_sessioninfo follows if XINFO_HAS_SESSIONINFO */
} xl_xact_commit;
#define MinSizeOfXactCommit (offsetof(xl_xact_commit, xact_time) + sizeof(TimestampTz))
@@ -294,6 +303,7 @@ typedef struct xl_xact_abort
/* xl_xact_twophase follows if XINFO_HAS_TWOPHASE */
/* twophase_gid follows if XINFO_HAS_GID. As a null-terminated string. */
/* xl_xact_origin follows if XINFO_HAS_ORIGIN, stored unaligned! */
+ /* xl_xact_sessioninfo follows if XINFO_HAS_SESSIONINFO */
} xl_xact_abort;
#define MinSizeOfXactAbort sizeof(xl_xact_abort)
@@ -344,6 +354,10 @@ typedef struct xl_xact_parsed_commit
XLogRecPtr origin_lsn;
TimestampTz origin_timestamp;
+
+ TimestampTz session_start_time;
+ int session_pid;
+ Oid userid;
} xl_xact_parsed_commit;
typedef xl_xact_parsed_commit xl_xact_parsed_prepare;
@@ -367,6 +381,10 @@ typedef struct xl_xact_parsed_abort
XLogRecPtr origin_lsn;
TimestampTz origin_timestamp;
+
+ TimestampTz session_start_time;
+ int session_pid;
+ Oid userid;
} xl_xact_parsed_abort;