Add SQL type xid8 to expose FullTransactionId to users.
authorThomas Munro <[email protected]>
Mon, 6 Apr 2020 23:08:14 +0000 (11:08 +1200)
committerThomas Munro <[email protected]>
Tue, 7 Apr 2020 00:03:59 +0000 (12:03 +1200)
Similar to xid, but 64 bits wide.  This new type is suitable for use in
various system views and administration functions.

Reviewed-by: Fujii Masao <[email protected]>
Reviewed-by: Takao Fujii <[email protected]>
Reviewed-by: Yoshikazu Imai <[email protected]>
Reviewed-by: Mark Dilger <[email protected]>
Discussion: https://postgr.es/m/20190725000636.666m5mad25wfbrri%40alap3.anarazel.de

20 files changed:
doc/src/sgml/datatype.sgml
src/backend/access/hash/hashvalidate.c
src/backend/utils/adt/xid.c
src/fe_utils/print.c
src/include/access/transam.h
src/include/catalog/catversion.h
src/include/catalog/pg_amop.dat
src/include/catalog/pg_amproc.dat
src/include/catalog/pg_cast.dat
src/include/catalog/pg_opclass.dat
src/include/catalog/pg_operator.dat
src/include/catalog/pg_opfamily.dat
src/include/catalog/pg_proc.dat
src/include/catalog/pg_type.dat
src/include/utils/xid8.h [new file with mode: 0644]
src/test/regress/expected/opr_sanity.out
src/test/regress/expected/xid.out [new file with mode: 0644]
src/test/regress/parallel_schedule
src/test/regress/serial_schedule
src/test/regress/sql/xid.sql [new file with mode: 0644]

index 03971822c293bcc80f1a9764e25fc9ab815a3429..89f3a7c1196d4056d8a4a127ffe0f5f2b17d159d 100644 (file)
@@ -4516,6 +4516,10 @@ INSERT INTO mytable VALUES(-1);  -- fails
     <primary>regtype</primary>
    </indexterm>
 
+   <indexterm zone="datatype-oid">
+    <primary>xid8</primary>
+   </indexterm>
+
    <indexterm zone="datatype-oid">
     <primary>cid</primary>
    </indexterm>
@@ -4719,6 +4723,9 @@ SELECT * FROM pg_attribute
     Another identifier type used by the system is <type>xid</type>, or transaction
     (abbreviated <abbrev>xact</abbrev>) identifier.  This is the data type of the system columns
     <structfield>xmin</structfield> and <structfield>xmax</structfield>.  Transaction identifiers are 32-bit quantities.
+    In some contexts, a 64-bit variant <type>xid8</type> is used.  Unlike
+    <type>xid</type> values, <type>xid8</type> values increase strictly
+    monotonically and cannot be reused in the lifetime of a database cluster.
    </para>
 
    <para>
index 7b08ed535437d0033bcbbc0320aefb6aa6e9b796..b3d1367fecb0e83e41a7c09dc27a2386a814b2f8 100644 (file)
@@ -317,6 +317,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)
index db6fc9dd6b8342c7839eb8007e8e07152992a468..20389aff1d12a4f388b224eca855cb549d6a7e3d 100644 (file)
@@ -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,121 @@ 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);
+
+   PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(pg_strtouint64(str, NULL, 0)));
+}
+
+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
+xid8ne(PG_FUNCTION_ARGS)
+{
+   FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
+   FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
+
+   PG_RETURN_BOOL(!FullTransactionIdEquals(fxid1, fxid2));
+}
+
+Datum
+xid8lt(PG_FUNCTION_ARGS)
+{
+   FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
+   FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
+
+   PG_RETURN_BOOL(FullTransactionIdPrecedes(fxid1, fxid2));
+}
+
+Datum
+xid8gt(PG_FUNCTION_ARGS)
+{
+   FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
+   FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
+
+   PG_RETURN_BOOL(FullTransactionIdFollows(fxid1, fxid2));
+}
+
+Datum
+xid8le(PG_FUNCTION_ARGS)
+{
+   FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
+   FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
+
+   PG_RETURN_BOOL(FullTransactionIdPrecedesOrEquals(fxid1, fxid2));
+}
+
+Datum
+xid8ge(PG_FUNCTION_ARGS)
+{
+   FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
+   FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
+
+   PG_RETURN_BOOL(FullTransactionIdFollowsOrEquals(fxid1, fxid2));
+}
+
+Datum
+xid8cmp(PG_FUNCTION_ARGS)
+{
+   FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
+   FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
+
+   if (FullTransactionIdFollows(fxid1, fxid2))
+       PG_RETURN_INT32(1);
+   else if (FullTransactionIdEquals(fxid1, fxid2))
+       PG_RETURN_INT32(0);
+   else
+       PG_RETURN_INT32(-1);
+}
+
 /*****************************************************************************
  *  COMMAND IDENTIFIER ROUTINES                                             *
  *****************************************************************************/
