From 9ec66311c64289774da1aa6fc12b97347791a2a7 Mon Sep 17 00:00:00 2001
From: Thomas Munro
Date: Fri, 2 Aug 2019 17:29:34 +1200
Subject: [PATCH 1/2] Add SQL type xid8 to expose FullTransactionId to users.
Similar to xid, but 64 bits wide. This new type is suitable for use
in various system views and administration functions.
Author: Thomas Munro
Reviewed-by: Takao Fujii
Discussion: https://postgr.es/m/https://www.postgresql.org/message-id/20190725000636.666m5mad25wfbrri%40alap3.anarazel.de
---
src/backend/access/hash/hashvalidate.c | 3 +
src/backend/utils/adt/xid.c | 74 ++++++++++++++++++++++++
src/fe_utils/print.c | 1 +
src/include/access/transam.h | 11 ++++
src/include/catalog/pg_amop.dat | 4 ++
src/include/catalog/pg_amproc.dat | 4 ++
src/include/catalog/pg_cast.dat | 4 ++
src/include/catalog/pg_opclass.dat | 2 +
src/include/catalog/pg_operator.dat | 8 +++
src/include/catalog/pg_opfamily.dat | 2 +
src/include/catalog/pg_proc.dat | 21 +++++++
src/include/catalog/pg_type.dat | 4 ++
src/include/utils/xid8.h | 22 +++++++
src/test/regress/expected/opr_sanity.out | 2 +
14 files changed, 162 insertions(+)
create mode 100644 src/include/utils/xid8.h
diff --git a/src/backend/access/hash/hashvalidate.c b/src/backend/access/hash/hashvalidate.c
index 9315872751..8ecbd074b2 100644
--- a/src/backend/access/hash/hashvalidate.c
+++ b/src/backend/access/hash/hashvalidate.c
@@ -313,6 +313,9 @@ check_hash_func_signature(Oid funcid, int16 amprocnum, Oid argtype)
(argtype == DATEOID ||
argtype == XIDOID || argtype == CIDOID))
/* okay, allowed use of hashint4() */ ;
+ else if ((funcid == F_HASHINT8 || funcid == F_HASHINT8EXTENDED) &&
+ (argtype == XID8OID))
+ /* okay, allowed use of hashint8() */ ;
else if ((funcid == F_TIMESTAMP_HASH ||
funcid == F_TIMESTAMP_HASH_EXTENDED) &&
argtype == TIMESTAMPTZOID)
diff --git a/src/backend/utils/adt/xid.c b/src/backend/utils/adt/xid.c
index 7853e41865..3d7c249b1c 100644
--- a/src/backend/utils/adt/xid.c
+++ b/src/backend/utils/adt/xid.c
@@ -21,6 +21,7 @@
#include "access/xact.h"
#include "libpq/pqformat.h"
#include "utils/builtins.h"
+#include "utils/xid8.h"
#define PG_GETARG_TRANSACTIONID(n) DatumGetTransactionId(PG_GETARG_DATUM(n))
#define PG_RETURN_TRANSACTIONID(x) return TransactionIdGetDatum(x)
@@ -147,6 +148,79 @@ xidComparator(const void *arg1, const void *arg2)
return 0;
}
+Datum
+xid8toxid(PG_FUNCTION_ARGS)
+{
+ FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
+
+ PG_RETURN_TRANSACTIONID(XidFromFullTransactionId(fxid));
+}
+
+Datum
+xid8in(PG_FUNCTION_ARGS)
+{
+ char *str = PG_GETARG_CSTRING(0);
+ char *end;
+ uint64 value;
+
+ value = pg_strtouint64(str, &end, 10);
+ if (*str == '\0' || *end != '\0')
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("value \"%s\" is invalid for type xid8", str)));
+
+ PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(value));
+}
+
+Datum
+xid8out(PG_FUNCTION_ARGS)
+{
+ FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
+ char *result = (char *) palloc(21);
+
+ snprintf(result, 21, UINT64_FORMAT, U64FromFullTransactionId(fxid));
+ PG_RETURN_CSTRING(result);
+}
+
+Datum
+xid8recv(PG_FUNCTION_ARGS)
+{
+ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
+ uint64 value;
+
+ value = (uint64) pq_getmsgint64(buf);
+ PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(value));
+}
+
+Datum
+xid8send(PG_FUNCTION_ARGS)
+{
+ FullTransactionId arg1 = PG_GETARG_FULLTRANSACTIONID(0);
+ StringInfoData buf;
+
+ pq_begintypsend(&buf);
+ pq_sendint64(&buf, (uint64) U64FromFullTransactionId(arg1));
+ PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+Datum
+xid8eq(PG_FUNCTION_ARGS)
+{
+ FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
+ FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
+
+ PG_RETURN_BOOL(FullTransactionIdEquals(fxid1, fxid2));
+}
+
+Datum
+xid8neq(PG_FUNCTION_ARGS)
+{
+ FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
+ FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
+
+ PG_RETURN_BOOL(!FullTransactionIdEquals(fxid1, fxid2));
+}
+
/*****************************************************************************
* COMMAND IDENTIFIER ROUTINES *
*****************************************************************************/
diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c
index b9cd6a1752..9ec046af2d 100644
--- a/src/fe_utils/print.c
+++ b/src/fe_utils/print.c
@@ -3510,6 +3510,7 @@ column_type_alignment(Oid ftype)
case NUMERICOID:
case OIDOID:
case XIDOID:
+ case XID8OID:
case CIDOID:
case CASHOID:
align = 'r';
diff --git a/src/include/access/transam.h b/src/include/access/transam.h
index 33fd052156..787451b3b7 100644
--- a/src/include/access/transam.h
+++ b/src/include/access/transam.h
@@ -47,6 +47,7 @@
#define EpochFromFullTransactionId(x) ((uint32) ((x).value >> 32))
#define XidFromFullTransactionId(x) ((uint32) (x).value)
#define U64FromFullTransactionId(x) ((x).value)
+#define FullTransactionIdEquals(a, b) ((a).value == (b).value)
#define FullTransactionIdPrecedes(a, b) ((a).value < (b).value)
#define FullTransactionIdIsValid(x) TransactionIdIsValid(XidFromFullTransactionId(x))
#define InvalidFullTransactionId FullTransactionIdFromEpochAndXid(0, InvalidTransactionId)
@@ -71,6 +72,16 @@ FullTransactionIdFromEpochAndXid(uint32 epoch, TransactionId xid)
return result;
}
+static inline FullTransactionId
+FullTransactionIdFromU64(uint64 value)
+{
+ FullTransactionId result;
+
+ result.value = value;
+
+ return result;
+}
+
/* advance a transaction ID variable, handling wraparound correctly */
#define TransactionIdAdvance(dest) \
do { \
diff --git a/src/include/catalog/pg_amop.dat b/src/include/catalog/pg_amop.dat
index 232557ee81..2a232f1608 100644
--- a/src/include/catalog/pg_amop.dat
+++ b/src/include/catalog/pg_amop.dat
@@ -1009,6 +1009,10 @@
{ amopfamily => 'hash/xid_ops', amoplefttype => 'xid', amoprighttype => 'xid',
amopstrategy => '1', amopopr => '=(xid,xid)', amopmethod => 'hash' },
+# xid_ops
+{ amopfamily => 'hash/xid8_ops', amoplefttype => 'xid8', amoprighttype => 'xid8',
+ amopstrategy => '1', amopopr => '=(xid8,xid8)', amopmethod => 'hash' },
+
# cid_ops
{ amopfamily => 'hash/cid_ops', amoplefttype => 'cid', amoprighttype => 'cid',
amopstrategy => '1', amopopr => '=(cid,cid)', amopmethod => 'hash' },
diff --git a/src/include/catalog/pg_amproc.dat b/src/include/catalog/pg_amproc.dat
index 5e705019b4..fbe1667292 100644
--- a/src/include/catalog/pg_amproc.dat
+++ b/src/include/catalog/pg_amproc.dat
@@ -339,6 +339,10 @@
amprocrighttype => 'xid', amprocnum => '1', amproc => 'hashint4' },
{ amprocfamily => 'hash/xid_ops', amproclefttype => 'xid',
amprocrighttype => 'xid', amprocnum => '2', amproc => 'hashint4extended' },
+{ amprocfamily => 'hash/xid8_ops', amproclefttype => 'xid8',
+ amprocrighttype => 'xid8', amprocnum => '1', amproc => 'hashint8' },
+{ amprocfamily => 'hash/xid8_ops', amproclefttype => 'xid8',
+ amprocrighttype => 'xid8', amprocnum => '2', amproc => 'hashint8extended' },
{ amprocfamily => 'hash/cid_ops', amproclefttype => 'cid',
amprocrighttype => 'cid', amprocnum => '1', amproc => 'hashint4' },
{ amprocfamily => 'hash/cid_ops', amproclefttype => 'cid',
diff --git a/src/include/catalog/pg_cast.dat b/src/include/catalog/pg_cast.dat
index aabfa7af03..6dc856230f 100644
--- a/src/include/catalog/pg_cast.dat
+++ b/src/include/catalog/pg_cast.dat
@@ -93,6 +93,10 @@
{ castsource => 'bool', casttarget => 'int4', castfunc => 'int4(bool)',
castcontext => 'e', castmethod => 'f' },
+# Allow explicit coercions between xid8 and xid
+{ castsource => 'xid8', casttarget => 'xid', castfunc => 'xid(xid8)',
+ castcontext => 'e', castmethod => 'f' },
+
# OID category: allow implicit conversion from any integral type (including
# int8, to support OID literals > 2G) to OID, as well as assignment coercion
# from OID to int4 or int8. Similarly for each OID-alias type. Also allow
diff --git a/src/include/catalog/pg_opclass.dat b/src/include/catalog/pg_opclass.dat
index 2d575102ef..7b01e5ca4c 100644
--- a/src/include/catalog/pg_opclass.dat
+++ b/src/include/catalog/pg_opclass.dat
@@ -168,6 +168,8 @@
opcintype => 'tid' },
{ opcmethod => 'hash', opcname => 'xid_ops', opcfamily => 'hash/xid_ops',
opcintype => 'xid' },
+{ opcmethod => 'hash', opcname => 'xid8_ops', opcfamily => 'hash/xid8_ops',
+ opcintype => 'xid8' },
{ opcmethod => 'hash', opcname => 'cid_ops', opcfamily => 'hash/cid_ops',
opcintype => 'cid' },
{ opcmethod => 'hash', opcname => 'tid_ops', opcfamily => 'hash/tid_ops',
diff --git a/src/include/catalog/pg_operator.dat b/src/include/catalog/pg_operator.dat
index 126bfac3ff..bfbc1f5066 100644
--- a/src/include/catalog/pg_operator.dat
+++ b/src/include/catalog/pg_operator.dat
@@ -193,6 +193,14 @@
oprname => '<>', oprleft => 'xid', oprright => 'int4', oprresult => 'bool',
oprnegate => '=(xid,int4)', oprcode => 'xidneqint4', oprrest => 'neqsel',
oprjoin => 'neqjoinsel' },
+{ oid => '9551', descr => 'equal',
+ oprname => '=', oprcanhash => 't', oprleft => 'xid8', oprright => 'xid8',
+ oprresult => 'bool', oprcom => '=(xid8,xid8)', oprnegate => '<>(xid8,xid8)',
+ oprcode => 'xid8eq', oprrest => 'eqsel', oprjoin => 'eqjoinsel' },
+{ oid => '9552', descr => 'not equal',
+ oprname => '<>', oprleft => 'xid8', oprright => 'xid8',
+ oprresult => 'bool', oprcom => '<>(xid8,xid8)', oprnegate => '=(xid8,xid8)',
+ oprcode => 'xid8neq', oprrest => 'neqsel', oprjoin => 'neqjoinsel' },
{ oid => '388', descr => 'factorial',
oprname => '!', oprkind => 'r', oprleft => 'int8', oprright => '0',
oprresult => 'numeric', oprcode => 'numeric_fac' },
diff --git a/src/include/catalog/pg_opfamily.dat b/src/include/catalog/pg_opfamily.dat
index 41e40d657a..45dd8a5701 100644
--- a/src/include/catalog/pg_opfamily.dat
+++ b/src/include/catalog/pg_opfamily.dat
@@ -110,6 +110,8 @@
opfmethod => 'btree', opfname => 'tid_ops' },
{ oid => '2225',
opfmethod => 'hash', opfname => 'xid_ops' },
+{ oid => '8164',
+ opfmethod => 'hash', opfname => 'xid8_ops' },
{ oid => '2226',
opfmethod => 'hash', opfname => 'cid_ops' },
{ oid => '2227',
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index ac8f64b219..348b528dad 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -112,6 +112,18 @@
{ oid => '51', descr => 'I/O',
proname => 'xidout', prorettype => 'cstring', proargtypes => 'xid',
prosrc => 'xidout' },
+{ oid => '9553', descr => 'I/O',
+ proname => 'xid8in', prorettype => 'xid8', proargtypes => 'cstring',
+ prosrc => 'xid8in' },
+{ oid => '9554', descr => 'I/O',
+ proname => 'xid8out', prorettype => 'cstring', proargtypes => 'xid8',
+ prosrc => 'xid8out' },
+{ oid => '9555', descr => 'I/O',
+ proname => 'xid8recv', prorettype => 'xid8', proargtypes => 'internal',
+ prosrc => 'xid8recv' },
+{ oid => '9556', descr => 'I/O',
+ proname => 'xid8send', prorettype => 'bytea', proargtypes => 'xid8',
+ prosrc => 'xid8send' },
{ oid => '52', descr => 'I/O',
proname => 'cidin', prorettype => 'cid', proargtypes => 'cstring',
prosrc => 'cidin' },
@@ -163,6 +175,15 @@
{ oid => '3308',
proname => 'xidneq', proleakproof => 't', prorettype => 'bool',
proargtypes => 'xid xid', prosrc => 'xidneq' },
+{ oid => '9557',
+ proname => 'xid8eq', proleakproof => 't', prorettype => 'bool',
+ proargtypes => 'xid8 xid8', prosrc => 'xid8eq' },
+{ oid => '9558',
+ proname => 'xid8neq', proleakproof => 't', prorettype => 'bool',
+ proargtypes => 'xid8 xid8', prosrc => 'xid8neq' },
+{ oid => '9559', descr => 'convert xid8 to xid',
+ proname => 'xid', prorettype => 'xid', proargtypes => 'xid8',
+ prosrc => 'xid8toxid' },
{ oid => '69',
proname => 'cideq', proleakproof => 't', prorettype => 'bool',
proargtypes => 'cid cid', prosrc => 'cideq' },
diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat
index d9b35af914..fadef93aca 100644
--- a/src/include/catalog/pg_type.dat
+++ b/src/include/catalog/pg_type.dat
@@ -177,6 +177,10 @@
typtype => 'p', typcategory => 'P', typinput => 'pg_ddl_command_in',
typoutput => 'pg_ddl_command_out', typreceive => 'pg_ddl_command_recv',
typsend => 'pg_ddl_command_send', typalign => 'ALIGNOF_POINTER' },
+{ oid => '9560', array_type_oid => '271', descr => 'full transaction id',
+ typname => 'xid8', typlen => '8', typbyval => 'FLOAT8PASSBYVAL',
+ typcategory => 'U', typinput => 'xid8in', typoutput => 'xid8out',
+ typreceive => 'xid8recv', typsend => 'xid8send', typalign => 'd' },
# OIDS 600 - 699
diff --git a/src/include/utils/xid8.h b/src/include/utils/xid8.h
new file mode 100644
index 0000000000..3919b2f195
--- /dev/null
+++ b/src/include/utils/xid8.h
@@ -0,0 +1,22 @@
+/*-------------------------------------------------------------------------
+ *
+ * xid8.h
+ * Header file for the "xid8" ADT.
+ *
+ * Copyright (c) 2019, PostgreSQL Global Development Group
+ *
+ * src/include/utils/xid8.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef XID8_H
+#define XID8_H
+
+#include "access/transam.h"
+
+#define DatumGetFullTransactionId(X) (FullTransactionIdFromU64(DatumGetUInt64(X)))
+#define FullTransactionIdGetDatum(X) (UInt64GetDatum(U64FromFullTransactionId(X)))
+#define PG_GETARG_FULLTRANSACTIONID(X) DatumGetFullTransactionId(PG_GETARG_DATUM(X))
+#define PG_RETURN_FULLTRANSACTIONID(X) return FullTransactionIdGetDatum(X)
+
+#endif /* XID8_H */
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index c19740e5db..dcaf31eb7b 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -790,6 +790,8 @@ macaddr8_gt(macaddr8,macaddr8)
macaddr8_ge(macaddr8,macaddr8)
macaddr8_ne(macaddr8,macaddr8)
macaddr8_cmp(macaddr8,macaddr8)
+xid8eq(xid8,xid8)
+xid8neq(xid8,xid8)
-- restore normal output mode
\a\t
-- List of functions used by libpq's fe-lobj.c
--
2.23.0