v4-0001-Add-arithmetic-operators-for-xid8.patch
application/octet-stream
Filename: v4-0001-Add-arithmetic-operators-for-xid8.patch
Type: application/octet-stream
Part: 0
From 0cf63fee403d77aba208b21087a22b7d9c958078 Mon Sep 17 00:00:00 2001
From: Shinya Kato <shinya11.kato@gmail.com>
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 <shinya11.kato@gmail.com>
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