index 06096cc86cb1e3067083d1764f0d007b2238efad..66a50f183f52597a1efb468e22927e801a7c02ee 100644 (file)
@@ -3509,6 +3509,7 @@ column_type_alignment(Oid ftype)
        case NUMERICOID:
        case OIDOID:
        case XIDOID:
+       case XID8OID:
        case CIDOID:
        case CASHOID:
            align = 'r';
index 6a947b958b0b5040ae828c6ba811022fae9b9f64..9a808f64ebe253fb0c0f8977865a196f8fe3e111 100644 (file)
 #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 FullTransactionIdPrecedesOrEquals(a, b) ((a).value <= (b).value)
+#define FullTransactionIdFollows(a, b) ((a).value > (b).value)
+#define FullTransactionIdFollowsOrEquals(a, b) ((a).value >= (b).value)
 #define FullTransactionIdIsValid(x)        TransactionIdIsValid(XidFromFullTransactionId(x))
 #define InvalidFullTransactionId       FullTransactionIdFromEpochAndXid(0, InvalidTransactionId)
 
@@ -71,6 +75,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 { \
index 6d91fa2bde31f29eb091c4f4c29dc47dd879ccd9..4201790ec48c0eb9d0a08eacda8f93562765deac 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 202004022
+#define CATALOG_VERSION_NO 202004061
 
 #endif
index 11aaa519c8bbf40bb99f8e57a67b45569001cc8a..b5dfaad9ec0edbdd460f79a52b7270b9d62ff9b1 100644 (file)
 { amopfamily => 'btree/oid_ops', amoplefttype => 'oid', amoprighttype => 'oid',
   amopstrategy => '5', amopopr => '>(oid,oid)', amopmethod => 'btree' },
 
+# btree xid8_ops
+
+{ amopfamily => 'btree/xid8_ops', amoplefttype => 'xid8',
+  amoprighttype => 'xid8', amopstrategy => '1', amopopr => '<(xid8,xid8)',
+  amopmethod => 'btree' },
+{ amopfamily => 'btree/xid8_ops', amoplefttype => 'xid8',
+  amoprighttype => 'xid8', amopstrategy => '2', amopopr => '<=(xid8,xid8)',
+  amopmethod => 'btree' },
+{ amopfamily => 'btree/xid8_ops', amoplefttype => 'xid8',
+  amoprighttype => 'xid8', amopstrategy => '3', amopopr => '=(xid8,xid8)',
+  amopmethod => 'btree' },
+{ amopfamily => 'btree/xid8_ops', amoplefttype => 'xid8',
+  amoprighttype => 'xid8', amopstrategy => '4', amopopr => '>=(xid8,xid8)',
+  amopmethod => 'btree' },
+{ amopfamily => 'btree/xid8_ops', amoplefttype => 'xid8',
+  amoprighttype => 'xid8', amopstrategy => '5', amopopr => '>(xid8,xid8)',
+  amopmethod => 'btree' },
+
 # btree tid_ops
 
 { amopfamily => 'btree/tid_ops', amoplefttype => 'tid', amoprighttype => 'tid',
 { amopfamily => 'hash/xid_ops', amoplefttype => 'xid', amoprighttype => 'xid',
   amopstrategy => '1', amopopr => '=(xid,xid)', amopmethod => 'hash' },
 
+# xid8_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' },
index cef63b2a716bf9665d104ef38572f35424e06494..37b580883fcb90cb5807fa55332bde14fe086be4 100644 (file)
   amprocrighttype => 'anyrange', amprocnum => '1', amproc => 'range_cmp' },
 { amprocfamily => 'btree/jsonb_ops', amproclefttype => 'jsonb',
   amprocrighttype => 'jsonb', amprocnum => '1', amproc => 'jsonb_cmp' },
+{ amprocfamily => 'btree/xid8_ops', amproclefttype => 'xid8',
+  amprocrighttype => 'xid8', amprocnum => '1', amproc => 'xid8cmp' },
+{ amprocfamily => 'btree/xid8_ops', amproclefttype => 'xid8',
+  amprocrighttype => 'xid8', amprocnum => '4', amproc => 'btequalimage' },
 
 # hash
 { amprocfamily => 'hash/bpchar_ops', amproclefttype => 'bpchar',
   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',
index 01c5328dddb3b649f719a7b7f440e4252de27ce1..5a58f50fbb2367d85051ad4a469c6dfeb2910b24 100644 (file)
 { 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
index ab2f50c9eb3b5d10970e690526739cc736a1baa1..f2342bb328cb7b167111e473b0991cc3a360808f 100644 (file)
   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 => 'btree', opcname => 'xid8_ops', opcfamily => 'btree/xid8_ops',
+  opcintype => 'xid8' },
 { opcmethod => 'hash', opcname => 'cid_ops', opcfamily => 'hash/cid_ops',
   opcintype => 'cid' },
 { opcmethod => 'hash', opcname => 'tid_ops', opcfamily => 'hash/tid_ops',
index 65c7fedf237bdcc30f5304f5e33734bab76a37d2..00ada7e48fc1d0f2a3b67fd74dd20affbc0387eb 100644 (file)
   oprname => '<>', oprleft => 'xid', oprright => 'int4', oprresult => 'bool',
   oprnegate => '=(xid,int4)', oprcode => 'xidneqint4', oprrest => 'neqsel',
   oprjoin => 'neqjoinsel' },
+{ oid => '9418', descr => 'equal',
+  oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'xid8',
+  oprright => 'xid8', oprresult => 'bool', oprcom => '=(xid8,xid8)',
+  oprnegate => '<>(xid8,xid8)', oprcode => 'xid8eq', oprrest => 'eqsel',
+  oprjoin => 'eqjoinsel' },
+{ oid => '9422', descr => 'not equal',
+  oprname => '<>', oprleft => 'xid8', oprright => 'xid8',
+  oprresult => 'bool', oprcom => '<>(xid8,xid8)', oprnegate => '=(xid8,xid8)',
+  oprcode => 'xid8ne', oprrest => 'neqsel', oprjoin => 'neqjoinsel' },
+{ oid => '9432', descr => 'less than',
+  oprname => '<', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool',
+  oprcom => '>(xid8,xid8)', oprnegate => '>=(xid8,xid8)', oprcode => 'xid8lt',
+  oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' },
+{ oid => '9433', descr => 'greater than',
+  oprname => '>', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool',
+  oprcom => '<(xid8,xid8)', oprnegate => '<=(xid8,xid8)', oprcode => 'xid8gt',
+  oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' },
+{ oid => '9434', descr => 'less than or equal',
+  oprname => '<=', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool',
+  oprcom => '>=(xid8,xid8)', oprnegate => '>(xid8,xid8)', oprcode => 'xid8le',
+  oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' },
+{ oid => '9435', descr => 'greater than or equal',
+  oprname => '>=', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool',
+  oprcom => '<=(xid8,xid8)', oprnegate => '<(xid8,xid8)', oprcode => 'xid8ge',
+  oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' },
 { oid => '388', descr => 'factorial',
   oprname => '!', oprkind => 'r', oprleft => 'int8', oprright => '0',
   oprresult => 'numeric', oprcode => 'numeric_fac' },
index 26227df2165cd552e553286cbfbfadddd329e12c..4004138d77896dd6d6d946cfe8277036541378cd 100644 (file)
   opfmethod => 'btree', opfname => 'tid_ops' },
 { oid => '2225',
   opfmethod => 'hash', opfname => 'xid_ops' },
+{ oid => '8164',
+  opfmethod => 'hash', opfname => 'xid8_ops' },
+{ oid => '9322',
+  opfmethod => 'btree', opfname => 'xid8_ops' },
 { oid => '2226',
   opfmethod => 'hash', opfname => 'cid_ops' },
 { oid => '2227',
index a649e44d0891999b6857cdde2debb61d7e9b182e..6be7e4f1571734ebf95eef19451f16054a59eb05 100644 (file)
 { oid => '51', descr => 'I/O',
   proname => 'xidout', prorettype => 'cstring', proargtypes => 'xid',
   prosrc => 'xidout' },
+{ oid => '9420', 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' },
 { 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 => 'xid8ne', proleakproof => 't', prorettype => 'bool',
+  proargtypes => 'xid8 xid8', prosrc => 'xid8ne' },
+{ oid => '8295',
+  proname => 'xid8lt', proleakproof => 't', prorettype => 'bool',
+  proargtypes => 'xid8 xid8', prosrc => 'xid8lt' },
+{ oid => '8296',
+  proname => 'xid8gt', proleakproof => 't', prorettype => 'bool',
+  proargtypes => 'xid8 xid8', prosrc => 'xid8gt' },
+{ oid => '8297',
+  proname => 'xid8le', proleakproof => 't', prorettype => 'bool',
+  proargtypes => 'xid8 xid8', prosrc => 'xid8le' },
+{ oid => '8298',
+  proname => 'xid8ge', proleakproof => 't', prorettype => 'bool',
+  proargtypes => 'xid8 xid8', prosrc => 'xid8ge' },
+{ oid => '9912', descr => 'less-equal-greater',
+  proname => 'xid8cmp', proleakproof => 't', prorettype => 'int4',
+  proargtypes => 'xid8 xid8', prosrc => 'xid8cmp' },
+{ oid => '9421', 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' },
index 2e6110e3f2ca91bc5b72cc118c99a3c278fe0edc..a1f441b8daa8aadacceef489d352b61a795709ec 100644 (file)
   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 => '9419', 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 (file)
index 0000000..288e62d
--- /dev/null
@@ -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 */
index 2efd7d7ec74e76327e85c39a30308c3c6b060930..0c03afe53d20952cc163b66017bbba76e91204fa 100644 (file)
@@ -832,6 +832,13 @@ macaddr8_gt(macaddr8,macaddr8)
 macaddr8_ge(macaddr8,macaddr8)
 macaddr8_ne(macaddr8,macaddr8)
 macaddr8_cmp(macaddr8,macaddr8)
+xid8lt(xid8,xid8)
+xid8gt(xid8,xid8)
+xid8le(xid8,xid8)
+xid8ge(xid8,xid8)
+xid8eq(xid8,xid8)
+xid8ne(xid8,xid8)
+xid8cmp(xid8,xid8)
 -- restore normal output mode
 \a\t
 -- List of functions used by libpq's fe-lobj.c
diff --git a/src/test/regress/expected/xid.out b/src/test/regress/expected/xid.out
new file mode 100644 (file)
index 0000000..e9e1fa8
--- /dev/null
@@ -0,0 +1,136 @@
+-- xid and xid8
+-- values in range, in octal, decimal, hex
+select '010'::xid,
+       '42'::xid,
+       '0xffffffff'::xid,
+       '-1'::xid,
+      '010'::xid8,
+      '42'::xid8,
+      '0xffffffffffffffff'::xid8,
+      '-1'::xid8;
+ xid | xid |    xid     |    xid     | xid8 | xid8 |         xid8         |         xid8         
+-----+-----+------------+------------+------+------+----------------------+----------------------
+   8 |  42 | 4294967295 | 4294967295 |    8 |   42 | 18446744073709551615 | 18446744073709551615
+(1 row)
+
+-- garbage values are not yet rejected (perhaps they should be)
+select ''::xid;
+ xid 
+-----
+   0
+(1 row)
+
+select 'asdf'::xid;
+ xid 
+-----
+   0
+(1 row)
+
+select ''::xid8;
+ xid8 
+------
+    0
+(1 row)
+
+select 'asdf'::xid8;
+ xid8 
+------
+    0
+(1 row)
+
+-- equality
+select '1'::xid = '1'::xid;
+ ?column? 
+----------
+ t
+(1 row)
+
+select '1'::xid != '1'::xid;
+ ?column? 
+----------
+ f
+(1 row)
+
+select '1'::xid8 = '1'::xid8;
+ ?column? 
+----------
+ t
+(1 row)
+
+select '1'::xid8 != '1'::xid8;
+ ?column? 
+----------
+ f
+(1 row)
+
+-- conversion
+select '1'::xid = '1'::xid8::xid;
+ ?column? 
+----------
+ t
+(1 row)
+
+select '1'::xid != '1'::xid8::xid;
+ ?column? 
+----------
+ f
+(1 row)
+
+-- we don't want relational operators for xid, due to use of modular arithmetic
+select '1'::xid < '2'::xid;
+ERROR:  operator does not exist: xid < xid
+LINE 1: select '1'::xid < '2'::xid;
+                        ^
+HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+select '1'::xid <= '2'::xid;
+ERROR:  operator does not exist: xid <= xid
+LINE 1: select '1'::xid <= '2'::xid;
+                        ^
+HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+select '1'::xid > '2'::xid;
+ERROR:  operator does not exist: xid > xid
+LINE 1: select '1'::xid > '2'::xid;
+                        ^
+HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+select '1'::xid >= '2'::xid;
+ERROR:  operator does not exist: xid >= xid
+LINE 1: select '1'::xid >= '2'::xid;
+                        ^
+HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+-- we want them for xid8 though
+select '1'::xid8 < '2'::xid8, '2'::xid8 < '2'::xid8, '2'::xid8 < '1'::xid8;
+ ?column? | ?column? | ?column? 
+----------+----------+----------
+ t        | f        | f
+(1 row)
+
+select '1'::xid8 <= '2'::xid8, '2'::xid8 <= '2'::xid8, '2'::xid8 <= '1'::xid8;
+ ?column? | ?column? | ?column? 
+----------+----------+----------
+ t        | t        | f
+(1 row)
+
+select '1'::xid8 > '2'::xid8, '2'::xid8 > '2'::xid8, '2'::xid8 > '1'::xid8;
+ ?column? | ?column? | ?column? 
+----------+----------+----------
+ f        | f        | t
+(1 row)
+
+select '1'::xid8 >= '2'::xid8, '2'::xid8 >= '2'::xid8, '2'::xid8 >= '1'::xid8;
+ ?column? | ?column? | ?column? 
+----------+----------+----------
+ f        | t        | t
+(1 row)
+
+-- we also have a 3way compare for btrees
+select xid8cmp('1', '2'), xid8cmp('2', '2'), xid8cmp('2', '1');
+ xid8cmp | xid8cmp | xid8cmp 
+---------+---------+---------
+      -1 |       0 |       1
+(1 row)
+
+-- xid8 has btree and hash opclasses
+create table xid8_t1 (x xid8);
+create index on xid8_t1 using btree(x);
+create index on xid8_t1 using hash(x);
+drop table xid8_t1;
index a741e89616a51933207eae1c8e75cc9b3200800c..95f1925072b09c8ece25517a895316937e45c42d 100644 (file)
@@ -20,7 +20,7 @@ test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeri
 # strings depends on char, varchar and text
 # numerology depends on int2, int4, int8, float4, float8
 # ----------
-test: strings numerology point lseg line box path polygon circle date time timetz timestamp timestamptz interval inet macaddr macaddr8 tstypes
+test: strings numerology point lseg line box path polygon circle date time timetz timestamp timestamptz interval inet macaddr macaddr8 tstypes xid
 
 # ----------
 # Another group of parallel tests
index 1a6821ca46b445c4590f88d91cf83eade80c77f0..8ba413622027c63929696dd780757557cf235806 100644 (file)
@@ -10,6 +10,7 @@ test: int2
 test: int4
 test: int8
 test: oid
+test: xid
 test: float4
 test: float8
 test: bit
diff --git a/src/test/regress/sql/xid.sql b/src/test/regress/sql/xid.sql
new file mode 100644 (file)
index 0000000..a4fbca5
--- /dev/null
@@ -0,0 +1,48 @@
+-- xid and xid8
+
+-- values in range, in octal, decimal, hex
+select '010'::xid,
+       '42'::xid,
+       '0xffffffff'::xid,
+       '-1'::xid,
+      '010'::xid8,
+      '42'::xid8,
+      '0xffffffffffffffff'::xid8,
+      '-1'::xid8;
+
+-- garbage values are not yet rejected (perhaps they should be)
+select ''::xid;
+select 'asdf'::xid;
+select ''::xid8;
+select 'asdf'::xid8;
+
+-- equality
+select '1'::xid = '1'::xid;
+select '1'::xid != '1'::xid;
+select '1'::xid8 = '1'::xid8;
+select '1'::xid8 != '1'::xid8;
+
+-- conversion
+select '1'::xid = '1'::xid8::xid;
+select '1'::xid != '1'::xid8::xid;
+
+-- we don't want relational operators for xid, due to use of modular arithmetic
+select '1'::xid < '2'::xid;
+select '1'::xid <= '2'::xid;
+select '1'::xid > '2'::xid;
+select '1'::xid >= '2'::xid;
+
+-- we want them for xid8 though
+select '1'::xid8 < '2'::xid8, '2'::xid8 < '2'::xid8, '2'::xid8 < '1'::xid8;
+select '1'::xid8 <= '2'::xid8, '2'::xid8 <= '2'::xid8, '2'::xid8 <= '1'::xid8;
+select '1'::xid8 > '2'::xid8, '2'::xid8 > '2'::xid8, '2'::xid8 > '1'::xid8;
+select '1'::xid8 >= '2'::xid8, '2'::xid8 >= '2'::xid8, '2'::xid8 >= '1'::xid8;
+
+-- we also have a 3way compare for btrees
+select xid8cmp('1', '2'), xid8cmp('2', '2'), xid8cmp('2', '1');
+
+-- xid8 has btree and hash opclasses
+create table xid8_t1 (x xid8);
+create index on xid8_t1 using btree(x);
+create index on xid8_t1 using hash(x);
+drop table xid8_t1;