From c26d9fd2ec11c94720f236f7f3d89c773a13719d Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Tue, 28 Jan 2020 16:36:36 +1300 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, Yoshikazu Imai, Mark Dilger 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/catversion.h | 2 +- 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 + 15 files changed, 163 insertions(+), 1 deletion(-) 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 6346e65865..2f2858021c 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 db6fc9dd6b..f0c317e7b1 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 06096cc86c..66a50f183f 100644 --- a/src/fe_utils/print.c +++ b/src/fe_utils/print.c @@ -3509,6 +3509,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 6a947b958b..4dc9a0c67b 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/catversion.h b/src/include/catalog/catversion.h index 249b1f5a34..efd5df5517 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202001251 +#define CATALOG_VERSION_NO 202001271 #endif diff --git a/src/include/catalog/pg_amop.dat b/src/include/catalog/pg_amop.dat index 11aaa519c8..a2ac3b8b5b 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 c67768fcab..dd3d29822b 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 6ef8b8a4e7..13389d4695 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 ab2f50c9eb..50837463fb 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 7c135da3b1..38bac36361 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 26227df216..ba5c770c65 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 bef50c76d9..95a888e060 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 fe2c4eabb4..89d9c40e42 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..288e62de9c --- /dev/null +++ b/src/include/utils/xid8.h @@ -0,0 +1,22 @@ +/*------------------------------------------------------------------------- + * + * xid8.h + * Header file for the "xid8" ADT. + * + * Copyright (c) 2020, 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