Commit 4aaddf2f authored by Alvaro Herrera's avatar Alvaro Herrera

Fix commit_ts for FrozenXid and BootstrapXid

Previously, requesting commit timestamp for transactions
FrozenTransactionId and BootstrapTransactionId resulted in an error.
But since those values can validly appear in committed tuples' Xmin,
this behavior is unhelpful and error prone: each caller would have to
special-case those values before requesting timestamp data for an Xid.
We already have a perfectly good interface for returning "the Xid you
requested is too old for us to have commit TS data for it", so let's use
that instead.

Backpatch to 9.5, where commit timestamps appeared.

Author: Craig Ringer
Discussion: https://www.postgresql.org/message-id/CAMsr+YFM5Q=+ry3mKvWEqRTxrB0iU3qUSRnS28nz6FJYtBwhJg@mail.gmail.com
parent 6fa391be
...@@ -289,11 +289,18 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts, ...@@ -289,11 +289,18 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
TransactionId oldestCommitTsXid; TransactionId oldestCommitTsXid;
TransactionId newestCommitTsXid; TransactionId newestCommitTsXid;
/* error if the given Xid doesn't normally commit */ if (!TransactionIdIsValid(xid))
if (!TransactionIdIsNormal(xid))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot retrieve commit timestamp for transaction %u", xid))); errmsg("cannot retrieve commit timestamp for transaction %u", xid)));
else if (!TransactionIdIsNormal(xid))
{
/* frozen and bootstrap xids are always committed far in the past */
*ts = 0;
if (nodeid)
*nodeid = 0;
return false;
}
LWLockAcquire(CommitTsLock, LW_SHARED); LWLockAcquire(CommitTsLock, LW_SHARED);
......
...@@ -28,9 +28,17 @@ DROP TABLE committs_test; ...@@ -28,9 +28,17 @@ DROP TABLE committs_test;
SELECT pg_xact_commit_timestamp('0'::xid); SELECT pg_xact_commit_timestamp('0'::xid);
ERROR: cannot retrieve commit timestamp for transaction 0 ERROR: cannot retrieve commit timestamp for transaction 0
SELECT pg_xact_commit_timestamp('1'::xid); SELECT pg_xact_commit_timestamp('1'::xid);
ERROR: cannot retrieve commit timestamp for transaction 1 pg_xact_commit_timestamp
--------------------------
(1 row)
SELECT pg_xact_commit_timestamp('2'::xid); SELECT pg_xact_commit_timestamp('2'::xid);
ERROR: cannot retrieve commit timestamp for transaction 2 pg_xact_commit_timestamp
--------------------------
(1 row)
SELECT x.xid::text::bigint > 0, x.timestamp > '-infinity'::timestamptz, x.timestamp <= now() FROM pg_last_committed_xact() x; SELECT x.xid::text::bigint > 0, x.timestamp > '-infinity'::timestamptz, x.timestamp <= now() FROM pg_last_committed_xact() x;
?column? | ?column? | ?column? ?column? | ?column? | ?column?
----------+----------+---------- ----------+----------+----------
......
...@@ -23,9 +23,17 @@ DROP TABLE committs_test; ...@@ -23,9 +23,17 @@ DROP TABLE committs_test;
SELECT pg_xact_commit_timestamp('0'::xid); SELECT pg_xact_commit_timestamp('0'::xid);
ERROR: cannot retrieve commit timestamp for transaction 0 ERROR: cannot retrieve commit timestamp for transaction 0
SELECT pg_xact_commit_timestamp('1'::xid); SELECT pg_xact_commit_timestamp('1'::xid);
ERROR: cannot retrieve commit timestamp for transaction 1 pg_xact_commit_timestamp
--------------------------
(1 row)
SELECT pg_xact_commit_timestamp('2'::xid); SELECT pg_xact_commit_timestamp('2'::xid);
ERROR: cannot retrieve commit timestamp for transaction 2 pg_xact_commit_timestamp
--------------------------
(1 row)
SELECT x.xid::text::bigint > 0, x.timestamp > '-infinity'::timestamptz, x.timestamp <= now() FROM pg_last_committed_xact() x; SELECT x.xid::text::bigint > 0, x.timestamp > '-infinity'::timestamptz, x.timestamp <= now() FROM pg_last_committed_xact() x;
ERROR: could not get commit timestamp data ERROR: could not get commit timestamp data
HINT: Make sure the configuration parameter "track_commit_timestamp" is set. HINT: Make sure the configuration parameter "track_commit_timestamp" is set.
...@@ -25,19 +25,13 @@ like( ...@@ -25,19 +25,13 @@ like(
($ret, $stdout, $stderr) = ($ret, $stdout, $stderr) =
$node_master->psql('postgres', qq[SELECT pg_xact_commit_timestamp('1');]); $node_master->psql('postgres', qq[SELECT pg_xact_commit_timestamp('1');]);
is($ret, 3, 'getting ts of BootstrapTransactionId reports error'); is($ret, 0, 'getting ts of BootstrapTransactionId succeeds');
like( is($stdout, '', 'timestamp of BootstrapTransactionId is null');
$stderr,
qr/cannot retrieve commit timestamp for transaction/,
'expected error from BootstrapTransactionId');
($ret, $stdout, $stderr) = ($ret, $stdout, $stderr) =
$node_master->psql('postgres', qq[SELECT pg_xact_commit_timestamp('2');]); $node_master->psql('postgres', qq[SELECT pg_xact_commit_timestamp('2');]);
is($ret, 3, 'getting ts of FrozenTransactionId reports error'); is($ret, 0, 'getting ts of FrozenTransactionId succeeds');
like( is($stdout, '', 'timestamp of FrozenTransactionId is null');
$stderr,
qr/cannot retrieve commit timestamp for transaction/,
'expected error from FrozenTransactionId');
# Since FirstNormalTransactionId will've occurred during initdb, long before we # Since FirstNormalTransactionId will've occurred during initdb, long before we
# enabled commit timestamps, it'll be null since we have no cts data for it but # enabled commit timestamps, it'll be null since we have no cts data for it but
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment