public inbox for [email protected]help / color / mirror / Atom feed
Re: Use pg_current_xact_id() instead of deprecated txid_current() 4+ messages / 2 participants [nested] [flat]
* Re: Use pg_current_xact_id() instead of deprecated txid_current() @ 2026-02-09 12:07 Shinya Kato <[email protected]> 0 siblings, 1 reply; 4+ messages in thread From: Shinya Kato @ 2026-02-09 12:07 UTC (permalink / raw) To: Tom Lane <[email protected]>; +Cc: Álvaro Herrera <[email protected]>; pgsql-hackers <[email protected]> On Mon, Feb 9, 2026 at 1:24 AM Tom Lane <[email protected]> wrote: > > =?UTF-8?Q?=C3=81lvaro_Herrera?= <[email protected]> writes: > > On 2026-02-08, Shinya Kato wrote: > >> Since pg_current_xact_id() returns xid8 which does not support > >> arithmetic operators, places that need "xid + 1" cast the result via > >> ::text::bigint first. > > > I think it may be better to add some operators, or was there a rationale for these not being there? > > I'm fairly concerned about overloading the arithmetic operators with > unsigned versions. The reason we never invented SQL-level uint8 and > such is fear of getting a lot of "ambiguous operator" errors. Now, > if we are careful not to create implicit casts between xid[8] and > any ordinary type, maybe it'd be okay to invent xid+int, xid8-int, > and a few more. Got it. I’ll give it a try, thanks. > As things stand, I don't find the proposed patch to be an improvement. I agree that casting xid8 to bigint was not the right approach. However, I still believe it's important to move away from using deprecated functions. -- Best regards, Shinya Kato NTT OSS Center ^ permalink raw reply [nested|flat] 4+ messages in thread
* Re: Use pg_current_xact_id() instead of deprecated txid_current() @ 2026-02-10 06:38 Shinya Kato <[email protected]> parent: Shinya Kato <[email protected]> 0 siblings, 1 reply; 4+ messages in thread From: Shinya Kato @ 2026-02-10 06:38 UTC (permalink / raw) To: Tom Lane <[email protected]>; +Cc: Álvaro Herrera <[email protected]>; pgsql-hackers <[email protected]> On Mon, Feb 9, 2026 at 9:07 PM Shinya Kato <[email protected]> wrote: > > On Mon, Feb 9, 2026 at 1:24 AM Tom Lane <[email protected]> wrote: > > > > =?UTF-8?Q?=C3=81lvaro_Herrera?= <[email protected]> writes: > > > On 2026-02-08, Shinya Kato wrote: > > >> Since pg_current_xact_id() returns xid8 which does not support > > >> arithmetic operators, places that need "xid + 1" cast the result via > > >> ::text::bigint first. > > > > > I think it may be better to add some operators, or was there a rationale for these not being there? > > > > I'm fairly concerned about overloading the arithmetic operators with > > unsigned versions. The reason we never invented SQL-level uint8 and > > such is fear of getting a lot of "ambiguous operator" errors. Now, > > if we are careful not to create implicit casts between xid[8] and > > any ordinary type, maybe it'd be okay to invent xid+int, xid8-int, > > and a few more. > > Got it. I’ll give it a try, thanks. I have added the + and - operators for the xid8 type in the v2-0001 patch. This allows for direct arithmetic and eliminates the need for casting through text and bigint. Specifically, I implemented: xid8 + int8 -> xid8 int8 + xid8 -> xid8 xid8 - int8 -> xid8 xid8 - xid8 -> int8 Additionally, the v2-0002 patch removes the existing ::text::bigint casts where they are no longer necessary. -- Best regards, Shinya Kato NTT OSS Center Attachments: [application/octet-stream] v2-0001-Add-arithmetic-operators-for-xid8.patch (8.1K, 2-v2-0001-Add-arithmetic-operators-for-xid8.patch) download | inline diff: From ff32629101f326bcd66f9c24c03537982c636c01 Mon Sep 17 00:00:00 2001 From: Shinya Kato <[email protected]> Date: Mon, 9 Feb 2026 13:35:07 +0900 Subject: [PATCH v2 1/2] Add arithmetic operators for xid8 Add +, - operators for xid8 type to allow direct arithmetic without the need for casting through text and bigint: xid8 + int8 -> xid8 int8 + xid8 -> xid8 xid8 - int8 -> xid8 xid8 - xid8 -> int8 These operators follow the same pattern as the existing pg_lsn arithmetic operators. Since there are no implicit casts between xid8 and any ordinary numeric type, this avoids the "ambiguous operator" concern. Author: Shinya Kato <[email protected]> Reviewed-by: Discussion: https://postgr.es/m/CAOzEurQetW=-1+OnMo8baeVQF=-kAr-wNtFcgRNo+ErPk=xsDQ@mail.gmail.com --- src/backend/catalog/system_functions.sql | 6 +++ src/backend/utils/adt/xid.c | 64 ++++++++++++++++++++++++ src/include/catalog/pg_operator.dat | 12 +++++ src/include/catalog/pg_proc.dat | 13 +++++ src/test/regress/expected/xid.out | 46 +++++++++++++++++ src/test/regress/sql/xid.sql | 14 ++++++ 6 files changed, 155 insertions(+) diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql index eb9e31ae1bf..7aee4e3e65d 100644 --- a/src/backend/catalog/system_functions.sql +++ b/src/backend/catalog/system_functions.sql @@ -103,6 +103,12 @@ CREATE OR REPLACE FUNCTION numeric_pl_pg_lsn(numeric, pg_lsn) IMMUTABLE PARALLEL SAFE STRICT COST 1 RETURN $2 + $1; +CREATE OR REPLACE FUNCTION int8_pl_xid8(bigint, xid8) + RETURNS xid8 + LANGUAGE sql + IMMUTABLE PARALLEL SAFE STRICT COST 1 +RETURN $2 + $1; + CREATE OR REPLACE FUNCTION path_contain_pt(path, point) RETURNS boolean LANGUAGE sql diff --git a/src/backend/utils/adt/xid.c b/src/backend/utils/adt/xid.c index f746a5f97dd..2b770e011cd 100644 --- a/src/backend/utils/adt/xid.c +++ b/src/backend/utils/adt/xid.c @@ -312,6 +312,70 @@ hashxid8extended(PG_FUNCTION_ARGS) return hashint8extended(fcinfo); } +Datum +xid8pl(PG_FUNCTION_ARGS) +{ + FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0); + int64 delta = PG_GETARG_INT64(1); + uint64 val = U64FromFullTransactionId(fxid); + uint64 result; + + result = val + (uint64) delta; + + /* Check for over/underflow */ + if ((delta > 0 && result < val) || (delta < 0 && result > val)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("xid8 out of range"))); + + PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(result)); +} + +Datum +xid8mi(PG_FUNCTION_ARGS) +{ + FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0); + int64 delta = PG_GETARG_INT64(1); + uint64 val = U64FromFullTransactionId(fxid); + uint64 result; + + result = val - (uint64) delta; + + /* Check for over/underflow */ + if ((delta > 0 && result > val) || (delta < 0 && result < val)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("xid8 out of range"))); + + PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(result)); +} + +Datum +xid8_mi_xid8(PG_FUNCTION_ARGS) +{ + FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0); + FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1); + uint64 val1 = U64FromFullTransactionId(fxid1); + uint64 val2 = U64FromFullTransactionId(fxid2); + + if (val1 >= val2) + { + if (val1 - val2 > (uint64) PG_INT64_MAX) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64((int64) (val1 - val2)); + } + else + { + if (val2 - val1 > (uint64) PG_INT64_MAX + 1) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(-((int64) (val2 - val1))); + } +} + Datum xid8_larger(PG_FUNCTION_ARGS) { diff --git a/src/include/catalog/pg_operator.dat b/src/include/catalog/pg_operator.dat index 1465f13120a..4cc38e7e294 100644 --- a/src/include/catalog/pg_operator.dat +++ b/src/include/catalog/pg_operator.dat @@ -219,6 +219,18 @@ oprname => '>=', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool', oprcom => '<=(xid8,xid8)', oprnegate => '<(xid8,xid8)', oprcode => 'xid8ge', oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '5107', descr => 'add', + oprname => '+', oprleft => 'xid8', oprright => 'int8', oprresult => 'xid8', + oprcom => '+(int8,xid8)', oprcode => 'xid8pl' }, +{ oid => '5108', descr => 'add', + oprname => '+', oprleft => 'int8', oprright => 'xid8', oprresult => 'xid8', + oprcom => '+(xid8,int8)', oprcode => 'int8_pl_xid8' }, +{ oid => '5109', descr => 'subtract', + oprname => '-', oprleft => 'xid8', oprright => 'int8', oprresult => 'xid8', + oprcode => 'xid8mi' }, +{ oid => '5110', descr => 'subtract', + oprname => '-', oprleft => 'xid8', oprright => 'xid8', oprresult => 'int8', + oprcode => 'xid8_mi_xid8' }, { oid => '385', descr => 'equal', oprname => '=', oprcanhash => 't', oprleft => 'cid', oprright => 'cid', oprresult => 'bool', oprcom => '=(cid,cid)', oprcode => 'cideq', diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 83f6501df38..f9c9690a376 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -209,6 +209,19 @@ { oid => '5098', descr => 'smaller of two', proname => 'xid8_smaller', prorettype => 'xid8', proargtypes => 'xid8 xid8', prosrc => 'xid8_smaller' }, +{ oid => '5101', + proname => 'xid8pl', prorettype => 'xid8', proargtypes => 'xid8 int8', + prosrc => 'xid8pl' }, +{ oid => '5102', + proname => 'xid8mi', prorettype => 'xid8', proargtypes => 'xid8 int8', + prosrc => 'xid8mi' }, +{ oid => '5103', + proname => 'xid8_mi_xid8', prorettype => 'int8', proargtypes => 'xid8 xid8', + prosrc => 'xid8_mi_xid8' }, +{ oid => '5106', + proname => 'int8_pl_xid8', prolang => 'sql', + prorettype => 'xid8', proargtypes => 'int8 xid8', + prosrc => 'see system_functions.sql' }, { oid => '69', proname => 'cideq', proleakproof => 't', prorettype => 'bool', proargtypes => 'cid cid', prosrc => 'cideq' }, diff --git a/src/test/regress/expected/xid.out b/src/test/regress/expected/xid.out index 1ce7826cf90..4d5f4006072 100644 --- a/src/test/regress/expected/xid.out +++ b/src/test/regress/expected/xid.out @@ -175,6 +175,52 @@ select min(x), max(x) from xid8_t1; create index on xid8_t1 using btree(x); create index on xid8_t1 using hash(x); drop table xid8_t1; +-- xid8 arithmetic operators +select '42'::xid8 + 3::bigint; + ?column? +---------- + 45 +(1 row) + +select 3::bigint + '42'::xid8; + ?column? +---------- + 45 +(1 row) + +select '42'::xid8 - 3::bigint; + ?column? +---------- + 39 +(1 row) + +select '100'::xid8 - '42'::xid8; + ?column? +---------- + 58 +(1 row) + +select '42'::xid8 + (-3)::bigint; + ?column? +---------- + 39 +(1 row) + +select '42'::xid8 - (-3)::bigint; + ?column? +---------- + 45 +(1 row) + +-- xid8 arithmetic overflow/underflow +select '0'::xid8 - 1::bigint; +ERROR: xid8 out of range +select '18446744073709551615'::xid8 + 1::bigint; +ERROR: xid8 out of range +select '18446744073709551615'::xid8 - '0'::xid8; +ERROR: bigint out of range +select '0'::xid8 - '18446744073709551615'::xid8; +ERROR: bigint out of range -- pg_snapshot data type and related functions -- Note: another set of tests similar to this exists in txid.sql, for a limited -- time (the relevant functions share C code) diff --git a/src/test/regress/sql/xid.sql b/src/test/regress/sql/xid.sql index 9f716b3653a..f6bacc04428 100644 --- a/src/test/regress/sql/xid.sql +++ b/src/test/regress/sql/xid.sql @@ -59,6 +59,20 @@ create index on xid8_t1 using btree(x); create index on xid8_t1 using hash(x); drop table xid8_t1; +-- xid8 arithmetic operators +select '42'::xid8 + 3::bigint; +select 3::bigint + '42'::xid8; +select '42'::xid8 - 3::bigint; +select '100'::xid8 - '42'::xid8; +select '42'::xid8 + (-3)::bigint; +select '42'::xid8 - (-3)::bigint; + +-- xid8 arithmetic overflow/underflow +select '0'::xid8 - 1::bigint; +select '18446744073709551615'::xid8 + 1::bigint; +select '18446744073709551615'::xid8 - '0'::xid8; +select '0'::xid8 - '18446744073709551615'::xid8; + -- pg_snapshot data type and related functions -- 2.47.3 [application/octet-stream] v2-0002-Use-pg_current_xact_id-instead-of-deprecated-txid.patch (13.2K, 3-v2-0002-Use-pg_current_xact_id-instead-of-deprecated-txid.patch) download | inline diff: From ce14e4386376cef4c0cc19ffa42c6ac2468ca225 Mon Sep 17 00:00:00 2001 From: Shinya Kato <[email protected]> Date: Tue, 10 Feb 2026 13:54:01 +0900 Subject: [PATCH v2 2/2] Use pg_current_xact_id() instead of deprecated txid_current() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace txid_current() with pg_current_xact_id() in test code. The previous commit added arithmetic operators for xid8, so places that need "xid + 1" can now use pg_current_xact_id() + 1 directly. Author: Shinya Kato <[email protected]> Reviewed-by: Álvaro Herrera <[email protected]> Reviewed-by: Tom Lane <[email protected]> Discussion: https://postgr.es/m/CAOzEurQetW=-1+OnMo8baeVQF=-kAr-wNtFcgRNo+ErPk=xsDQ@mail.gmail.com --- contrib/pg_visibility/t/001_concurrent_transaction.pl | 2 +- contrib/test_decoding/expected/slot_creation_error.out | 6 +++--- contrib/test_decoding/specs/slot_creation_error.spec | 2 +- src/bin/pg_combinebackup/t/002_compare_backups.pl | 4 ++-- src/test/modules/commit_ts/expected/commit_timestamp.out | 4 ++-- .../modules/commit_ts/expected/commit_timestamp_1.out | 4 ++-- src/test/modules/commit_ts/sql/commit_timestamp.sql | 4 ++-- src/test/modules/xid_wraparound/t/004_notify_freeze.pl | 4 ++-- src/test/recovery/t/021_row_visibility.pl | 2 +- src/test/recovery/t/031_recovery_conflict.pl | 2 +- src/test/recovery/t/040_standby_failover_slots_sync.pl | 4 ++-- src/test/regress/expected/create_index.out | 2 +- src/test/regress/sql/create_index.sql | 2 +- src/test/subscription/t/035_conflicts.pl | 8 ++++---- 14 files changed, 25 insertions(+), 25 deletions(-) diff --git a/contrib/pg_visibility/t/001_concurrent_transaction.pl b/contrib/pg_visibility/t/001_concurrent_transaction.pl index 3aa556892a6..889cae927fd 100644 --- a/contrib/pg_visibility/t/001_concurrent_transaction.pl +++ b/contrib/pg_visibility/t/001_concurrent_transaction.pl @@ -30,7 +30,7 @@ my $bsession = $node->background_psql('other_database'); $bsession->query_safe( qq[ BEGIN; - SELECT txid_current(); + SELECT pg_current_xact_id(); ]); # Create a sample table and run vacuum diff --git a/contrib/test_decoding/expected/slot_creation_error.out b/contrib/test_decoding/expected/slot_creation_error.out index 25883b508fb..95591752371 100644 --- a/contrib/test_decoding/expected/slot_creation_error.out +++ b/contrib/test_decoding/expected/slot_creation_error.out @@ -2,7 +2,7 @@ Parsed test spec with 2 sessions starting permutation: s1_b s1_xid s2_init s1_view_slot s1_cancel_s2 s1_view_slot s1_c step s1_b: BEGIN; -step s1_xid: SELECT 'xid' FROM txid_current(); +step s1_xid: SELECT 'xid' FROM pg_current_xact_id(); ?column? -------- xid @@ -43,7 +43,7 @@ step s1_c: COMMIT; starting permutation: s1_b s1_xid s2_init s1_c s1_view_slot s1_drop_slot step s1_b: BEGIN; -step s1_xid: SELECT 'xid' FROM txid_current(); +step s1_xid: SELECT 'xid' FROM pg_current_xact_id(); ?column? -------- xid @@ -78,7 +78,7 @@ pg_drop_replication_slot starting permutation: s1_b s1_xid s2_init s1_terminate_s2 s1_c s1_view_slot step s1_b: BEGIN; -step s1_xid: SELECT 'xid' FROM txid_current(); +step s1_xid: SELECT 'xid' FROM pg_current_xact_id(); ?column? -------- xid diff --git a/contrib/test_decoding/specs/slot_creation_error.spec b/contrib/test_decoding/specs/slot_creation_error.spec index d1e35bf58b5..6983f24eae6 100644 --- a/contrib/test_decoding/specs/slot_creation_error.spec +++ b/contrib/test_decoding/specs/slot_creation_error.spec @@ -4,7 +4,7 @@ session "s1" setup { SET synchronous_commit=on; } step s1_b { BEGIN; } -step s1_xid { SELECT 'xid' FROM txid_current(); } +step s1_xid { SELECT 'xid' FROM pg_current_xact_id(); } step s1_c { COMMIT; } step s1_cancel_s2 { SELECT pg_cancel_backend(pid) diff --git a/src/bin/pg_combinebackup/t/002_compare_backups.pl b/src/bin/pg_combinebackup/t/002_compare_backups.pl index b509296a94a..42d252b2242 100644 --- a/src/bin/pg_combinebackup/t/002_compare_backups.pl +++ b/src/bin/pg_combinebackup/t/002_compare_backups.pl @@ -105,9 +105,9 @@ my $lsn = $primary->safe_psql('postgres', "SELECT pg_current_wal_lsn();"); # Make sure that the WAL segment containing that LSN has been archived. # PostgreSQL won't issue two consecutive XLOG_SWITCH records, and the backup -# just issued one, so call txid_current() to generate some WAL activity +# just issued one, so call pg_current_xact_id() to generate some WAL activity # before calling pg_switch_wal(). -$primary->safe_psql('postgres', 'SELECT txid_current();'); +$primary->safe_psql('postgres', 'SELECT pg_current_xact_id();'); $primary->safe_psql('postgres', 'SELECT pg_switch_wal()'); # Now wait for the LSN we chose above to be archived. diff --git a/src/test/modules/commit_ts/expected/commit_timestamp.out b/src/test/modules/commit_ts/expected/commit_timestamp.out index bb2fda27681..0d08e0684a2 100644 --- a/src/test/modules/commit_ts/expected/commit_timestamp.out +++ b/src/test/modules/commit_ts/expected/commit_timestamp.out @@ -71,7 +71,7 @@ SELECT * FROM pg_xact_commit_timestamp_origin('2'::xid); -- ok, NULL (1 row) -- Test transaction without replication origin -SELECT txid_current() as txid_no_origin \gset +SELECT pg_current_xact_id() as txid_no_origin \gset SELECT x.timestamp > '-infinity'::timestamptz AS ts_low, x.timestamp <= now() AS ts_high, roident != 0 AS valid_roident @@ -104,7 +104,7 @@ SELECT pg_replication_origin_session_setup('regress_commit_ts: get_origin'); (1 row) -SELECT txid_current() as txid_with_origin \gset +SELECT pg_current_xact_id() as txid_with_origin \gset SELECT x.timestamp > '-infinity'::timestamptz AS ts_low, x.timestamp <= now() AS ts_high, r.roname diff --git a/src/test/modules/commit_ts/expected/commit_timestamp_1.out b/src/test/modules/commit_ts/expected/commit_timestamp_1.out index f37e701f37a..21f09b89cac 100644 --- a/src/test/modules/commit_ts/expected/commit_timestamp_1.out +++ b/src/test/modules/commit_ts/expected/commit_timestamp_1.out @@ -63,7 +63,7 @@ SELECT * FROM pg_xact_commit_timestamp_origin('2'::xid); -- ok, NULL (1 row) -- Test transaction without replication origin -SELECT txid_current() as txid_no_origin \gset +SELECT pg_current_xact_id() as txid_no_origin \gset SELECT x.timestamp > '-infinity'::timestamptz AS ts_low, x.timestamp <= now() AS ts_high, roident != 0 AS valid_roident @@ -90,7 +90,7 @@ SELECT pg_replication_origin_session_setup('regress_commit_ts: get_origin'); (1 row) -SELECT txid_current() as txid_with_origin \gset +SELECT pg_current_xact_id() as txid_with_origin \gset SELECT x.timestamp > '-infinity'::timestamptz AS ts_low, x.timestamp <= now() AS ts_high, r.roname diff --git a/src/test/modules/commit_ts/sql/commit_timestamp.sql b/src/test/modules/commit_ts/sql/commit_timestamp.sql index 3bb7bb27a74..a2f0e68317d 100644 --- a/src/test/modules/commit_ts/sql/commit_timestamp.sql +++ b/src/test/modules/commit_ts/sql/commit_timestamp.sql @@ -34,7 +34,7 @@ SELECT * FROM pg_xact_commit_timestamp_origin('1'::xid); -- ok, NULL SELECT * FROM pg_xact_commit_timestamp_origin('2'::xid); -- ok, NULL -- Test transaction without replication origin -SELECT txid_current() as txid_no_origin \gset +SELECT pg_current_xact_id() as txid_no_origin \gset SELECT x.timestamp > '-infinity'::timestamptz AS ts_low, x.timestamp <= now() AS ts_high, roident != 0 AS valid_roident @@ -48,7 +48,7 @@ SELECT x.timestamp > '-infinity'::timestamptz AS ts_low, SELECT pg_replication_origin_create('regress_commit_ts: get_origin') != 0 AS valid_roident; SELECT pg_replication_origin_session_setup('regress_commit_ts: get_origin'); -SELECT txid_current() as txid_with_origin \gset +SELECT pg_current_xact_id() as txid_with_origin \gset SELECT x.timestamp > '-infinity'::timestamptz AS ts_low, x.timestamp <= now() AS ts_high, r.roname diff --git a/src/test/modules/xid_wraparound/t/004_notify_freeze.pl b/src/test/modules/xid_wraparound/t/004_notify_freeze.pl index d0a1f1fe2fc..9a8300186f7 100644 --- a/src/test/modules/xid_wraparound/t/004_notify_freeze.pl +++ b/src/test/modules/xid_wraparound/t/004_notify_freeze.pl @@ -35,9 +35,9 @@ for my $i (1 .. 10) } # Consume enough XIDs to trigger truncation, and one more with -# 'txid_current' to bump up the freeze horizon. +# 'pg_current_xact_id' to bump up the freeze horizon. $node->safe_psql('postgres', 'select consume_xids(10000000);'); -$node->safe_psql('postgres', 'select txid_current()'); +$node->safe_psql('postgres', 'select pg_current_xact_id()'); # Remember current datfrozenxid before vacuum freeze so that we can # check that it is advanced. (Taking the min() this way assumes that diff --git a/src/test/recovery/t/021_row_visibility.pl b/src/test/recovery/t/021_row_visibility.pl index 0a4d22b3698..9626d431852 100644 --- a/src/test/recovery/t/021_row_visibility.pl +++ b/src/test/recovery/t/021_row_visibility.pl @@ -94,7 +94,7 @@ UPDATE test_visibility SET data = 'first update' RETURNING data; qr/^UPDATE 1$/m), 'UPDATE'); -$node_primary->psql('postgres', "SELECT txid_current();"); # ensure WAL flush +$node_primary->psql('postgres', "SELECT pg_current_xact_id();"); # ensure WAL flush $node_primary->wait_for_catchup($node_standby); ok( send_query_and_wait( diff --git a/src/test/recovery/t/031_recovery_conflict.pl b/src/test/recovery/t/031_recovery_conflict.pl index 7a740f69806..3f52b5c82b6 100644 --- a/src/test/recovery/t/031_recovery_conflict.pl +++ b/src/test/recovery/t/031_recovery_conflict.pl @@ -239,7 +239,7 @@ BEGIN; LOCK TABLE $table2; PREPARE TRANSACTION 'lock'; INSERT INTO $table1(a) VALUES (170); -SELECT txid_current(); +SELECT pg_current_xact_id(); ]); $node_primary->wait_for_replay_catchup($node_standby); diff --git a/src/test/recovery/t/040_standby_failover_slots_sync.pl b/src/test/recovery/t/040_standby_failover_slots_sync.pl index 47d64d05ad1..eb2dde8050d 100644 --- a/src/test/recovery/t/040_standby_failover_slots_sync.pl +++ b/src/test/recovery/t/040_standby_failover_slots_sync.pl @@ -433,11 +433,11 @@ $standby1->safe_psql('postgres', "SELECT pg_sync_replication_slots();"); $primary->safe_psql( 'postgres', qq( BEGIN; - SELECT txid_current(); + SELECT pg_current_xact_id(); SELECT pg_log_standby_snapshot(); COMMIT; BEGIN; - SELECT txid_current(); + SELECT pg_current_xact_id(); SELECT pg_log_standby_snapshot(); COMMIT; )); diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index c743fc769cb..d5ae62fd481 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -1438,7 +1438,7 @@ COMMIT; CREATE FUNCTION predicate_stable() RETURNS bool IMMUTABLE LANGUAGE plpgsql AS $$ BEGIN - EXECUTE 'SELECT txid_current()'; + EXECUTE 'SELECT pg_current_xact_id()'; RETURN true; END; $$; CREATE INDEX CONCURRENTLY concur_index8 ON concur_heap (f1) diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index eabc9623b20..5f64523c17b 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -513,7 +513,7 @@ COMMIT; CREATE FUNCTION predicate_stable() RETURNS bool IMMUTABLE LANGUAGE plpgsql AS $$ BEGIN - EXECUTE 'SELECT txid_current()'; + EXECUTE 'SELECT pg_current_xact_id()'; RETURN true; END; $$; CREATE INDEX CONCURRENTLY concur_index8 ON concur_heap (f1) diff --git a/src/test/subscription/t/035_conflicts.pl b/src/test/subscription/t/035_conflicts.pl index 426ad74cf33..68c511b6767 100644 --- a/src/test/subscription/t/035_conflicts.pl +++ b/src/test/subscription/t/035_conflicts.pl @@ -332,7 +332,7 @@ like( 'update target row was deleted in tab'); # Remember the next transaction ID to be assigned -my $next_xid = $node_A->safe_psql('postgres', "SELECT txid_current() + 1;"); +my $next_xid = $node_A->safe_psql('postgres', "SELECT pg_current_xact_id() + 1;"); # Confirm that the xmin value is advanced to the latest nextXid. If no # transactions are running, the apply worker selects nextXid as the candidate @@ -391,7 +391,7 @@ $node_A->safe_psql('postgres', "ALTER SUBSCRIPTION $subname_AB REFRESH PUBLICATION"); # Remember the next transaction ID to be assigned -$next_xid = $node_A->safe_psql('postgres', "SELECT txid_current() + 1;"); +$next_xid = $node_A->safe_psql('postgres', "SELECT pg_current_xact_id() + 1;"); # Confirm that the xmin value is advanced to the latest nextXid. If no # transactions are running, the apply worker selects nextXid as the candidate @@ -540,7 +540,7 @@ if ($injection_points_supported != 0) # Remember the next transaction ID to be assigned $next_xid = - $node_A->safe_psql('postgres', "SELECT txid_current() + 1;"); + $node_A->safe_psql('postgres', "SELECT pg_current_xact_id() + 1;"); # Confirm that the xmin value is advanced to the latest nextXid after the # prepared transaction on the publisher has been committed. @@ -591,7 +591,7 @@ $node_B->safe_psql('postgres', "INSERT INTO tab VALUES (5, 5);"); # Advance the xid on Node A to trigger the next cycle of oldest_nonremovable_xid # advancement. -$node_A->safe_psql('postgres', "SELECT txid_current() + 1;"); +$node_A->safe_psql('postgres', "SELECT pg_current_xact_id() + 1;"); $log_offset = -s $node_A->logfile; -- 2.47.3 ^ permalink raw reply [nested|flat] 4+ messages in thread
* Re: Use pg_current_xact_id() instead of deprecated txid_current() @ 2026-05-25 08:09 Shinya Kato <[email protected]> parent: Shinya Kato <[email protected]> 0 siblings, 1 reply; 4+ messages in thread From: Shinya Kato @ 2026-05-25 08:09 UTC (permalink / raw) To: Tom Lane <[email protected]>; +Cc: Álvaro Herrera <[email protected]>; pgsql-hackers <[email protected]> On Thu, May 14, 2026 at 9:31 PM Shinya Kato <[email protected]> wrote: > > Rebased the patches. Rebased the patches, again. -- Best regards, Shinya Kato NTT OSS Center Attachments: [application/octet-stream] v4-0001-Add-arithmetic-operators-for-xid8.patch (8.1K, 2-v4-0001-Add-arithmetic-operators-for-xid8.patch) download | inline diff: From 0cf63fee403d77aba208b21087a22b7d9c958078 Mon Sep 17 00:00:00 2001 From: Shinya Kato <[email protected]> Date: Mon, 9 Feb 2026 13:35:07 +0900 Subject: [PATCH v4 1/2] Add arithmetic operators for xid8 Add +, - operators for xid8 type to allow direct arithmetic without the need for casting through text and bigint: xid8 + int8 -> xid8 int8 + xid8 -> xid8 xid8 - int8 -> xid8 xid8 - xid8 -> int8 These operators follow the same pattern as the existing pg_lsn arithmetic operators. Since there are no implicit casts between xid8 and any ordinary numeric type, this avoids the "ambiguous operator" concern. Author: Shinya Kato <[email protected]> Reviewed-by: Discussion: https://postgr.es/m/CAOzEurQetW=-1+OnMo8baeVQF=-kAr-wNtFcgRNo+ErPk=xsDQ@mail.gmail.com --- src/backend/catalog/system_functions.sql | 6 +++ src/backend/utils/adt/xid.c | 64 ++++++++++++++++++++++++ src/include/catalog/pg_operator.dat | 12 +++++ src/include/catalog/pg_proc.dat | 13 +++++ src/test/regress/expected/xid.out | 46 +++++++++++++++++ src/test/regress/sql/xid.sql | 14 ++++++ 6 files changed, 155 insertions(+) diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql index c3c0a6e84ed..1f9e889115d 100644 --- a/src/backend/catalog/system_functions.sql +++ b/src/backend/catalog/system_functions.sql @@ -93,6 +93,12 @@ CREATE OR REPLACE FUNCTION numeric_pl_pg_lsn(numeric, pg_lsn) IMMUTABLE PARALLEL SAFE STRICT COST 1 RETURN $2 + $1; +CREATE OR REPLACE FUNCTION int8_pl_xid8(bigint, xid8) + RETURNS xid8 + LANGUAGE sql + IMMUTABLE PARALLEL SAFE STRICT COST 1 +RETURN $2 + $1; + CREATE OR REPLACE FUNCTION path_contain_pt(path, point) RETURNS boolean LANGUAGE sql diff --git a/src/backend/utils/adt/xid.c b/src/backend/utils/adt/xid.c index f746a5f97dd..2b770e011cd 100644 --- a/src/backend/utils/adt/xid.c +++ b/src/backend/utils/adt/xid.c @@ -312,6 +312,70 @@ hashxid8extended(PG_FUNCTION_ARGS) return hashint8extended(fcinfo); } +Datum +xid8pl(PG_FUNCTION_ARGS) +{ + FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0); + int64 delta = PG_GETARG_INT64(1); + uint64 val = U64FromFullTransactionId(fxid); + uint64 result; + + result = val + (uint64) delta; + + /* Check for over/underflow */ + if ((delta > 0 && result < val) || (delta < 0 && result > val)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("xid8 out of range"))); + + PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(result)); +} + +Datum +xid8mi(PG_FUNCTION_ARGS) +{ + FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0); + int64 delta = PG_GETARG_INT64(1); + uint64 val = U64FromFullTransactionId(fxid); + uint64 result; + + result = val - (uint64) delta; + + /* Check for over/underflow */ + if ((delta > 0 && result > val) || (delta < 0 && result < val)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("xid8 out of range"))); + + PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(result)); +} + +Datum +xid8_mi_xid8(PG_FUNCTION_ARGS) +{ + FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0); + FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1); + uint64 val1 = U64FromFullTransactionId(fxid1); + uint64 val2 = U64FromFullTransactionId(fxid2); + + if (val1 >= val2) + { + if (val1 - val2 > (uint64) PG_INT64_MAX) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64((int64) (val1 - val2)); + } + else + { + if (val2 - val1 > (uint64) PG_INT64_MAX + 1) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(-((int64) (val2 - val1))); + } +} + Datum xid8_larger(PG_FUNCTION_ARGS) { diff --git a/src/include/catalog/pg_operator.dat b/src/include/catalog/pg_operator.dat index 1a8fd8b8645..453c4938e62 100644 --- a/src/include/catalog/pg_operator.dat +++ b/src/include/catalog/pg_operator.dat @@ -219,6 +219,18 @@ oprname => '>=', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool', oprcom => '<=(xid8,xid8)', oprnegate => '<(xid8,xid8)', oprcode => 'xid8ge', oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '5107', descr => 'add', + oprname => '+', oprleft => 'xid8', oprright => 'int8', oprresult => 'xid8', + oprcom => '+(int8,xid8)', oprcode => 'xid8pl' }, +{ oid => '5108', descr => 'add', + oprname => '+', oprleft => 'int8', oprright => 'xid8', oprresult => 'xid8', + oprcom => '+(xid8,int8)', oprcode => 'int8_pl_xid8' }, +{ oid => '5109', descr => 'subtract', + oprname => '-', oprleft => 'xid8', oprright => 'int8', oprresult => 'xid8', + oprcode => 'xid8mi' }, +{ oid => '5110', descr => 'subtract', + oprname => '-', oprleft => 'xid8', oprright => 'xid8', oprresult => 'int8', + oprcode => 'xid8_mi_xid8' }, { oid => '385', descr => 'equal', oprname => '=', oprcanhash => 't', oprleft => 'cid', oprright => 'cid', oprresult => 'bool', oprcom => '=(cid,cid)', oprcode => 'cideq', diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index be157a5fbe9..e5c080a310f 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -209,6 +209,19 @@ { oid => '5098', descr => 'smaller of two', proname => 'xid8_smaller', prorettype => 'xid8', proargtypes => 'xid8 xid8', prosrc => 'xid8_smaller' }, +{ oid => '5101', + proname => 'xid8pl', prorettype => 'xid8', proargtypes => 'xid8 int8', + prosrc => 'xid8pl' }, +{ oid => '5102', + proname => 'xid8mi', prorettype => 'xid8', proargtypes => 'xid8 int8', + prosrc => 'xid8mi' }, +{ oid => '5103', + proname => 'xid8_mi_xid8', prorettype => 'int8', proargtypes => 'xid8 xid8', + prosrc => 'xid8_mi_xid8' }, +{ oid => '5106', + proname => 'int8_pl_xid8', prolang => 'sql', + prorettype => 'xid8', proargtypes => 'int8 xid8', + prosrc => 'see system_functions.sql' }, { oid => '69', proname => 'cideq', proleakproof => 't', prorettype => 'bool', proargtypes => 'cid cid', prosrc => 'cideq' }, diff --git a/src/test/regress/expected/xid.out b/src/test/regress/expected/xid.out index 1ce7826cf90..4d5f4006072 100644 --- a/src/test/regress/expected/xid.out +++ b/src/test/regress/expected/xid.out @@ -175,6 +175,52 @@ select min(x), max(x) from xid8_t1; create index on xid8_t1 using btree(x); create index on xid8_t1 using hash(x); drop table xid8_t1; +-- xid8 arithmetic operators +select '42'::xid8 + 3::bigint; + ?column? +---------- + 45 +(1 row) + +select 3::bigint + '42'::xid8; + ?column? +---------- + 45 +(1 row) + +select '42'::xid8 - 3::bigint; + ?column? +---------- + 39 +(1 row) + +select '100'::xid8 - '42'::xid8; + ?column? +---------- + 58 +(1 row) + +select '42'::xid8 + (-3)::bigint; + ?column? +---------- + 39 +(1 row) + +select '42'::xid8 - (-3)::bigint; + ?column? +---------- + 45 +(1 row) + +-- xid8 arithmetic overflow/underflow +select '0'::xid8 - 1::bigint; +ERROR: xid8 out of range +select '18446744073709551615'::xid8 + 1::bigint; +ERROR: xid8 out of range +select '18446744073709551615'::xid8 - '0'::xid8; +ERROR: bigint out of range +select '0'::xid8 - '18446744073709551615'::xid8; +ERROR: bigint out of range -- pg_snapshot data type and related functions -- Note: another set of tests similar to this exists in txid.sql, for a limited -- time (the relevant functions share C code) diff --git a/src/test/regress/sql/xid.sql b/src/test/regress/sql/xid.sql index 9f716b3653a..f6bacc04428 100644 --- a/src/test/regress/sql/xid.sql +++ b/src/test/regress/sql/xid.sql @@ -59,6 +59,20 @@ create index on xid8_t1 using btree(x); create index on xid8_t1 using hash(x); drop table xid8_t1; +-- xid8 arithmetic operators +select '42'::xid8 + 3::bigint; +select 3::bigint + '42'::xid8; +select '42'::xid8 - 3::bigint; +select '100'::xid8 - '42'::xid8; +select '42'::xid8 + (-3)::bigint; +select '42'::xid8 - (-3)::bigint; + +-- xid8 arithmetic overflow/underflow +select '0'::xid8 - 1::bigint; +select '18446744073709551615'::xid8 + 1::bigint; +select '18446744073709551615'::xid8 - '0'::xid8; +select '0'::xid8 - '18446744073709551615'::xid8; + -- pg_snapshot data type and related functions -- 2.47.3 [application/octet-stream] v4-0002-Use-pg_current_xact_id-instead-of-deprecated-txid.patch (13.3K, 3-v4-0002-Use-pg_current_xact_id-instead-of-deprecated-txid.patch) download | inline diff: From 3bda1ba8de1093b21fb6600ad6ee69ba873bc71b Mon Sep 17 00:00:00 2001 From: Shinya Kato <[email protected]> Date: Tue, 10 Feb 2026 13:54:01 +0900 Subject: [PATCH v4 2/2] Use pg_current_xact_id() instead of deprecated txid_current() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace txid_current() with pg_current_xact_id() in test code. The previous commit added arithmetic operators for xid8, so places that need "xid + 1" can now use pg_current_xact_id() + 1 directly. Author: Shinya Kato <[email protected]> Reviewed-by: Álvaro Herrera <[email protected]> Reviewed-by: Tom Lane <[email protected]> Discussion: https://postgr.es/m/CAOzEurQetW=-1+OnMo8baeVQF=-kAr-wNtFcgRNo+ErPk=xsDQ@mail.gmail.com --- contrib/pg_visibility/t/001_concurrent_transaction.pl | 2 +- contrib/test_decoding/expected/slot_creation_error.out | 6 +++--- contrib/test_decoding/specs/slot_creation_error.spec | 2 +- src/bin/pg_combinebackup/t/002_compare_backups.pl | 4 ++-- src/test/modules/commit_ts/expected/commit_timestamp.out | 4 ++-- .../modules/commit_ts/expected/commit_timestamp_1.out | 4 ++-- src/test/modules/commit_ts/sql/commit_timestamp.sql | 4 ++-- src/test/modules/xid_wraparound/t/004_notify_freeze.pl | 4 ++-- src/test/recovery/t/021_row_visibility.pl | 2 +- src/test/recovery/t/031_recovery_conflict.pl | 2 +- src/test/recovery/t/040_standby_failover_slots_sync.pl | 4 ++-- src/test/regress/expected/create_index.out | 2 +- src/test/regress/sql/create_index.sql | 2 +- src/test/subscription/t/035_conflicts.pl | 9 +++++---- 14 files changed, 26 insertions(+), 25 deletions(-) diff --git a/contrib/pg_visibility/t/001_concurrent_transaction.pl b/contrib/pg_visibility/t/001_concurrent_transaction.pl index 3aa556892a6..889cae927fd 100644 --- a/contrib/pg_visibility/t/001_concurrent_transaction.pl +++ b/contrib/pg_visibility/t/001_concurrent_transaction.pl @@ -30,7 +30,7 @@ my $bsession = $node->background_psql('other_database'); $bsession->query_safe( qq[ BEGIN; - SELECT txid_current(); + SELECT pg_current_xact_id(); ]); # Create a sample table and run vacuum diff --git a/contrib/test_decoding/expected/slot_creation_error.out b/contrib/test_decoding/expected/slot_creation_error.out index 25883b508fb..95591752371 100644 --- a/contrib/test_decoding/expected/slot_creation_error.out +++ b/contrib/test_decoding/expected/slot_creation_error.out @@ -2,7 +2,7 @@ Parsed test spec with 2 sessions starting permutation: s1_b s1_xid s2_init s1_view_slot s1_cancel_s2 s1_view_slot s1_c step s1_b: BEGIN; -step s1_xid: SELECT 'xid' FROM txid_current(); +step s1_xid: SELECT 'xid' FROM pg_current_xact_id(); ?column? -------- xid @@ -43,7 +43,7 @@ step s1_c: COMMIT; starting permutation: s1_b s1_xid s2_init s1_c s1_view_slot s1_drop_slot step s1_b: BEGIN; -step s1_xid: SELECT 'xid' FROM txid_current(); +step s1_xid: SELECT 'xid' FROM pg_current_xact_id(); ?column? -------- xid @@ -78,7 +78,7 @@ pg_drop_replication_slot starting permutation: s1_b s1_xid s2_init s1_terminate_s2 s1_c s1_view_slot step s1_b: BEGIN; -step s1_xid: SELECT 'xid' FROM txid_current(); +step s1_xid: SELECT 'xid' FROM pg_current_xact_id(); ?column? -------- xid diff --git a/contrib/test_decoding/specs/slot_creation_error.spec b/contrib/test_decoding/specs/slot_creation_error.spec index d1e35bf58b5..6983f24eae6 100644 --- a/contrib/test_decoding/specs/slot_creation_error.spec +++ b/contrib/test_decoding/specs/slot_creation_error.spec @@ -4,7 +4,7 @@ session "s1" setup { SET synchronous_commit=on; } step s1_b { BEGIN; } -step s1_xid { SELECT 'xid' FROM txid_current(); } +step s1_xid { SELECT 'xid' FROM pg_current_xact_id(); } step s1_c { COMMIT; } step s1_cancel_s2 { SELECT pg_cancel_backend(pid) diff --git a/src/bin/pg_combinebackup/t/002_compare_backups.pl b/src/bin/pg_combinebackup/t/002_compare_backups.pl index b509296a94a..42d252b2242 100644 --- a/src/bin/pg_combinebackup/t/002_compare_backups.pl +++ b/src/bin/pg_combinebackup/t/002_compare_backups.pl @@ -105,9 +105,9 @@ my $lsn = $primary->safe_psql('postgres', "SELECT pg_current_wal_lsn();"); # Make sure that the WAL segment containing that LSN has been archived. # PostgreSQL won't issue two consecutive XLOG_SWITCH records, and the backup -# just issued one, so call txid_current() to generate some WAL activity +# just issued one, so call pg_current_xact_id() to generate some WAL activity # before calling pg_switch_wal(). -$primary->safe_psql('postgres', 'SELECT txid_current();'); +$primary->safe_psql('postgres', 'SELECT pg_current_xact_id();'); $primary->safe_psql('postgres', 'SELECT pg_switch_wal()'); # Now wait for the LSN we chose above to be archived. diff --git a/src/test/modules/commit_ts/expected/commit_timestamp.out b/src/test/modules/commit_ts/expected/commit_timestamp.out index bb2fda27681..0d08e0684a2 100644 --- a/src/test/modules/commit_ts/expected/commit_timestamp.out +++ b/src/test/modules/commit_ts/expected/commit_timestamp.out @@ -71,7 +71,7 @@ SELECT * FROM pg_xact_commit_timestamp_origin('2'::xid); -- ok, NULL (1 row) -- Test transaction without replication origin -SELECT txid_current() as txid_no_origin \gset +SELECT pg_current_xact_id() as txid_no_origin \gset SELECT x.timestamp > '-infinity'::timestamptz AS ts_low, x.timestamp <= now() AS ts_high, roident != 0 AS valid_roident @@ -104,7 +104,7 @@ SELECT pg_replication_origin_session_setup('regress_commit_ts: get_origin'); (1 row) -SELECT txid_current() as txid_with_origin \gset +SELECT pg_current_xact_id() as txid_with_origin \gset SELECT x.timestamp > '-infinity'::timestamptz AS ts_low, x.timestamp <= now() AS ts_high, r.roname diff --git a/src/test/modules/commit_ts/expected/commit_timestamp_1.out b/src/test/modules/commit_ts/expected/commit_timestamp_1.out index f37e701f37a..21f09b89cac 100644 --- a/src/test/modules/commit_ts/expected/commit_timestamp_1.out +++ b/src/test/modules/commit_ts/expected/commit_timestamp_1.out @@ -63,7 +63,7 @@ SELECT * FROM pg_xact_commit_timestamp_origin('2'::xid); -- ok, NULL (1 row) -- Test transaction without replication origin -SELECT txid_current() as txid_no_origin \gset +SELECT pg_current_xact_id() as txid_no_origin \gset SELECT x.timestamp > '-infinity'::timestamptz AS ts_low, x.timestamp <= now() AS ts_high, roident != 0 AS valid_roident @@ -90,7 +90,7 @@ SELECT pg_replication_origin_session_setup('regress_commit_ts: get_origin'); (1 row) -SELECT txid_current() as txid_with_origin \gset +SELECT pg_current_xact_id() as txid_with_origin \gset SELECT x.timestamp > '-infinity'::timestamptz AS ts_low, x.timestamp <= now() AS ts_high, r.roname diff --git a/src/test/modules/commit_ts/sql/commit_timestamp.sql b/src/test/modules/commit_ts/sql/commit_timestamp.sql index 3bb7bb27a74..a2f0e68317d 100644 --- a/src/test/modules/commit_ts/sql/commit_timestamp.sql +++ b/src/test/modules/commit_ts/sql/commit_timestamp.sql @@ -34,7 +34,7 @@ SELECT * FROM pg_xact_commit_timestamp_origin('1'::xid); -- ok, NULL SELECT * FROM pg_xact_commit_timestamp_origin('2'::xid); -- ok, NULL -- Test transaction without replication origin -SELECT txid_current() as txid_no_origin \gset +SELECT pg_current_xact_id() as txid_no_origin \gset SELECT x.timestamp > '-infinity'::timestamptz AS ts_low, x.timestamp <= now() AS ts_high, roident != 0 AS valid_roident @@ -48,7 +48,7 @@ SELECT x.timestamp > '-infinity'::timestamptz AS ts_low, SELECT pg_replication_origin_create('regress_commit_ts: get_origin') != 0 AS valid_roident; SELECT pg_replication_origin_session_setup('regress_commit_ts: get_origin'); -SELECT txid_current() as txid_with_origin \gset +SELECT pg_current_xact_id() as txid_with_origin \gset SELECT x.timestamp > '-infinity'::timestamptz AS ts_low, x.timestamp <= now() AS ts_high, r.roname diff --git a/src/test/modules/xid_wraparound/t/004_notify_freeze.pl b/src/test/modules/xid_wraparound/t/004_notify_freeze.pl index d0a1f1fe2fc..9a8300186f7 100644 --- a/src/test/modules/xid_wraparound/t/004_notify_freeze.pl +++ b/src/test/modules/xid_wraparound/t/004_notify_freeze.pl @@ -35,9 +35,9 @@ for my $i (1 .. 10) } # Consume enough XIDs to trigger truncation, and one more with -# 'txid_current' to bump up the freeze horizon. +# 'pg_current_xact_id' to bump up the freeze horizon. $node->safe_psql('postgres', 'select consume_xids(10000000);'); -$node->safe_psql('postgres', 'select txid_current()'); +$node->safe_psql('postgres', 'select pg_current_xact_id()'); # Remember current datfrozenxid before vacuum freeze so that we can # check that it is advanced. (Taking the min() this way assumes that diff --git a/src/test/recovery/t/021_row_visibility.pl b/src/test/recovery/t/021_row_visibility.pl index 0a4d22b3698..9626d431852 100644 --- a/src/test/recovery/t/021_row_visibility.pl +++ b/src/test/recovery/t/021_row_visibility.pl @@ -94,7 +94,7 @@ UPDATE test_visibility SET data = 'first update' RETURNING data; qr/^UPDATE 1$/m), 'UPDATE'); -$node_primary->psql('postgres', "SELECT txid_current();"); # ensure WAL flush +$node_primary->psql('postgres', "SELECT pg_current_xact_id();"); # ensure WAL flush $node_primary->wait_for_catchup($node_standby); ok( send_query_and_wait( diff --git a/src/test/recovery/t/031_recovery_conflict.pl b/src/test/recovery/t/031_recovery_conflict.pl index 7a740f69806..3f52b5c82b6 100644 --- a/src/test/recovery/t/031_recovery_conflict.pl +++ b/src/test/recovery/t/031_recovery_conflict.pl @@ -239,7 +239,7 @@ BEGIN; LOCK TABLE $table2; PREPARE TRANSACTION 'lock'; INSERT INTO $table1(a) VALUES (170); -SELECT txid_current(); +SELECT pg_current_xact_id(); ]); $node_primary->wait_for_replay_catchup($node_standby); diff --git a/src/test/recovery/t/040_standby_failover_slots_sync.pl b/src/test/recovery/t/040_standby_failover_slots_sync.pl index f8922aaa1a2..ad4a94f5046 100644 --- a/src/test/recovery/t/040_standby_failover_slots_sync.pl +++ b/src/test/recovery/t/040_standby_failover_slots_sync.pl @@ -433,11 +433,11 @@ $standby1->safe_psql('postgres', "SELECT pg_sync_replication_slots();"); $primary->safe_psql( 'postgres', qq( BEGIN; - SELECT txid_current(); + SELECT pg_current_xact_id(); SELECT pg_log_standby_snapshot(); COMMIT; BEGIN; - SELECT txid_current(); + SELECT pg_current_xact_id(); SELECT pg_log_standby_snapshot(); COMMIT; )); diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index 55538c4c41e..31cd896dc17 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -1452,7 +1452,7 @@ COMMIT; CREATE FUNCTION predicate_stable() RETURNS bool IMMUTABLE LANGUAGE plpgsql AS $$ BEGIN - EXECUTE 'SELECT txid_current()'; + EXECUTE 'SELECT pg_current_xact_id()'; RETURN true; END; $$; CREATE INDEX CONCURRENTLY concur_index8 ON concur_heap (f1) diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index 82e4062a215..96e2aee98b2 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -517,7 +517,7 @@ COMMIT; CREATE FUNCTION predicate_stable() RETURNS bool IMMUTABLE LANGUAGE plpgsql AS $$ BEGIN - EXECUTE 'SELECT txid_current()'; + EXECUTE 'SELECT pg_current_xact_id()'; RETURN true; END; $$; CREATE INDEX CONCURRENTLY concur_index8 ON concur_heap (f1) diff --git a/src/test/subscription/t/035_conflicts.pl b/src/test/subscription/t/035_conflicts.pl index f23fe6af2a5..82e38f16bc6 100644 --- a/src/test/subscription/t/035_conflicts.pl +++ b/src/test/subscription/t/035_conflicts.pl @@ -330,7 +330,7 @@ like( 'update target row was deleted in tab'); # Remember the next transaction ID to be assigned -my $next_xid = $node_A->safe_psql('postgres', "SELECT txid_current() + 1;"); +my $next_xid = $node_A->safe_psql('postgres', "SELECT pg_current_xact_id() + 1;"); # Confirm that the xmin value is advanced to the latest nextXid. If no # transactions are running, the apply worker selects nextXid as the candidate @@ -388,7 +388,7 @@ $node_A->safe_psql('postgres', "ALTER SUBSCRIPTION $subname_AB REFRESH PUBLICATION"); # Remember the next transaction ID to be assigned -$next_xid = $node_A->safe_psql('postgres', "SELECT txid_current() + 1;"); +$next_xid = $node_A->safe_psql('postgres', "SELECT pg_current_xact_id() + 1;"); # Confirm that the xmin value is advanced to the latest nextXid. If no # transactions are running, the apply worker selects nextXid as the candidate @@ -535,7 +535,8 @@ if ($injection_points_supported != 0) 'update target row was deleted in tab'); # Remember the next transaction ID to be assigned - $next_xid = $node_A->safe_psql('postgres', "SELECT txid_current() + 1;"); + $next_xid = + $node_A->safe_psql('postgres', "SELECT pg_current_xact_id() + 1;"); # Confirm that the xmin value is advanced to the latest nextXid after the # prepared transaction on the publisher has been committed. @@ -587,7 +588,7 @@ $node_B->safe_psql('postgres', "INSERT INTO tab VALUES (5, 5);"); # Advance the xid on Node A to trigger the next cycle of oldest_nonremovable_xid # advancement. -$node_A->safe_psql('postgres', "SELECT txid_current() + 1;"); +$node_A->safe_psql('postgres', "SELECT pg_current_xact_id() + 1;"); $log_offset = -s $node_A->logfile; -- 2.47.3 ^ permalink raw reply [nested|flat] 4+ messages in thread
* Re: Use pg_current_xact_id() instead of deprecated txid_current() @ 2026-05-27 17:08 lin teletele <[email protected]> parent: Shinya Kato <[email protected]> 0 siblings, 0 replies; 4+ messages in thread From: lin teletele @ 2026-05-27 17:08 UTC (permalink / raw) To: Shinya Kato <[email protected]>; +Cc: Tom Lane <[email protected]>; Álvaro Herrera <[email protected]>; pgsql-hackers <[email protected]> Hi Shinya, Thanks for the patches. I read v4-0001 and have a few small observations from going through the arithmetic functions. I tested the suggestions below locally on top of v4 — they pass the existing xid regression tests and produce identical output on the boundary cases listed in section 3. 1. xid8pl / xid8mi could reuse the helpers in common/int.h ---------------------------------------------------- xid8pl currently rolls its own overflow detection on a mixed-sign addition: result = val + (uint64) delta; if ((delta > 0 && result < val) || (delta < 0 && result > val)) ereport(ERROR, ...); This is correct, but it's the only place in the tree that takes this approach, and the (uint64)-of-a-signed-value plus sign-aware compare takes a moment to convince oneself of. common/int.h already provides pg_add_u64_overflow / pg_sub_u64_overflow, plus pg_abs_s64 which returns uint64 and explicitly handles INT64_MIN, so xid8pl could be written as: uint64 abs_delta = pg_abs_s64(delta); bool overflow; if (delta >= 0) overflow = pg_add_u64_overflow(val, abs_delta, &result); else overflow = pg_sub_u64_overflow(val, abs_delta, &result); if (overflow) ereport(ERROR, ...); And xid8mi symmetrically (add/sub swapped): uint64 abs_delta = pg_abs_s64(delta); bool overflow; if (delta >= 0) overflow = pg_sub_u64_overflow(val, abs_delta, &result); else overflow = pg_add_u64_overflow(val, abs_delta, &result); if (overflow) ereport(ERROR, ...); This keeps the code inside the standard PG overflow-check idiom, and as a side effect handles a delta of INT64_MIN cleanly (pg_abs_s64 returns 2^63 in that case without invoking UB). 2. INT64_MIN boundary in xid8_mi_xid8 ---------------------------------------------------- In the val1 < val2 branch: if (val2 - val1 > (uint64) PG_INT64_MAX + 1) ereport(ERROR, ...); PG_RETURN_INT64(-((int64) (val2 - val1))); The bound permits val2 - val1 == 2^63 (e.g. '0'::xid8 - '9223372036854775808'::xid8). When val2 - val1 == 2^63, the cast (int64)(val2 - val1) is implementation-defined (the value doesn't fit in int64), and -INT64_MIN is signed overflow (UB). In practice on two's-complement targets the answer comes out as INT64_MIN, which is the correct value, but it relies on UB. Pulling out the boundary explicitly keeps the same observable behavior without the UB: uint64 diff = val2 - val1; if (diff > (uint64) PG_INT64_MAX + 1) ereport(ERROR, ...); /* diff == 2^63 maps to INT64_MIN */ if (diff > (uint64) PG_INT64_MAX) PG_RETURN_INT64(PG_INT64_MIN); PG_RETURN_INT64(-(int64) diff); 3. Test coverage ---------------------------------------------------- The regression tests in xid.sql exercise the positive overflow side nicely but miss a few boundaries on the negative side: -- xid8 - xid8 at the INT64_MIN boundary (#2 above) select '0'::xid8 - '9223372036854775808'::xid8; -- xid8 + int8 / xid8 - int8 with INT64_MAX / INT64_MIN deltas select '0'::xid8 + 9223372036854775807::bigint; select '0'::xid8 - (-9223372036854775807 - 1)::bigint; select '9223372036854775807'::xid8 - (-9223372036854775807 - 1)::bigint; It would be good to pin those down in the expected output. 4. Documentation ---------------------------------------------------- v4-0001 adds four user-visible operators but doesn't touch doc/src/sgml/. pg_lsn's arithmetic operators are documented in datatype.sgml around the "pg_lsn Type" section -- it would be nice for the new xid8 operators to get analogous coverage in the nearby xid8 paragraph. As a separate observation (probably better as a follow-up thread rather than expanding the scope of this one): xid8 currently has only hash and btree opclasses, no BRIN. Since xid8 is strictly monotonic and never wraps, BRIN minmax looks like a natural fit -- I'll raise that separately if there's interest. Regards, Teletele On Mon, May 25, 2026 at 4:10 PM Shinya Kato <[email protected]> wrote: > > On Thu, May 14, 2026 at 9:31 PM Shinya Kato <[email protected]> wrote: > > > > Rebased the patches. > > Rebased the patches, again. > > -- > Best regards, > Shinya Kato > NTT OSS Center ^ permalink raw reply [nested|flat] 4+ messages in thread
end of thread, other threads:[~2026-05-27 17:08 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2026-02-09 12:07 Re: Use pg_current_xact_id() instead of deprecated txid_current() Shinya Kato <[email protected]> 2026-02-10 06:38 ` Shinya Kato <[email protected]> 2026-05-25 08:09 ` Shinya Kato <[email protected]> 2026-05-27 17:08 ` lin teletele <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox