Introduce xid8-based functions to replace txid_XXX.
authorThomas Munro <tmunro@postgresql.org>
Mon, 6 Apr 2020 23:33:56 +0000 (11:33 +1200)
committerThomas Munro <tmunro@postgresql.org>
Tue, 7 Apr 2020 00:04:32 +0000 (12:04 +1200)
The txid_XXX family of fmgr functions exposes 64 bit transaction IDs to
users as int8.  Now that we have an SQL type xid8 for FullTransactionId,
define a new set of functions including pg_current_xact_id() and
pg_current_snapshot() based on that.  Keep the old functions around too,
for now.

It's a bit sneaky to use the same C functions for both, but since the
binary representation is identical except for the signedness of the
type, and since older functions are the ones using the wrong signedness,
and since we'll presumably drop the older ones after a reasonable period
of time, it seems reasonable to switch to FullTransactionId internally
and share the code for both.

Reviewed-by: Fujii Masao <masao.fujii@oss.nttdata.com>
Reviewed-by: Takao Fujii <btfujiitkp@oss.nttdata.com>
Reviewed-by: Yoshikazu Imai <imai.yoshikazu@fujitsu.com>
Reviewed-by: Mark Dilger <mark.dilger@enterprisedb.com>
Discussion: https://postgr.es/m/20190725000636.666m5mad25wfbrri%40alap3.anarazel.de

36 files changed:
contrib/test_decoding/expected/ddl.out
contrib/test_decoding/expected/decoding_in_xact.out
contrib/test_decoding/expected/oldest_xmin.out
contrib/test_decoding/expected/ondisk_startup.out
contrib/test_decoding/expected/snapshot_transfer.out
contrib/test_decoding/specs/oldest_xmin.spec
contrib/test_decoding/specs/ondisk_startup.spec
contrib/test_decoding/specs/snapshot_transfer.spec
contrib/test_decoding/sql/ddl.sql
contrib/test_decoding/sql/decoding_in_xact.sql
doc/src/sgml/datatype.sgml
doc/src/sgml/func.sgml
doc/src/sgml/logicaldecoding.sgml
doc/src/sgml/monitoring.sgml
src/backend/utils/adt/Makefile
src/backend/utils/adt/xid8funcs.c [moved from src/backend/utils/adt/txid.c with 54% similarity]
src/include/catalog/catversion.h
src/include/catalog/pg_proc.dat
src/include/catalog/pg_type.dat
src/test/modules/commit_ts/t/004_restart.pl
src/test/modules/test_ddl_deparse/expected/create_table.out
src/test/modules/test_ddl_deparse/sql/create_table.sql
src/test/recovery/t/003_recovery_targets.pl
src/test/recovery/t/011_crash_recovery.pl
src/test/regress/expected/alter_table.out
src/test/regress/expected/hs_standby_functions.out
src/test/regress/expected/opr_sanity.out
src/test/regress/expected/txid.out
src/test/regress/expected/update.out
src/test/regress/expected/xid.out
src/test/regress/sql/alter_table.sql
src/test/regress/sql/hs_standby_functions.sql
src/test/regress/sql/txid.sql
src/test/regress/sql/update.sql
src/test/regress/sql/xid.sql
src/tools/pgindent/typedefs.list

index cf0318f69771df6b90ac48950cc67f01b06e30de..d79cd316b79fccc7c65b297352151c2f132c1f3d 100644 (file)
@@ -382,7 +382,7 @@ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'inc
 -- test whether a known, but not yet logged toplevel xact, followed by a
 -- subxact commit is handled correctly
 BEGIN;
-SELECT txid_current() != 0; -- so no fixed xid apears in the outfile
+SELECT pg_current_xact_id() != '0'; -- so no fixed xid apears in the outfile
  ?column? 
 ----------
  t
index ab4d3aee723db94cc39c0d190a25db514855a56b..b65253f4630916521aad5a572a221ba41a2df265 100644 (file)
@@ -2,7 +2,7 @@
 SET synchronous_commit = on;
 -- fail because we're creating a slot while in an xact with xid
 BEGIN;
-SELECT txid_current() = 0;
+SELECT pg_current_xact_id() = '0';
  ?column? 
 ----------
  f
@@ -13,7 +13,7 @@ ERROR:  cannot create logical replication slot in transaction that has performed
 ROLLBACK;
 -- fail because we're creating a slot while in a subxact whose topxact has an xid
 BEGIN;
-SELECT txid_current() = 0;
+SELECT pg_current_xact_id() = '0';
  ?column? 
 ----------
  f
@@ -50,7 +50,7 @@ CREATE TABLE nobarf(id serial primary key, data text);
 INSERT INTO nobarf(data) VALUES('1');
 -- decoding works in transaction with xid
 BEGIN;
-SELECT txid_current() = 0;
+SELECT pg_current_xact_id() = '0';
  ?column? 
 ----------
  f
index d1b4f17e3aadd5880bd74255c40b797411bc76a0..02a091398fc15b02daddfc00cb1a40cd5bb346e2 100644 (file)
@@ -2,7 +2,7 @@ Parsed test spec with 2 sessions
 
 starting permutation: s0_begin s0_getxid s1_begin s1_insert s0_alter s0_commit s0_checkpoint s0_get_changes s0_get_changes s1_commit s0_vacuum s0_get_changes
 step s0_begin: BEGIN;
-step s0_getxid: SELECT txid_current() IS NULL;
+step s0_getxid: SELECT pg_current_xact_id() IS NULL;
 ?column?       
 
 f              
index c7b1f45b46b53dc4e092de401f07614f5d48d755..586b03d75dbb8bb16d9980d76ae9fc18e0356b62 100644 (file)
@@ -2,20 +2,20 @@ Parsed test spec with 3 sessions
 
 starting permutation: s2b s2txid s1init s3b s3txid s2alter s2c s2b s2txid s3c s2c s1insert s1checkpoint s1start s1insert s1alter s1insert s1start
 step s2b: BEGIN;
-step s2txid: SELECT txid_current() IS NULL;
+step s2txid: SELECT pg_current_xact_id() IS NULL;
 ?column?       
 
 f              
 step s1init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding'); <waiting ...>
 step s3b: BEGIN;
-step s3txid: SELECT txid_current() IS NULL;
+step s3txid: SELECT pg_current_xact_id() IS NULL;
 ?column?       
 
 f              
 step s2alter: ALTER TABLE do_write ADD COLUMN addedbys2 int;
 step s2c: COMMIT;
 step s2b: BEGIN;
-step s2txid: SELECT txid_current() IS NULL;
+step s2txid: SELECT pg_current_xact_id() IS NULL;
 ?column?       
 
 f              
index 87bed03f766c1dccc85aa848b23e93e3d0ef98e1..c3a00009946bef1c2d7afaed5cbe8103fd956f81 100644 (file)
@@ -3,7 +3,7 @@ Parsed test spec with 2 sessions
 starting permutation: s0_begin s0_begin_sub0 s0_log_assignment s0_sub_get_base_snap s1_produce_new_snap s0_insert s0_end_sub0 s0_commit s0_get_changes
 step s0_begin: BEGIN;
 step s0_begin_sub0: SAVEPOINT s0;
-step s0_log_assignment: SELECT txid_current() IS NULL;
+step s0_log_assignment: SELECT pg_current_xact_id() IS NULL;
 ?column?       
 
 f              
@@ -26,7 +26,7 @@ stop
 starting permutation: s0_begin s0_begin_sub0 s0_log_assignment s0_begin_sub1 s0_sub_get_base_snap s1_produce_new_snap s0_insert s0_end_sub1 s0_end_sub0 s0_commit s0_get_changes
 step s0_begin: BEGIN;
 step s0_begin_sub0: SAVEPOINT s0;
-step s0_log_assignment: SELECT txid_current() IS NULL;
+step s0_log_assignment: SELECT pg_current_xact_id() IS NULL;
 ?column?       
 
 f              
index 6cb13e85cec77b2161de4a3e4594b0db7fc9fe2d..da3a8cd512dbac6a096459eda912aa6b864ef67f 100644 (file)
@@ -19,7 +19,7 @@ teardown
 session "s0"
 setup { SET synchronous_commit=on; }
 step "s0_begin" { BEGIN; }
-step "s0_getxid" { SELECT txid_current() IS NULL; }
+step "s0_getxid" { SELECT pg_current_xact_id() IS NULL; }
 step "s0_alter" { ALTER TYPE basket DROP ATTRIBUTE mangos; }
 step "s0_commit" { COMMIT; }
 step "s0_checkpoint" { CHECKPOINT; }
index 12c57a813da2b8ed1e3a0e49301a23f2216d56a2..96ce87f1a45baf69a18cac3c0bfd78c429a72c9d 100644 (file)
@@ -25,7 +25,7 @@ session "s2"
 setup { SET synchronous_commit=on; }
 
 step "s2b" { BEGIN; }
-step "s2txid" { SELECT txid_current() IS NULL; }
+step "s2txid" { SELECT pg_current_xact_id() IS NULL; }
 step "s2alter" { ALTER TABLE do_write ADD COLUMN addedbys2 int; }
 step "s2c" { COMMIT; }
 
@@ -34,7 +34,7 @@ session "s3"
 setup { SET synchronous_commit=on; }
 
 step "s3b" { BEGIN; }
-step "s3txid" { SELECT txid_current() IS NULL; }
+step "s3txid" { SELECT pg_current_xact_id() IS NULL; }
 step "s3c" { COMMIT; }
 
 # Force usage of ondisk snapshot by starting and not finishing a
index ae81e8f102d265d921270b0b2e185f5c1370094f..152f2fd03d97983eeeb7f1305f00db64b8322758 100644 (file)
@@ -20,7 +20,7 @@ session "s0"
 setup { SET synchronous_commit=on; }
 step "s0_begin" { BEGIN; }
 step "s0_begin_sub0" { SAVEPOINT s0; }
-step "s0_log_assignment" { SELECT txid_current() IS NULL; }
+step "s0_log_assignment" { SELECT pg_current_xact_id() IS NULL; }
 step "s0_begin_sub1" { SAVEPOINT s1; }
 step "s0_sub_get_base_snap" { INSERT INTO dummy VALUES (0); }
 step "s0_insert" { INSERT INTO harvest VALUES (1, 2, 3); }
index 0f2b9992f7ae4ff0638ab47b8411e86165d3f21f..2c4823e578057ad31ef40fedc8de23eebd7f49c4 100644 (file)
@@ -220,7 +220,7 @@ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'inc
 -- test whether a known, but not yet logged toplevel xact, followed by a
 -- subxact commit is handled correctly
 BEGIN;
-SELECT txid_current() != 0; -- so no fixed xid apears in the outfile
+SELECT pg_current_xact_id() != '0'; -- so no fixed xid apears in the outfile
 SAVEPOINT a;
 INSERT INTO tr_sub(path) VALUES ('4-top-1-#1');
 RELEASE SAVEPOINT a;
index b524eb9a6e01fe22698ec6573ec3c19ba4ff70ad..108782dc2e98d55944aec5982d8f109606289100 100644 (file)
@@ -3,13 +3,13 @@ SET synchronous_commit = on;
 
 -- fail because we're creating a slot while in an xact with xid
 BEGIN;
-SELECT txid_current() = 0;
+SELECT pg_current_xact_id() = '0';
 SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
 ROLLBACK;
 
 -- fail because we're creating a slot while in a subxact whose topxact has an xid
 BEGIN;
-SELECT txid_current() = 0;
+SELECT pg_current_xact_id() = '0';
 SAVEPOINT barf;
 SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
 ROLLBACK TO SAVEPOINT barf;
@@ -29,7 +29,7 @@ INSERT INTO nobarf(data) VALUES('1');
 
 -- decoding works in transaction with xid
 BEGIN;
-SELECT txid_current() = 0;
+SELECT pg_current_xact_id() = '0';
 -- don't show yet, haven't committed
 INSERT INTO nobarf(data) VALUES('2');
 SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
index 89f3a7c1196d4056d8a4a127ffe0f5f2b17d159d..c2e42f31c0062e7a2b70c65cd02e29c1584e2a84 100644 (file)
        <entry><productname>PostgreSQL</productname> Log Sequence Number</entry>
       </row>
 
+      <row>
+       <entry><type>pg_snapshot</type></entry>
+       <entry></entry>
+       <entry>user-level transaction ID snapshot</entry>
+      </row>
+
       <row>
        <entry><type>point</type></entry>
        <entry></entry>
       <row>
        <entry><type>txid_snapshot</type></entry>
        <entry></entry>
-       <entry>user-level transaction ID snapshot</entry>
+       <entry>user-level transaction ID snapshot (deprecated; see <type>pg_snapshot</type>)</entry>
       </row>
 
       <row>
index 4d88b45e726cd2087e1fe48b1a630d9249d3c135..cc4a7bf8dfa71708eb479e64be2a17d0dd3d3c15 100644 (file)
@@ -18998,6 +18998,38 @@ SELECT collation for ('foo' COLLATE "de_DE");
     are stored globally as well.
    </para>
 
+   <indexterm>
+    <primary>pg_current_xact_id</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>pg_current_xact_id_if_assigned</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>pg_current_snapshot</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>pg_snapshot_xip</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>pg_snapshot_xmax</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>pg_snapshot_xmin</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>pg_visible_in_snapshot</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>pg_xact_status</primary>
+   </indexterm>
+
    <indexterm>
     <primary>txid_current</primary>
    </indexterm>
@@ -19031,76 +19063,136 @@ SELECT collation for ('foo' COLLATE "de_DE");
    </indexterm>
 
    <para>
-    The functions shown in <xref linkend="functions-txid-snapshot"/>
+    The functions shown in <xref linkend="functions-pg-snapshot"/>
     provide server transaction information in an exportable form.  The main
     use of these functions is to determine which transactions were committed
     between two snapshots.
    </para>
 
-   <table id="functions-txid-snapshot">
+   <table id="functions-pg-snapshot">
     <title>Transaction IDs and Snapshots</title>
     <tgroup cols="3">
      <thead>
       <row><entry>Name</entry> <entry>Return Type</entry> <entry>Description</entry></row>
      </thead>
 
+     <tbody>
+      <row>
+       <entry><literal><function>pg_current_xact_id()</function></literal></entry>
+       <entry><type>xid8</type></entry>
+       <entry>get current transaction ID, assigning a new one if the current transaction does not have one</entry>
+      </row>
+      <row>
+       <entry><literal><function>pg_current_xact_id_if_assigned()</function></literal></entry>
+       <entry><type>xid8</type></entry>
+       <entry>same as <function>pg_current_xact_id()</function> but returns null instead of assigning a new transaction ID if none is already assigned</entry>
+      </row>
+      <row>
+       <entry><literal><function>pg_xact_status(<parameter>xid8</parameter>)</function></literal></entry>
+       <entry><type>text</type></entry>
+       <entry>report the status of the given transaction: <literal>committed</literal>, <literal>aborted</literal>, <literal>in progress</literal>, or null if the transaction ID is too old</entry>
+      </row>
+      <row>
+       <entry><literal><function>pg_current_snapshot()</function></literal></entry>
+       <entry><type>pg_snapshot</type></entry>
+       <entry>get current snapshot</entry>
+      </row>
+      <row>
+       <entry><literal><function>pg_snapshot_xip(<parameter>pg_snapshot</parameter>)</function></literal></entry>
+       <entry><type>setof xid8</type></entry>
+       <entry>get in-progress transaction IDs in snapshot</entry>
+      </row>
+      <row>
+       <entry><literal><function>pg_snapshot_xmax(<parameter>pg_snapshot</parameter>)</function></literal></entry>
+       <entry><type>xid8</type></entry>
+       <entry>get <literal>xmax</literal> of snapshot</entry>
+      </row>
+      <row>
+       <entry><literal><function>pg_snapshot_xmin(<parameter>pg_snapshot</parameter>)</function></literal></entry>
+       <entry><type>xid8</type></entry>
+       <entry>get <literal>xmin</literal> of snapshot</entry>
+      </row>
+      <row>
+       <entry><literal><function>pg_visible_in_snapshot(<parameter>xid8</parameter>, <parameter>pg_snapshot</parameter>)</function></literal></entry>
+       <entry><type>boolean</type></entry>
+       <entry>is transaction ID visible in snapshot? (do not use with subtransaction IDs)</entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+
+   <para>
+    The internal transaction ID type <type>xid</type> is 32 bits wide and
+    wraps around every 4 billion transactions.  However, these functions use a
+    64-bit variant <type>xid8</type> that does not wrap around during the life
+    of an installation, and can be converted to <type>xid</type> by casting if
+    required.  The data type <type>pg_snapshot</type> stores information about
+    transaction ID visibility at a particular moment in time.  Its components
+    are described in <xref linkend="functions-pg-snapshot-parts"/>.
+   </para>
+
+   <para>
+    In releases of <productname>PostgreSQL</productname> before 13 there was
+    no <type>xid8</type> type, so variants of these functions were provided
+    that used <type>bigint</type>.  These older functions with
+    <literal>txid</literal> in their names are still supported for backward
+    compatibility, but may be removed from a future
+    release. See <xref linkend="functions-txid-snapshot"/>.
+   </para>
+
+   <table id="functions-txid-snapshot">
+    <title>Transaction IDs and Snapshots (Deprecated Functions)</title>
+    <tgroup cols="3">
+     <thead>
+      <row><entry>Name</entry> <entry>Return Type</entry> <entry>Description</entry></row>
+     </thead>
+
      <tbody>
       <row>
        <entry><literal><function>txid_current()</function></literal></entry>
        <entry><type>bigint</type></entry>
-       <entry>get current transaction ID, assigning a new one if the current transaction does not have one</entry>
+       <entry>see <function>pg_current_xact_id()</function></entry>
       </row>
       <row>
        <entry><literal><function>txid_current_if_assigned()</function></literal></entry>
        <entry><type>bigint</type></entry>
-       <entry>same as <function>txid_current()</function> but returns null instead of assigning a new transaction ID if none is already assigned</entry>
+       <entry>see <function>pg_current_xact_id_if_assigned()</function></entry>
       </row>
       <row>
        <entry><literal><function>txid_current_snapshot()</function></literal></entry>
        <entry><type>txid_snapshot</type></entry>
-       <entry>get current snapshot</entry>
+       <entry>see <function>pg_current_snapshot()</function></entry>
       </row>
       <row>
        <entry><literal><function>txid_snapshot_xip(<parameter>txid_snapshot</parameter>)</function></literal></entry>
        <entry><type>setof bigint</type></entry>
-       <entry>get in-progress transaction IDs in snapshot</entry>
+       <entry>see <function>pg_snapshot_xip()</function></entry>
       </row>
       <row>
        <entry><literal><function>txid_snapshot_xmax(<parameter>txid_snapshot</parameter>)</function></literal></entry>
        <entry><type>bigint</type></entry>
-       <entry>get <literal>xmax</literal> of snapshot</entry>
+       <entry>see <function>pg_snapshot_xmax()</function></entry>
       </row>
       <row>
        <entry><literal><function>txid_snapshot_xmin(<parameter>txid_snapshot</parameter>)</function></literal></entry>
        <entry><type>bigint</type></entry>
-       <entry>get <literal>xmin</literal> of snapshot</entry>
+       <entry>see <function>pg_snapshot_xmin()</function></entry>
       </row>
       <row>
        <entry><literal><function>txid_visible_in_snapshot(<parameter>bigint</parameter>, <parameter>txid_snapshot</parameter>)</function></literal></entry>
        <entry><type>boolean</type></entry>
-       <entry>is transaction ID visible in snapshot? (do not use with subtransaction ids)</entry>
+       <entry>see <function>pg_visible_in_snapshot()</function></entry>
       </row>
       <row>
        <entry><literal><function>txid_status(<parameter>bigint</parameter>)</function></literal></entry>
        <entry><type>text</type></entry>
-       <entry>report the status of the given transaction: <literal>committed</literal>, <literal>aborted</literal>, <literal>in progress</literal>, or null if the transaction ID is too old</entry>
+       <entry>see <function>pg_xact_status()</function></entry>
       </row>
      </tbody>
     </tgroup>
    </table>
 
-   <para>
-    The internal transaction ID type (<type>xid</type>) is 32 bits wide and
-    wraps around every 4 billion transactions.  However, these functions
-    export a 64-bit format that is extended with an <quote>epoch</quote> counter
-    so it will not wrap around during the life of an installation.
-    The data type used by these functions, <type>txid_snapshot</type>,
-    stores information about transaction ID
-    visibility at a particular moment in time.  Its components are
-    described in <xref linkend="functions-txid-snapshot-parts"/>.
-   </para>
-
-   <table id="functions-txid-snapshot-parts">
+   <table id="functions-pg-snapshot-parts">
     <title>Snapshot Components</title>
     <tgroup cols="2">
      <thead>
@@ -19115,31 +19207,29 @@ SELECT collation for ('foo' COLLATE "de_DE");
       <row>
        <entry><type>xmin</type></entry>
        <entry>
-         Earliest transaction ID (txid) that is still active.  All earlier
-         transactions will either be committed and visible, or rolled
-         back and dead.
+         Lowest transaction ID that was still active.  All transaction IDs
+         less than <literal>xmin</literal> are either committed and visible,
+         or rolled back and dead.
        </entry>
       </row>
 
       <row>
        <entry><type>xmax</type></entry>
        <entry>
-        First as-yet-unassigned txid.  All txids greater than or equal to this
-        are not yet started as of the time of the snapshot, and thus invisible.
+         One past the highest completed transaction ID.  All transaction IDs
+         greater than or equal to <literal>xmax</literal> had not yet
+         completed as of the time of the snapshot, and thus are invisible.
        </entry>
       </row>
 
       <row>
        <entry><type>xip_list</type></entry>
        <entry>
-        Active txids at the time of the snapshot.  The list
-        includes only those active txids between <literal>xmin</literal>
-        and <literal>xmax</literal>; there might be active txids higher
-        than <literal>xmax</literal>.  A txid that is <literal>xmin &lt;= txid &lt;
-        xmax</literal> and not in this list was already completed
-        at the time of the snapshot, and thus either visible or
-        dead according to its commit status.  The list does not
-        include txids of subtransactions.
+        Transactions in progress at the time of the snapshot.  A transaction
+        ID that is <literal>xmin &lt;= X &lt; xmax</literal> and not in this
+        list was already completed at the time of the snapshot, and is thus
+        either visible or dead according to its commit status.  The list does
+        not include the transaction IDs of subtransactions.
        </entry>
       </row>
 
@@ -19148,14 +19238,14 @@ SELECT collation for ('foo' COLLATE "de_DE");
    </table>
 
    <para>
-    <type>txid_snapshot</type>'s textual representation is
+    <type>pg_snapshot</type>'s textual representation is
     <literal><replaceable>xmin</replaceable>:<replaceable>xmax</replaceable>:<replaceable>xip_list</replaceable></literal>.
     For example <literal>10:20:10,14,15</literal> means
     <literal>xmin=10, xmax=20, xip_list=10, 14, 15</literal>.
    </para>
 
    <para>
-    <function>txid_status(bigint)</function> reports the commit status of a recent
+    <function>pg_xact_status(xid8)</function> reports the commit status of a recent
     transaction.  Applications may use it to determine whether a transaction
     committed or aborted when the application and database server become
     disconnected while a <literal>COMMIT</literal> is in progress.
@@ -19169,7 +19259,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
     transactions are reported as <literal>in progress</literal>; applications must
     check <link
     linkend="view-pg-prepared-xacts"><literal>pg_prepared_xacts</literal></link> if they
-    need to determine whether the txid is a prepared transaction.
+    need to determine whether the transaction ID belongs to a prepared transaction.
    </para>
 
    <para>
index bce6d379bf07ec2a2dc3fd712a8ae2f41ab7a1ec..bad3bfe6206c519431a72b2fd47408aeaaf673c9 100644 (file)
@@ -418,7 +418,7 @@ CREATE TABLE another_catalog_table(data text) WITH (user_catalog_table = true);
 </programlisting>
      Any actions leading to transaction ID assignment are prohibited. That, among others,
      includes writing to tables, performing DDL changes, and
-     calling <literal>txid_current()</literal>.
+     calling <literal>pg_current_xact_id()</literal>.
     </para>
    </sect2>
 
index fd8b17ef8f6c38719a8e3bc0a8bb3dfcad9fbe9f..c50b72137f327e9ef733d6ed2c8616fd28424011 100644 (file)
@@ -1112,7 +1112,7 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
         </row>
         <row>
          <entry><literal>CLogTruncationLock</literal></entry>
-         <entry>Waiting to execute <function>txid_status</function> or update
+         <entry>Waiting to execute <function>pg_xact_status</function> or update
          the oldest transaction id available to it.</entry>
         </row>
         <row>
index 13efa9338c165f32e90621d2636c04388df01fc3..5d2aca8cfe6f84ea56510ac72fabc280c5ffc374 100644 (file)
@@ -101,7 +101,6 @@ OBJS = \
    tsvector.o \
    tsvector_op.o \
    tsvector_parser.o \
-   txid.o \
    uuid.o \
    varbit.o \
    varchar.o \
@@ -109,6 +108,7 @@ OBJS = \
    version.o \
    windowfuncs.o \
    xid.o \
+   xid8funcs.o \
    xml.o
 
 jsonpath_scan.c: FLEXFLAGS = -CF -p -p
similarity index 54%
rename from src/backend/utils/adt/txid.c
rename to src/backend/utils/adt/xid8funcs.c
index 33272f80308dca7b54a16fc2b1af34272857f6dd..616f187ad42cb1d39542487b379dbcc19fb3b7ea 100644 (file)
@@ -1,20 +1,25 @@
 /*-------------------------------------------------------------------------
- * txid.c
+ * xid8funcs.c
  *
  * Export internal transaction IDs to user level.
  *
- * Note that only top-level transaction IDs are ever converted to TXID.
- * This is important because TXIDs frequently persist beyond the global
+ * Note that only top-level transaction IDs are exposed to user sessions.
+ * This is important because xid8s frequently persist beyond the global
  * xmin horizon, or may even be shipped to other machines, so we cannot
  * rely on being able to correlate subtransaction IDs with their parents
  * via functions such as SubTransGetTopmostTransaction().
  *
+ * These functions are used to support the txid_XXX functions and the newer
+ * pg_current_xact, pg_current_snapshot and related fmgr functions, since the
+ * only difference between them is whether they expose xid8 or int8 values to
+ * users.  The txid_XXX variants should eventually be dropped.
+ *
  *
  * Copyright (c) 2003-2020, PostgreSQL Global Development Group
  * Author: Jan Wieck, Afilias USA INC.
  * 64-bit txids: Marko Kreen, Skype Technologies
  *
- * src/backend/utils/adt/txid.c
+ * src/backend/utils/adt/xid8funcs.c
  *
  *-------------------------------------------------------------------------
  */
 #include "utils/builtins.h"
 #include "utils/memutils.h"
 #include "utils/snapmgr.h"
+#include "utils/xid8.h"
 
-/* txid will be signed int8 in database, so must limit to 63 bits */
-#define MAX_TXID   ((uint64) PG_INT64_MAX)
-
-/* Use unsigned variant internally */
-typedef uint64 txid;
-
-/* sprintf format code for uint64 */
-#define TXID_FMT UINT64_FORMAT
 
 /*
- * If defined, use bsearch() function for searching for txids in snapshots
+ * If defined, use bsearch() function for searching for xid8s in snapshots
  * that have more than the specified number of values.
  */
 #define USE_BSEARCH_IF_NXIP_GREATER 30
 
 
 /*
- * Snapshot containing 8byte txids.
+ * Snapshot containing FullTransactionIds.
  */
 typedef struct
 {
@@ -63,39 +61,17 @@ typedef struct
     */
    int32       __varsz;
 
-   uint32      nxip;           /* number of txids in xip array */
-   txid        xmin;
-   txid        xmax;
-   /* in-progress txids, xmin <= xip[i] < xmax: */
-   txid        xip[FLEXIBLE_ARRAY_MEMBER];
-} TxidSnapshot;
-
-#define TXID_SNAPSHOT_SIZE(nxip) \
-   (offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip))
-#define TXID_SNAPSHOT_MAX_NXIP \
-   ((MaxAllocSize - offsetof(TxidSnapshot, xip)) / sizeof(txid))
-
-/*
- * Epoch values from xact.c
- */
-typedef struct
-{
-   TransactionId last_xid;
-   uint32      epoch;
-} TxidEpoch;
-
-
-/*
- * Fetch epoch data from xact.c.
- */
-static void
-load_xid_epoch(TxidEpoch *state)
-{
-   FullTransactionId fullXid = ReadNextFullTransactionId();
+   uint32      nxip;           /* number of fxids in xip array */
+   FullTransactionId xmin;
+   FullTransactionId xmax;
+   /* in-progress fxids, xmin <= xip[i] < xmax: */
+   FullTransactionId xip[FLEXIBLE_ARRAY_MEMBER];
+} pg_snapshot;
 
-   state->last_xid = XidFromFullTransactionId(fullXid);
-   state->epoch = EpochFromFullTransactionId(fullXid);
-}
+#define PG_SNAPSHOT_SIZE(nxip) \
+   (offsetof(pg_snapshot, xip) + sizeof(FullTransactionId) * (nxip))
+#define PG_SNAPSHOT_MAX_NXIP \
+   ((MaxAllocSize - offsetof(pg_snapshot, xip)) / sizeof(FullTransactionId))
 
 /*
  * Helper to get a TransactionId from a 64-bit xid with wraparound detection.
@@ -111,10 +87,10 @@ load_xid_epoch(TxidEpoch *state)
  * relating to those XIDs.
  */
 static bool
-TransactionIdInRecentPast(uint64 xid_with_epoch, TransactionId *extracted_xid)
+TransactionIdInRecentPast(FullTransactionId fxid, TransactionId *extracted_xid)
 {
-   uint32      xid_epoch = (uint32) (xid_with_epoch >> 32);
-   TransactionId xid = (TransactionId) xid_with_epoch;
+   uint32      xid_epoch = EpochFromFullTransactionId(fxid);
+   TransactionId xid = XidFromFullTransactionId(fxid);
    uint32      now_epoch;
    TransactionId now_epoch_next_xid;
    FullTransactionId now_fullxid;
@@ -134,11 +110,12 @@ TransactionIdInRecentPast(uint64 xid_with_epoch, TransactionId *extracted_xid)
        return true;
 
    /* If the transaction ID is in the future, throw an error. */
-   if (xid_with_epoch >= U64FromFullTransactionId(now_fullxid))
+   if (!FullTransactionIdPrecedes(fxid, now_fullxid))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("transaction ID %s is in the future",
-                       psprintf(UINT64_FORMAT, xid_with_epoch))));
+                       psprintf(UINT64_FORMAT,
+                                U64FromFullTransactionId(fxid)))));
 
    /*
     * ShmemVariableCache->oldestClogXid is protected by CLogTruncationLock,
@@ -164,41 +141,46 @@ TransactionIdInRecentPast(uint64 xid_with_epoch, TransactionId *extracted_xid)
 }
 
 /*
- * do a TransactionId -> txid conversion for an XID near the given epoch
+ * Convert a TransactionId obtained from a snapshot held by the caller to a
+ * FullTransactionId.  Use next_fxid as a reference FullTransactionId, so that
+ * we can compute the high order bits.  It must have been obtained by the
+ * caller with ReadNextFullTransactionId() after the snapshot was created.
  */
-static txid
-convert_xid(TransactionId xid, const TxidEpoch *state)
+static FullTransactionId
+widen_snapshot_xid(TransactionId xid, FullTransactionId next_fxid)
 {
-   uint64      epoch;
+   TransactionId next_xid = XidFromFullTransactionId(next_fxid);
+   uint32      epoch = EpochFromFullTransactionId(next_fxid);
 
-   /* return special xid's as-is */
+   /* Special transaction ID. */
    if (!TransactionIdIsNormal(xid))
-       return (txid) xid;
+       return FullTransactionIdFromEpochAndXid(0, xid);
 
-   /* xid can be on either side when near wrap-around */
-   epoch = (uint64) state->epoch;
-   if (xid > state->last_xid &&
-       TransactionIdPrecedes(xid, state->last_xid))
+   /*
+    * The 64 bit result must be <= next_fxid, since next_fxid hadn't been
+    * issued yet when the snapshot was created.  Every TransactionId in the
+    * snapshot must therefore be from the same epoch as next_fxid, or the
+    * epoch before.  We know this because next_fxid is never allow to get
+    * more than one epoch ahead of the TransactionIds in any snapshot.
+    */
+   if (xid > next_xid)
        epoch--;
-   else if (xid < state->last_xid &&
-            TransactionIdFollows(xid, state->last_xid))
-       epoch++;
 
-   return (epoch << 32) | xid;
+   return FullTransactionIdFromEpochAndXid(epoch, xid);
 }
 
 /*
  * txid comparator for qsort/bsearch
  */
 static int
-cmp_txid(const void *aa, const void *bb)
+cmp_fxid(const void *aa, const void *bb)
 {
-   txid        a = *(const txid *) aa;
-   txid        b = *(const txid *) bb;
+   FullTransactionId a = *(const FullTransactionId *) aa;
+   FullTransactionId b = *(const FullTransactionId *) bb;
 
-   if (a < b)
+   if (FullTransactionIdPrecedes(a, b))
        return -1;
-   if (a > b)
+   if (FullTransactionIdPrecedes(b, a))
        return 1;
    return 0;
 }
@@ -211,31 +193,33 @@ cmp_txid(const void *aa, const void *bb)
  * will not be used.
  */
 static void
-sort_snapshot(TxidSnapshot *snap)
+sort_snapshot(pg_snapshot *snap)
 {
    if (snap->nxip > 1)
    {
-       qsort(snap->xip, snap->nxip, sizeof(txid), cmp_txid);
-       snap->nxip = qunique(snap->xip, snap->nxip, sizeof(txid), cmp_txid);
+       qsort(snap->xip, snap->nxip, sizeof(FullTransactionId), cmp_fxid);
+       snap->nxip = qunique(snap->xip, snap->nxip, sizeof(FullTransactionId),
+                            cmp_fxid);
    }
 }
 
 /*
- * check txid visibility.
+ * check fxid visibility.
  */
 static bool
-is_visible_txid(txid value, const TxidSnapshot *snap)
+is_visible_fxid(FullTransactionId value, const pg_snapshot *snap)
 {
-   if (value < snap->xmin)
+   if (FullTransactionIdPrecedes(value, snap->xmin))
        return true;
-   else if (value >= snap->xmax)
+   else if (!FullTransactionIdPrecedes(value, snap->xmax))
        return false;
 #ifdef USE_BSEARCH_IF_NXIP_GREATER
    else if (snap->nxip > USE_BSEARCH_IF_NXIP_GREATER)
    {
        void       *res;
 
-       res = bsearch(&value, snap->xip, snap->nxip, sizeof(txid), cmp_txid);
+       res = bsearch(&value, snap->xip, snap->nxip, sizeof(FullTransactionId),
+                     cmp_fxid);
        /* if found, transaction is still in progress */
        return (res) ? false : true;
    }
@@ -246,7 +230,7 @@ is_visible_txid(txid value, const TxidSnapshot *snap)
 
        for (i = 0; i < snap->nxip; i++)
        {
-           if (value == snap->xip[i])
+           if (FullTransactionIdEquals(value, snap->xip[i]))
                return false;
        }
        return true;
@@ -254,13 +238,13 @@ is_visible_txid(txid value, const TxidSnapshot *snap)
 }
 
 /*
- * helper functions to use StringInfo for TxidSnapshot creation.
+ * helper functions to use StringInfo for pg_snapshot creation.
  */
 
 static StringInfo
-buf_init(txid xmin, txid xmax)
+buf_init(FullTransactionId xmin, FullTransactionId xmax)
 {
-   TxidSnapshot snap;
+   pg_snapshot snap;
    StringInfo  buf;
 
    snap.xmin = xmin;
@@ -268,25 +252,25 @@ buf_init(txid xmin, txid xmax)
    snap.nxip = 0;
 
    buf = makeStringInfo();
-   appendBinaryStringInfo(buf, (char *) &snap, TXID_SNAPSHOT_SIZE(0));
+   appendBinaryStringInfo(buf, (char *) &snap, PG_SNAPSHOT_SIZE(0));
    return buf;
 }
 
 static void
-buf_add_txid(StringInfo buf, txid xid)
+buf_add_txid(StringInfo buf, FullTransactionId fxid)
 {
-   TxidSnapshot *snap = (TxidSnapshot *) buf->data;
+   pg_snapshot *snap = (pg_snapshot *) buf->data;
 
    /* do this before possible realloc */
    snap->nxip++;
 
-   appendBinaryStringInfo(buf, (char *) &xid, sizeof(xid));
+   appendBinaryStringInfo(buf, (char *) &fxid, sizeof(fxid));
 }
 
-static TxidSnapshot *
+static pg_snapshot *
 buf_finalize(StringInfo buf)
 {
-   TxidSnapshot *snap = (TxidSnapshot *) buf->data;
+   pg_snapshot *snap = (pg_snapshot *) buf->data;
 
    SET_VARSIZE(snap, buf->len);
 
@@ -297,68 +281,34 @@ buf_finalize(StringInfo buf)
    return snap;
 }
 
-/*
- * simple number parser.
- *
- * We return 0 on error, which is invalid value for txid.
- */
-static txid
-str2txid(const char *s, const char **endp)
-{
-   txid        val = 0;
-   txid        cutoff = MAX_TXID / 10;
-   txid        cutlim = MAX_TXID % 10;
-
-   for (; *s; s++)
-   {
-       unsigned    d;
-
-       if (*s < '0' || *s > '9')
-           break;
-       d = *s - '0';
-
-       /*
-        * check for overflow
-        */
-       if (val > cutoff || (val == cutoff && d > cutlim))
-       {
-           val = 0;
-           break;
-       }
-
-       val = val * 10 + d;
-   }
-   if (endp)
-       *endp = s;
-   return val;
-}
-
 /*
  * parse snapshot from cstring
  */
-static TxidSnapshot *
+static pg_snapshot *
 parse_snapshot(const char *str)
 {
-   txid        xmin;
-   txid        xmax;
-   txid        last_val = 0,
-               val;
+   FullTransactionId xmin;
+   FullTransactionId xmax;
+   FullTransactionId last_val = InvalidFullTransactionId;
+   FullTransactionId val;
    const char *str_start = str;
-   const char *endp;
+   char       *endp;
    StringInfo  buf;
 
-   xmin = str2txid(str, &endp);
+   xmin = FullTransactionIdFromU64(pg_strtouint64(str, &endp, 10));
    if (*endp != ':')
        goto bad_format;
    str = endp + 1;
 
-   xmax = str2txid(str, &endp);
+   xmax = FullTransactionIdFromU64(pg_strtouint64(str, &endp, 10));
    if (*endp != ':')
        goto bad_format;
    str = endp + 1;
 
    /* it should look sane */
-   if (xmin == 0 || xmax == 0 || xmin > xmax)
+   if (!FullTransactionIdIsValid(xmin) ||
+       !FullTransactionIdIsValid(xmax) ||
+       FullTransactionIdPrecedes(xmax, xmin))
        goto bad_format;
 
    /* allocate buffer */
@@ -368,15 +318,17 @@ parse_snapshot(const char *str)
    while (*str != '\0')
    {
        /* read next value */
-       val = str2txid(str, &endp);
+       val = FullTransactionIdFromU64(pg_strtouint64(str, &endp, 10));
        str = endp;
 
        /* require the input to be in order */
-       if (val < xmin || val >= xmax || val < last_val)
+       if (FullTransactionIdPrecedes(val, xmin) ||
+           FullTransactionIdFollowsOrEquals(val, xmax) ||
+           FullTransactionIdPrecedes(val, last_val))
            goto bad_format;
 
        /* skip duplicates */
-       if (val != last_val)
+       if (!FullTransactionIdEquals(val, last_val))
            buf_add_txid(buf, val);
        last_val = val;
 
@@ -392,108 +344,82 @@ bad_format:
    ereport(ERROR,
            (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
             errmsg("invalid input syntax for type %s: \"%s\"",
-                   "txid_snapshot", str_start)));
+                   "pg_snapshot", str_start)));
    return NULL;                /* keep compiler quiet */
 }
 
 /*
- * Public functions.
- *
- * txid_current() and txid_current_snapshot() are the only ones that
- * communicate with core xid machinery.  All the others work on data
- * returned by them.
- */
-
-/*
- * txid_current() returns int8
+ * pg_current_xact_id() returns xid8
  *
- * Return the current toplevel transaction ID as TXID
+ * Return the current toplevel full transaction ID.
  * If the current transaction does not have one, one is assigned.
- *
- * This value has the epoch as the high 32 bits and the 32-bit xid
- * as the low 32 bits.
  */
 Datum
-txid_current(PG_FUNCTION_ARGS)
+pg_current_xact_id(PG_FUNCTION_ARGS)
 {
-   txid        val;
-   TxidEpoch   state;
-
    /*
     * Must prevent during recovery because if an xid is not assigned we try
     * to assign one, which would fail. Programs already rely on this function
     * to always return a valid current xid, so we should not change this to
     * return NULL or similar invalid xid.
     */
-   PreventCommandDuringRecovery("txid_current()");
-
-   load_xid_epoch(&state);
+   PreventCommandDuringRecovery("pg_current_xact_id()");
 
-   val = convert_xid(GetTopTransactionId(), &state);
-
-   PG_RETURN_INT64(val);
+   PG_RETURN_FULLTRANSACTIONID(GetTopFullTransactionId());
 }
 
 /*
- * Same as txid_current() but doesn't assign a new xid if there isn't one
- * yet.
+ * Same as pg_current_xact_if_assigned() but doesn't assign a new xid if there
+ * isn't one yet.
  */
 Datum
-txid_current_if_assigned(PG_FUNCTION_ARGS)
+pg_current_xact_id_if_assigned(PG_FUNCTION_ARGS)
 {
-   txid        val;
-   TxidEpoch   state;
-   TransactionId topxid = GetTopTransactionIdIfAny();
+   FullTransactionId topfxid = GetTopFullTransactionIdIfAny();
 
-   if (topxid == InvalidTransactionId)
+   if (!FullTransactionIdIsValid(topfxid))
        PG_RETURN_NULL();
 
-   load_xid_epoch(&state);
-
-   val = convert_xid(topxid, &state);
-
-   PG_RETURN_INT64(val);
+   PG_RETURN_FULLTRANSACTIONID(topfxid);
 }
 
 /*
- * txid_current_snapshot() returns txid_snapshot
+ * pg_current_snapshot() returns pg_snapshot
  *
- *     Return current snapshot in TXID format
+ *     Return current snapshot
  *
  * Note that only top-transaction XIDs are included in the snapshot.
  */
 Datum
-txid_current_snapshot(PG_FUNCTION_ARGS)
+pg_current_snapshot(PG_FUNCTION_ARGS)
 {
-   TxidSnapshot *snap;
+   pg_snapshot *snap;
    uint32      nxip,
                i;
-   TxidEpoch   state;
    Snapshot    cur;
+   FullTransactionId next_fxid = ReadNextFullTransactionId();
 
    cur = GetActiveSnapshot();
    if (cur == NULL)
        elog(ERROR, "no active snapshot set");
 
-   load_xid_epoch(&state);
-
    /*
     * Compile-time limits on the procarray (MAX_BACKENDS processes plus
     * MAX_BACKENDS prepared transactions) guarantee nxip won't be too large.
     */
-   StaticAssertStmt(MAX_BACKENDS * 2 <= TXID_SNAPSHOT_MAX_NXIP,
-                    "possible overflow in txid_current_snapshot()");
+   StaticAssertStmt(MAX_BACKENDS * 2 <= PG_SNAPSHOT_MAX_NXIP,
+                    "possible overflow in pg_current_snapshot()");
 
    /* allocate */
    nxip = cur->xcnt;
-   snap = palloc(TXID_SNAPSHOT_SIZE(nxip));
+   snap = palloc(PG_SNAPSHOT_SIZE(nxip));
 
    /* fill */
-   snap->xmin = convert_xid(cur->xmin, &state);
-   snap->xmax = convert_xid(cur->xmax, &state);
+   snap->xmin = widen_snapshot_xid(cur->xmin, next_fxid);
+   snap->xmax = widen_snapshot_xid(cur->xmax, next_fxid);
    snap->nxip = nxip;
    for (i = 0; i < nxip; i++)
-       snap->xip[i] = convert_xid(cur->xip[i], &state);
+       snap->xip[i] = widen_snapshot_xid(cur->xip[i], next_fxid);
 
    /*
     * We want them guaranteed to be in ascending order.  This also removes
@@ -505,21 +431,21 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
    sort_snapshot(snap);
 
    /* set size after sorting, because it may have removed duplicate xips */
-   SET_VARSIZE(snap, TXID_SNAPSHOT_SIZE(snap->nxip));
+   SET_VARSIZE(snap, PG_SNAPSHOT_SIZE(snap->nxip));
 
    PG_RETURN_POINTER(snap);
 }
 
 /*
- * txid_snapshot_in(cstring) returns txid_snapshot
+ * pg_snapshot_in(cstring) returns pg_snapshot
  *
- *     input function for type txid_snapshot
+ *     input function for type pg_snapshot
  */
 Datum
-txid_snapshot_in(PG_FUNCTION_ARGS)
+pg_snapshot_in(PG_FUNCTION_ARGS)
 {
    char       *str = PG_GETARG_CSTRING(0);
-   TxidSnapshot *snap;
+   pg_snapshot *snap;
 
    snap = parse_snapshot(str);
 
@@ -527,73 +453,81 @@ txid_snapshot_in(PG_FUNCTION_ARGS)
 }
 
 /*
- * txid_snapshot_out(txid_snapshot) returns cstring
+ * pg_snapshot_out(pg_snapshot) returns cstring
  *
- *     output function for type txid_snapshot
+ *     output function for type pg_snapshot
  */
 Datum
-txid_snapshot_out(PG_FUNCTION_ARGS)
+pg_snapshot_out(PG_FUNCTION_ARGS)
 {
-   TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
+   pg_snapshot *snap = (pg_snapshot *) PG_GETARG_VARLENA_P(0);
    StringInfoData str;
    uint32      i;
 
    initStringInfo(&str);
 
-   appendStringInfo(&str, TXID_FMT ":", snap->xmin);
-   appendStringInfo(&str, TXID_FMT ":", snap->xmax);
+   appendStringInfo(&str, UINT64_FORMAT ":",
+                    U64FromFullTransactionId(snap->xmin));
+   appendStringInfo(&str, UINT64_FORMAT ":",
+                    U64FromFullTransactionId(snap->xmax));
 
    for (i = 0; i < snap->nxip; i++)
    {
        if (i > 0)
            appendStringInfoChar(&str, ',');
-       appendStringInfo(&str, TXID_FMT, snap->xip[i]);
+       appendStringInfo(&str, UINT64_FORMAT,
+                        U64FromFullTransactionId(snap->xip[i]));
    }
 
    PG_RETURN_CSTRING(str.data);
 }
 
 /*
- * txid_snapshot_recv(internal) returns txid_snapshot
+ * pg_snapshot_recv(internal) returns pg_snapshot
  *
- *     binary input function for type txid_snapshot
+ *     binary input function for type pg_snapshot
  *
  *     format: int4 nxip, int8 xmin, int8 xmax, int8 xip
  */
 Datum
-txid_snapshot_recv(PG_FUNCTION_ARGS)
+pg_snapshot_recv(PG_FUNCTION_ARGS)
 {
    StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
-   TxidSnapshot *snap;
-   txid        last = 0;
+   pg_snapshot *snap;
+   FullTransactionId last = InvalidFullTransactionId;
    int         nxip;
    int         i;
-   txid        xmin,
-               xmax;
+   FullTransactionId xmin;
+   FullTransactionId xmax;
 
    /* load and validate nxip */
    nxip = pq_getmsgint(buf, 4);
-   if (nxip < 0 || nxip > TXID_SNAPSHOT_MAX_NXIP)
+   if (nxip < 0 || nxip > PG_SNAPSHOT_MAX_NXIP)
        goto bad_format;
 
-   xmin = pq_getmsgint64(buf);
-   xmax = pq_getmsgint64(buf);
-   if (xmin == 0 || xmax == 0 || xmin > xmax || xmax > MAX_TXID)
+   xmin = FullTransactionIdFromU64((uint64) pq_getmsgint64(buf));
+   xmax = FullTransactionIdFromU64((uint64) pq_getmsgint64(buf));
+   if (!FullTransactionIdIsValid(xmin) ||
+       !FullTransactionIdIsValid(xmax) ||
+       FullTransactionIdPrecedes(xmax, xmin))
        goto bad_format;
 
-   snap = palloc(TXID_SNAPSHOT_SIZE(nxip));
+   snap = palloc(PG_SNAPSHOT_SIZE(nxip));
    snap->xmin = xmin;
    snap->xmax = xmax;
 
    for (i = 0; i < nxip; i++)
    {
-       txid        cur = pq_getmsgint64(buf);
+       FullTransactionId cur =
+       FullTransactionIdFromU64((uint64) pq_getmsgint64(buf));
 
-       if (cur < last || cur < xmin || cur >= xmax)
+       if (FullTransactionIdPrecedes(cur, last) ||
+           FullTransactionIdPrecedes(cur, xmin) ||
+           FullTransactionIdPrecedes(xmax, cur))
            goto bad_format;
 
        /* skip duplicate xips */
-       if (cur == last)
+       if (FullTransactionIdEquals(cur, last))
        {
            i--;
            nxip--;
@@ -604,95 +538,95 @@ txid_snapshot_recv(PG_FUNCTION_ARGS)
        last = cur;
    }
    snap->nxip = nxip;
-   SET_VARSIZE(snap, TXID_SNAPSHOT_SIZE(nxip));
+   SET_VARSIZE(snap, PG_SNAPSHOT_SIZE(nxip));
    PG_RETURN_POINTER(snap);
 
 bad_format:
    ereport(ERROR,
            (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
-            errmsg("invalid external txid_snapshot data")));
+            errmsg("invalid external pg_snapshot data")));
    PG_RETURN_POINTER(NULL);    /* keep compiler quiet */
 }
 
 /*
- * txid_snapshot_send(txid_snapshot) returns bytea
+ * pg_snapshot_send(pg_snapshot) returns bytea
  *
- *     binary output function for type txid_snapshot
+ *     binary output function for type pg_snapshot
  *
- *     format: int4 nxip, int8 xmin, int8 xmax, int8 xip
+ *     format: int4 nxip, u64 xmin, u64 xmax, u64 xip...
  */
 Datum
-txid_snapshot_send(PG_FUNCTION_ARGS)
+pg_snapshot_send(PG_FUNCTION_ARGS)
 {
-   TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
+   pg_snapshot *snap = (pg_snapshot *) PG_GETARG_VARLENA_P(0);
    StringInfoData buf;
    uint32      i;
 
    pq_begintypsend(&buf);
    pq_sendint32(&buf, snap->nxip);
-   pq_sendint64(&buf, snap->xmin);
-   pq_sendint64(&buf, snap->xmax);
+   pq_sendint64(&buf, (int64) U64FromFullTransactionId(snap->xmin));
+   pq_sendint64(&buf, (int64) U64FromFullTransactionId(snap->xmax));
    for (i = 0; i < snap->nxip; i++)
-       pq_sendint64(&buf, snap->xip[i]);
+       pq_sendint64(&buf, (int64) U64FromFullTransactionId(snap->xip[i]));
    PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 /*
- * txid_visible_in_snapshot(int8, txid_snapshot) returns bool
+ * pg_visible_in_snapshot(xid8, pg_snapshot) returns bool
  *
  *     is txid visible in snapshot ?
  */
 Datum
-txid_visible_in_snapshot(PG_FUNCTION_ARGS)
+pg_visible_in_snapshot(PG_FUNCTION_ARGS)
 {
-   txid        value = PG_GETARG_INT64(0);
-   TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(1);
+   FullTransactionId value = PG_GETARG_FULLTRANSACTIONID(0);
+   pg_snapshot *snap = (pg_snapshot *) PG_GETARG_VARLENA_P(1);
 
-   PG_RETURN_BOOL(is_visible_txid(value, snap));
+   PG_RETURN_BOOL(is_visible_fxid(value, snap));
 }
 
 /*
- * txid_snapshot_xmin(txid_snapshot) returns int8
+ * pg_snapshot_xmin(pg_snapshot) returns xid8
  *
  *     return snapshot's xmin
  */
 Datum
-txid_snapshot_xmin(PG_FUNCTION_ARGS)
+pg_snapshot_xmin(PG_FUNCTION_ARGS)
 {
-   TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
+   pg_snapshot *snap = (pg_snapshot *) PG_GETARG_VARLENA_P(0);
 
-   PG_RETURN_INT64(snap->xmin);
+   PG_RETURN_FULLTRANSACTIONID(snap->xmin);
 }
 
 /*
- * txid_snapshot_xmax(txid_snapshot) returns int8
+ * pg_snapshot_xmax(pg_snapshot) returns xid8
  *
  *     return snapshot's xmax
  */
 Datum
-txid_snapshot_xmax(PG_FUNCTION_ARGS)
+pg_snapshot_xmax(PG_FUNCTION_ARGS)
 {
-   TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
+   pg_snapshot *snap = (pg_snapshot *) PG_GETARG_VARLENA_P(0);
 
-   PG_RETURN_INT64(snap->xmax);
+   PG_RETURN_FULLTRANSACTIONID(snap->xmax);
 }
 
 /*
- * txid_snapshot_xip(txid_snapshot) returns setof int8
+ * pg_snapshot_xip(pg_snapshot) returns setof xid8
  *
- *     return in-progress TXIDs in snapshot.
+ *     return in-progress xid8s in snapshot.
  */
 Datum
-txid_snapshot_xip(PG_FUNCTION_ARGS)
+pg_snapshot_xip(PG_FUNCTION_ARGS)
 {
    FuncCallContext *fctx;
-   TxidSnapshot *snap;
-   txid        value;
+   pg_snapshot *snap;
+   FullTransactionId value;
 
    /* on first call initialize fctx and get copy of snapshot */
    if (SRF_IS_FIRSTCALL())
    {
-       TxidSnapshot *arg = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
+       pg_snapshot *arg = (pg_snapshot *) PG_GETARG_VARLENA_P(0);
 
        fctx = SRF_FIRSTCALL_INIT();
 
@@ -709,7 +643,7 @@ txid_snapshot_xip(PG_FUNCTION_ARGS)
    if (fctx->call_cntr < snap->nxip)
    {
        value = snap->xip[fctx->call_cntr];
-       SRF_RETURN_NEXT(fctx, Int64GetDatum(value));
+       SRF_RETURN_NEXT(fctx, FullTransactionIdGetDatum(value));
    }
    else
    {
@@ -728,10 +662,10 @@ txid_snapshot_xip(PG_FUNCTION_ARGS)
  * though the parent xact may still be in progress or may have aborted.
  */
 Datum
-txid_status(PG_FUNCTION_ARGS)
+pg_xact_status(PG_FUNCTION_ARGS)
 {
    const char *status;
-   uint64      xid_with_epoch = PG_GETARG_INT64(0);
+   FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
    TransactionId xid;
 
    /*
@@ -739,7 +673,7 @@ txid_status(PG_FUNCTION_ARGS)
     * an I/O error on SLRU lookup.
     */
    LWLockAcquire(CLogTruncationLock, LW_SHARED);
-   if (TransactionIdInRecentPast(xid_with_epoch, &xid))
+   if (TransactionIdInRecentPast(fxid, &xid))
    {
        Assert(TransactionIdIsValid(xid));
 
index 4201790ec48c0eb9d0a08eacda8f93562765deac..498992ff84c325dc95121519b29f17b1d2317d17 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 202004061
+#define CATALOG_VERSION_NO 202004062
 
 #endif
index 6be7e4f1571734ebf95eef19451f16054a59eb05..2d1862a9d8ab812a8613c8df7ea30fabebf666ed 100644 (file)
   proname => 'jsonb_path_match_opr', prorettype => 'bool',
   proargtypes => 'jsonb jsonpath', prosrc => 'jsonb_path_match_opr' },
 
-# txid
+# historical int8/txid_snapshot variants of xid8 functions
 { oid => '2939', descr => 'I/O',
   proname => 'txid_snapshot_in', prorettype => 'txid_snapshot',
-  proargtypes => 'cstring', prosrc => 'txid_snapshot_in' },
+  proargtypes => 'cstring', prosrc => 'pg_snapshot_in' },
 { oid => '2940', descr => 'I/O',
   proname => 'txid_snapshot_out', prorettype => 'cstring',
-  proargtypes => 'txid_snapshot', prosrc => 'txid_snapshot_out' },
+  proargtypes => 'txid_snapshot', prosrc => 'pg_snapshot_out' },
 { oid => '2941', descr => 'I/O',
   proname => 'txid_snapshot_recv', prorettype => 'txid_snapshot',
-  proargtypes => 'internal', prosrc => 'txid_snapshot_recv' },
+  proargtypes => 'internal', prosrc => 'pg_snapshot_recv' },
 { oid => '2942', descr => 'I/O',
   proname => 'txid_snapshot_send', prorettype => 'bytea',
-  proargtypes => 'txid_snapshot', prosrc => 'txid_snapshot_send' },
+  proargtypes => 'txid_snapshot', prosrc => 'pg_snapshot_send' },
 { oid => '2943', descr => 'get current transaction ID',
   proname => 'txid_current', provolatile => 's', proparallel => 'u',
-  prorettype => 'int8', proargtypes => '', prosrc => 'txid_current' },
+  prorettype => 'int8', proargtypes => '', prosrc => 'pg_current_xact_id' },
 { oid => '3348', descr => 'get current transaction ID',
   proname => 'txid_current_if_assigned', provolatile => 's', proparallel => 'u',
   prorettype => 'int8', proargtypes => '',
-  prosrc => 'txid_current_if_assigned' },
+  prosrc => 'pg_current_xact_id_if_assigned' },
 { oid => '2944', descr => 'get current snapshot',
   proname => 'txid_current_snapshot', provolatile => 's',
   prorettype => 'txid_snapshot', proargtypes => '',
-  prosrc => 'txid_current_snapshot' },
+  prosrc => 'pg_current_snapshot' },
 { oid => '2945', descr => 'get xmin of snapshot',
   proname => 'txid_snapshot_xmin', prorettype => 'int8',
-  proargtypes => 'txid_snapshot', prosrc => 'txid_snapshot_xmin' },
+  proargtypes => 'txid_snapshot', prosrc => 'pg_snapshot_xmin' },
 { oid => '2946', descr => 'get xmax of snapshot',
   proname => 'txid_snapshot_xmax', prorettype => 'int8',
-  proargtypes => 'txid_snapshot', prosrc => 'txid_snapshot_xmax' },
+  proargtypes => 'txid_snapshot', prosrc => 'pg_snapshot_xmax' },
 { oid => '2947', descr => 'get set of in-progress txids in snapshot',
   proname => 'txid_snapshot_xip', prorows => '50', proretset => 't',
   prorettype => 'int8', proargtypes => 'txid_snapshot',
-  prosrc => 'txid_snapshot_xip' },
+  prosrc => 'pg_snapshot_xip' },
 { oid => '2948', descr => 'is txid visible in snapshot?',
   proname => 'txid_visible_in_snapshot', prorettype => 'bool',
-  proargtypes => 'int8 txid_snapshot', prosrc => 'txid_visible_in_snapshot' },
+  proargtypes => 'int8 txid_snapshot', prosrc => 'pg_visible_in_snapshot' },
 { oid => '3360', descr => 'commit status of transaction',
   proname => 'txid_status', provolatile => 'v', prorettype => 'text',
-  proargtypes => 'int8', prosrc => 'txid_status' },
+  proargtypes => 'int8', prosrc => 'pg_xact_status' },
+
+# pg_snapshot functions
+{ oid => '9247', descr => 'I/O',
+  proname => 'pg_snapshot_in', prorettype => 'pg_snapshot',
+  proargtypes => 'cstring', prosrc => 'pg_snapshot_in' },
+{ oid => '9248', descr => 'I/O',
+  proname => 'pg_snapshot_out', prorettype => 'cstring',
+  proargtypes => 'pg_snapshot', prosrc => 'pg_snapshot_out' },
+{ oid => '9249', descr => 'I/O',
+  proname => 'pg_snapshot_recv', prorettype => 'pg_snapshot',
+  proargtypes => 'internal', prosrc => 'pg_snapshot_recv' },
+{ oid => '9250', descr => 'I/O',
+  proname => 'pg_snapshot_send', prorettype => 'bytea',
+  proargtypes => 'pg_snapshot', prosrc => 'pg_snapshot_send' },
+{ oid => '9253', descr => 'get current snapshot',
+  proname => 'pg_current_snapshot', provolatile => 's',
+  prorettype => 'pg_snapshot', proargtypes => '',
+  prosrc => 'pg_current_snapshot' },
+{ oid => '9254', descr => 'get xmin of snapshot',
+  proname => 'pg_snapshot_xmin', prorettype => 'xid8',
+  proargtypes => 'pg_snapshot', prosrc => 'pg_snapshot_xmin' },
+{ oid => '9255', descr => 'get xmax of snapshot',
+  proname => 'pg_snapshot_xmax', prorettype => 'xid8',
+  proargtypes => 'pg_snapshot', prosrc => 'pg_snapshot_xmax' },
+{ oid => '9256', descr => 'get set of in-progress transactions in snapshot',
+  proname => 'pg_snapshot_xip', prorows => '50', proretset => 't',
+  prorettype => 'xid8', proargtypes => 'pg_snapshot',
+  prosrc => 'pg_snapshot_xip' },
+{ oid => '9257', descr => 'is xid8 visible in snapshot?',
+  proname => 'pg_visible_in_snapshot', prorettype => 'bool',
+  proargtypes => 'xid8 pg_snapshot', prosrc => 'pg_visible_in_snapshot' },
+
+# transaction ID and status functions
+{ oid => '9251', descr => 'get current transaction ID',
+  proname => 'pg_current_xact_id', provolatile => 's', proparallel => 'u',
+  prorettype => 'xid8', proargtypes => '', prosrc => 'pg_current_xact_id' },
+{ oid => '9252', descr => 'get current transaction ID',
+  proname => 'pg_current_xact_id_if_assigned', provolatile => 's', proparallel => 'u',
+  prorettype => 'xid8', proargtypes => '',
+  prosrc => 'pg_current_xact_id_if_assigned' },
+{ oid => '9258', descr => 'commit status of transaction',
+  proname => 'pg_xact_status', provolatile => 'v', prorettype => 'text',
+  proargtypes => 'xid8', prosrc => 'pg_xact_status' },
 
 # record comparison using normal comparison rules
 { oid => '2981',
index a1f441b8daa8aadacceef489d352b61a795709ec..78f44af5e75c936c46d5433948d6ba7d2e8955ea 100644 (file)
   typcategory => 'U', typinput => 'txid_snapshot_in',
   typoutput => 'txid_snapshot_out', typreceive => 'txid_snapshot_recv',
   typsend => 'txid_snapshot_send', typalign => 'd', typstorage => 'x' },
+{ oid => '8355', array_type_oid => '8356', descr => 'snapshot',
+  typname => 'pg_snapshot', typlen => '-1', typbyval => 'f',
+  typcategory => 'U', typinput => 'pg_snapshot_in',
+  typoutput => 'pg_snapshot_out', typreceive => 'pg_snapshot_recv',
+  typsend => 'pg_snapshot_send', typalign => 'd', typstorage => 'x' },
 
 # range types
 { oid => '3904', array_type_oid => '3905', descr => 'range of integers',
index bd4b9433056d67164550d57423610fe93d9aeebc..39ca25a06bf0126414a14c0e9a8ec6a7f033e869 100644 (file)
@@ -45,7 +45,7 @@ my $xid = $node_master->safe_psql(
    'postgres', qq[
    BEGIN;
    INSERT INTO committs_test(x, y) VALUES (1, current_timestamp);
-   SELECT txid_current();
+   SELECT pg_current_xact_id()::xid;
    COMMIT;
 ]);
 
@@ -93,7 +93,7 @@ DECLARE
     i int;
     BEGIN
         FOR i in 1..cnt LOOP
-            EXECUTE 'SELECT txid_current()';
+            EXECUTE 'SELECT pg_current_xact_id()';
             COMMIT;
         END LOOP;
     END;
@@ -115,7 +115,7 @@ my $xid_disabled = $node_master->safe_psql(
    'postgres', qq[
    BEGIN;
    INSERT INTO committs_test(x, y) VALUES (2, current_timestamp);
-   SELECT txid_current();
+   SELECT pg_current_xact_id();
    COMMIT;
 ]);
 
index 523c9960933d0e2f5bcebd693677e298baf04aa2..c7c9bf8971f37f18764519ded54494e28c2ad5f2 100644 (file)
@@ -43,7 +43,7 @@ CREATE TABLE datatype_table (
     v_json         JSON,
     v_xml          XML,
     v_uuid         UUID,
-    v_txid_snapshot txid_snapshot,
+    v_pg_snapshot  pg_snapshot,
     v_enum         ENUM_TEST,
     v_postal_code  japanese_postal_code,
     v_int2range    int2range,
index dd3a908638d7db9eb6e4abdf85800dd5885f3b04..39cdb9df03cee22a3f57590ae9e2399f8e2866b4 100644 (file)
@@ -44,7 +44,7 @@ CREATE TABLE datatype_table (
     v_json         JSON,
     v_xml          XML,
     v_uuid         UUID,
-    v_txid_snapshot txid_snapshot,
+    v_pg_snapshot  pg_snapshot,
     v_enum         ENUM_TEST,
     v_postal_code  japanese_postal_code,
     v_int2range    int2range,
index fd14bab208bd139b6a03ab84b57c4df9911b2de3..2a520e6db1a81d3febf34974bbd2c83e3bfb88f7 100644 (file)
@@ -68,7 +68,7 @@ $node_master->backup('my_backup');
 $node_master->safe_psql('postgres',
    "INSERT INTO tab_int VALUES (generate_series(1001,2000))");
 my $ret = $node_master->safe_psql('postgres',
-   "SELECT pg_current_wal_lsn(), txid_current();");
+   "SELECT pg_current_wal_lsn(), pg_current_xact_id();");
 my ($lsn2, $recovery_txid) = split /\|/, $ret;
 
 # More data, with recovery target timestamp
index 526a3481fb567fe060de91abf7f9eeb50e53193e..ca6e92b50df4e70e9bcf838751b417222015fbf9 100644 (file)
@@ -24,7 +24,7 @@ $node->start;
 
 my ($stdin, $stdout, $stderr) = ('', '', '');
 
-# Ensure that txid_status reports 'aborted' for xacts
+# Ensure that pg_xact_status reports 'aborted' for xacts
 # that were in-progress during crash. To do that, we need
 # an xact to be in-progress when we crash and we need to know
 # its xid.
@@ -42,7 +42,7 @@ my $tx = IPC::Run::start(
 $stdin .= q[
 BEGIN;
 CREATE TABLE mine(x integer);
-SELECT txid_current();
+SELECT pg_current_xact_id();
 ];
 $tx->pump until $stdout =~ /[[:digit:]]+[\r\n]$/;
 
@@ -50,7 +50,7 @@ $tx->pump until $stdout =~ /[[:digit:]]+[\r\n]$/;
 my $xid = $stdout;
 chomp($xid);
 
-is($node->safe_psql('postgres', qq[SELECT txid_status('$xid');]),
+is($node->safe_psql('postgres', qq[SELECT pg_xact_status('$xid');]),
    'in progress', 'own xid is in-progress');
 
 # Crash and restart the postmaster
@@ -58,11 +58,11 @@ $node->stop('immediate');
 $node->start;
 
 # Make sure we really got a new xid
-cmp_ok($node->safe_psql('postgres', 'SELECT txid_current()'),
+cmp_ok($node->safe_psql('postgres', 'SELECT pg_current_xact_id()'),
    '>', $xid, 'new xid after restart is greater');
 
 # and make sure we show the in-progress xact as aborted
-is($node->safe_psql('postgres', qq[SELECT txid_status('$xid');]),
+is($node->safe_psql('postgres', qq[SELECT pg_xact_status('$xid');]),
    'aborted', 'xid is aborted after crash');
 
 $tx->kill_kill;
index e46775afbf52d4b2cdbd60e23f49842a1ab30e3f..f343f9b42ea46e54ee6f43cc6ed84a5692ab6030 100644 (file)
@@ -2556,7 +2556,7 @@ from pg_locks l join pg_class c on l.relation = c.oid
 where virtualtransaction = (
         select virtualtransaction
         from pg_locks
-        where transactionid = txid_current()::integer)
+        where transactionid = pg_current_xact_id()::xid)
 and locktype = 'relation'
 and relnamespace != (select oid from pg_namespace where nspname = 'pg_catalog')
 and c.relname != 'my_locks'
@@ -2719,7 +2719,7 @@ from pg_locks l join pg_class c on l.relation = c.oid
 where virtualtransaction = (
         select virtualtransaction
         from pg_locks
-        where transactionid = txid_current()::integer)
+        where transactionid = pg_current_xact_id()::xid)
 and locktype = 'relation'
 and relnamespace != (select oid from pg_namespace where nspname = 'pg_catalog')
 and c.relname = 'my_locks'
index e0af677ea1b8022b44a16d93541734f1d7addada..ce846b758bf8c8519732316989b12353cbd89fe6 100644 (file)
@@ -4,9 +4,9 @@
 -- hs_standby_functions.sql
 --
 -- should fail
-select txid_current();
-ERROR:  cannot execute txid_current() during recovery
-select length(txid_current_snapshot()::text) >= 4;
+select pg_current_xact_id();
+ERROR:  cannot execute pg_current_xact_id() during recovery
+select length(pg_current_snapshot()::text) >= 4;
  ?column? 
 ----------
  t
index 0c03afe53d20952cc163b66017bbba76e91204fa..8d350ab61bb8881df08e1d806f5d9c1562f05902 100644 (file)
@@ -194,9 +194,11 @@ WHERE p1.oid != p2.oid AND
 ORDER BY 1, 2;
  prorettype | prorettype 
 ------------+------------
+         20 |       9419
          25 |       1043
        1114 |       1184
-(2 rows)
+       2970 |       8355
+(4 rows)
 
 SELECT DISTINCT p1.proargtypes[0], p2.proargtypes[0]
 FROM pg_proc AS p1, pg_proc AS p2
@@ -210,11 +212,13 @@ WHERE p1.oid != p2.oid AND
 ORDER BY 1, 2;
  proargtypes | proargtypes 
 -------------+-------------
+          20 |        9419
           25 |        1042
           25 |        1043
         1114 |        1184
         1560 |        1562
-(4 rows)
+        2970 |        8355
+(6 rows)
 
 SELECT DISTINCT p1.proargtypes[1], p2.proargtypes[1]
 FROM pg_proc AS p1, pg_proc AS p2
@@ -231,7 +235,8 @@ ORDER BY 1, 2;
           23 |          28
         1114 |        1184
         1560 |        1562
-(3 rows)
+        2970 |        8355
+(4 rows)
 
 SELECT DISTINCT p1.proargtypes[2], p2.proargtypes[2]
 FROM pg_proc AS p1, pg_proc AS p2
index 015dae305121dc956e4975def1ce7c969ee92187..95ba66e95eea7eac555cc01338197ff99d8f6276 100644 (file)
@@ -1,4 +1,7 @@
 -- txid_snapshot data type and related functions
+-- Note: these are backward-compatibility functions and types, and have been
+-- replaced by new xid8-based variants.  See xid.sql.  The txid variants will
+-- be removed in a future release.
 -- i/o
 select '12:13:'::txid_snapshot;
  txid_snapshot 
@@ -20,19 +23,19 @@ select '12:16:14,14'::txid_snapshot;
 
 -- errors
 select '31:12:'::txid_snapshot;
-ERROR:  invalid input syntax for type txid_snapshot: "31:12:"
+ERROR:  invalid input syntax for type pg_snapshot: "31:12:"
 LINE 1: select '31:12:'::txid_snapshot;
                ^
 select '0:1:'::txid_snapshot;
-ERROR:  invalid input syntax for type txid_snapshot: "0:1:"
+ERROR:  invalid input syntax for type pg_snapshot: "0:1:"
 LINE 1: select '0:1:'::txid_snapshot;
                ^
 select '12:13:0'::txid_snapshot;
-ERROR:  invalid input syntax for type txid_snapshot: "12:13:0"
+ERROR:  invalid input syntax for type pg_snapshot: "12:13:0"
 LINE 1: select '12:13:0'::txid_snapshot;
                ^
 select '12:16:14,13'::txid_snapshot;
-ERROR:  invalid input syntax for type txid_snapshot: "12:16:14,13"
+ERROR:  invalid input syntax for type pg_snapshot: "12:16:14,13"
 LINE 1: select '12:16:14,13'::txid_snapshot;
                ^
 create temp table snapshot_test (
@@ -235,7 +238,7 @@ SELECT txid_snapshot '1:9223372036854775807:3';
 (1 row)
 
 SELECT txid_snapshot '1:9223372036854775808:3';
-ERROR:  invalid input syntax for type txid_snapshot: "1:9223372036854775808:3"
+ERROR:  invalid input syntax for type pg_snapshot: "1:9223372036854775808:3"
 LINE 1: SELECT txid_snapshot '1:9223372036854775808:3';
                              ^
 -- test txid_current_if_assigned
index b7f90de52b13a0fb0a6d39360bda1d7fa784ee2a..bf939d79f607f5c71ee6551247fd67b84af06a3d 100644 (file)
@@ -230,10 +230,9 @@ INSERT INTO upsert_test VALUES (1, 'Bat') ON CONFLICT(a)
 -- ON CONFLICT using system attributes in RETURNING, testing both the
 -- inserting and updating paths. See bug report at:
 -- https://www.postgresql.org/message-id/73436355-6432-49B1-92ED-1FE4F7E7E100%40finefun.com.au
-CREATE FUNCTION xid_current() RETURNS xid LANGUAGE SQL AS $$SELECT (txid_current() % ((1::int8<<32)))::text::xid;$$;
 INSERT INTO upsert_test VALUES (2, 'Beeble') ON CONFLICT(a)
   DO UPDATE SET (b, a) = (SELECT b || ', Excluded', a from upsert_test i WHERE i.a = excluded.a)
-  RETURNING tableoid::regclass, xmin = xid_current() AS xmin_correct, xmax = 0 AS xmax_correct;
+  RETURNING tableoid::regclass, xmin = pg_current_xact_id()::xid AS xmin_correct, xmax = 0 AS xmax_correct;
   tableoid   | xmin_correct | xmax_correct 
 -------------+--------------+--------------
  upsert_test | t            | t
@@ -243,13 +242,12 @@ INSERT INTO upsert_test VALUES (2, 'Beeble') ON CONFLICT(a)
 -- but it seems worthwhile to have to be explicit if that changes.
 INSERT INTO upsert_test VALUES (2, 'Brox') ON CONFLICT(a)
   DO UPDATE SET (b, a) = (SELECT b || ', Excluded', a from upsert_test i WHERE i.a = excluded.a)
-  RETURNING tableoid::regclass, xmin = xid_current() AS xmin_correct, xmax = xid_current() AS xmax_correct;
+  RETURNING tableoid::regclass, xmin = pg_current_xact_id()::xid AS xmin_correct, xmax = pg_current_xact_id()::xid AS xmax_correct;
   tableoid   | xmin_correct | xmax_correct 
 -------------+--------------+--------------
  upsert_test | t            | t
 (1 row)
 
-DROP FUNCTION xid_current();
 DROP TABLE update_test;
 DROP TABLE upsert_test;
 ---------------------------
index e9e1fa8259105fcfa1a62c4abb4b71dd12c3f0a6..b7a1ed0f9ee4acf43e5c3b7034289a2e45e7b850 100644 (file)
@@ -134,3 +134,329 @@ 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;
+-- 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)
+-- i/o
+select '12:13:'::pg_snapshot;
+ pg_snapshot 
+-------------
+ 12:13:
+(1 row)
+
+select '12:18:14,16'::pg_snapshot;
+ pg_snapshot 
+-------------
+ 12:18:14,16
+(1 row)
+
+select '12:16:14,14'::pg_snapshot;
+ pg_snapshot 
+-------------
+ 12:16:14
+(1 row)
+
+-- errors
+select '31:12:'::pg_snapshot;
+ERROR:  invalid input syntax for type pg_snapshot: "31:12:"
+LINE 1: select '31:12:'::pg_snapshot;
+               ^
+select '0:1:'::pg_snapshot;
+ERROR:  invalid input syntax for type pg_snapshot: "0:1:"
+LINE 1: select '0:1:'::pg_snapshot;
+               ^
+select '12:13:0'::pg_snapshot;
+ERROR:  invalid input syntax for type pg_snapshot: "12:13:0"
+LINE 1: select '12:13:0'::pg_snapshot;
+               ^
+select '12:16:14,13'::pg_snapshot;
+ERROR:  invalid input syntax for type pg_snapshot: "12:16:14,13"
+LINE 1: select '12:16:14,13'::pg_snapshot;
+               ^
+create temp table snapshot_test (
+   nr  integer,
+   snap    pg_snapshot
+);
+insert into snapshot_test values (1, '12:13:');
+insert into snapshot_test values (2, '12:20:13,15,18');
+insert into snapshot_test values (3, '100001:100009:100005,100007,100008');
+insert into snapshot_test values (4, '100:150:101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131');
+select snap from snapshot_test order by nr;
+                                                                snap                                                                 
+-------------------------------------------------------------------------------------------------------------------------------------
+ 12:13:
+ 12:20:13,15,18
+ 100001:100009:100005,100007,100008
+ 100:150:101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131
+(4 rows)
+
+select  pg_snapshot_xmin(snap),
+   pg_snapshot_xmax(snap),
+   pg_snapshot_xip(snap)
+from snapshot_test order by nr;
+ pg_snapshot_xmin | pg_snapshot_xmax | pg_snapshot_xip 
+------------------+------------------+-----------------
+               12 |               20 |              13
+               12 |               20 |              15
+               12 |               20 |              18
+           100001 |           100009 |          100005
+           100001 |           100009 |          100007
+           100001 |           100009 |          100008
+              100 |              150 |             101
+              100 |              150 |             102
+              100 |              150 |             103
+              100 |              150 |             104
+              100 |              150 |             105
+              100 |              150 |             106
+              100 |              150 |             107
+              100 |              150 |             108
+              100 |              150 |             109
+              100 |              150 |             110
+              100 |              150 |             111
+              100 |              150 |             112
+              100 |              150 |             113
+              100 |              150 |             114
+              100 |              150 |             115
+              100 |              150 |             116
+              100 |              150 |             117
+              100 |              150 |             118
+              100 |              150 |             119
+              100 |              150 |             120
+              100 |              150 |             121
+              100 |              150 |             122
+              100 |              150 |             123
+              100 |              150 |             124
+              100 |              150 |             125
+              100 |              150 |             126
+              100 |              150 |             127
+              100 |              150 |             128
+              100 |              150 |             129
+              100 |              150 |             130
+              100 |              150 |             131
+(37 rows)
+
+select id, pg_visible_in_snapshot(id::text::xid8, snap)
+from snapshot_test, generate_series(11, 21) id
+where nr = 2;
+ id | pg_visible_in_snapshot 
+----+------------------------
+ 11 | t
+ 12 | t
+ 13 | f
+ 14 | t
+ 15 | f
+ 16 | t
+ 17 | t
+ 18 | f
+ 19 | t
+ 20 | f
+ 21 | f
+(11 rows)
+
+-- test bsearch
+select id, pg_visible_in_snapshot(id::text::xid8, snap)
+from snapshot_test, generate_series(90, 160) id
+where nr = 4;
+ id  | pg_visible_in_snapshot 
+-----+------------------------
+  90 | t
+  91 | t
+  92 | t
+  93 | t
+  94 | t
+  95 | t
+  96 | t
+  97 | t
+  98 | t
+  99 | t
+ 100 | t
+ 101 | f
+ 102 | f
+ 103 | f
+ 104 | f
+ 105 | f
+ 106 | f
+ 107 | f
+ 108 | f
+ 109 | f
+ 110 | f
+ 111 | f
+ 112 | f
+ 113 | f
+ 114 | f
+ 115 | f
+ 116 | f
+ 117 | f
+ 118 | f
+ 119 | f
+ 120 | f
+ 121 | f
+ 122 | f
+ 123 | f
+ 124 | f
+ 125 | f
+ 126 | f
+ 127 | f
+ 128 | f
+ 129 | f
+ 130 | f
+ 131 | f
+ 132 | t
+ 133 | t
+ 134 | t
+ 135 | t
+ 136 | t
+ 137 | t
+ 138 | t
+ 139 | t
+ 140 | t
+ 141 | t
+ 142 | t
+ 143 | t
+ 144 | t
+ 145 | t
+ 146 | t
+ 147 | t
+ 148 | t
+ 149 | t
+ 150 | f
+ 151 | f
+ 152 | f
+ 153 | f
+ 154 | f
+ 155 | f
+ 156 | f
+ 157 | f
+ 158 | f
+ 159 | f
+ 160 | f
+(71 rows)
+
+-- test current values also
+select pg_current_xact_id() >= pg_snapshot_xmin(pg_current_snapshot());
+ ?column? 
+----------
+ t
+(1 row)
+
+-- we can't assume current is always less than xmax, however
+select pg_visible_in_snapshot(pg_current_xact_id(), pg_current_snapshot());
+ pg_visible_in_snapshot 
+------------------------
+ f
+(1 row)
+
+-- test 64bitness
+select pg_snapshot '1000100010001000:1000100010001100:1000100010001012,1000100010001013';
+                             pg_snapshot                             
+---------------------------------------------------------------------
+ 1000100010001000:1000100010001100:1000100010001012,1000100010001013
+(1 row)
+
+select pg_visible_in_snapshot('1000100010001012', '1000100010001000:1000100010001100:1000100010001012,1000100010001013');
+ pg_visible_in_snapshot 
+------------------------
+ f
+(1 row)
+
+select pg_visible_in_snapshot('1000100010001015', '1000100010001000:1000100010001100:1000100010001012,1000100010001013');
+ pg_visible_in_snapshot 
+------------------------
+ t
+(1 row)
+
+-- test 64bit overflow
+SELECT pg_snapshot '1:9223372036854775807:3';
+       pg_snapshot       
+-------------------------
+ 1:9223372036854775807:3
+(1 row)
+
+SELECT pg_snapshot '1:9223372036854775808:3';
+ERROR:  invalid input syntax for type pg_snapshot: "1:9223372036854775808:3"
+LINE 1: SELECT pg_snapshot '1:9223372036854775808:3';
+                           ^
+-- test pg_current_xact_id_if_assigned
+BEGIN;
+SELECT pg_current_xact_id_if_assigned() IS NULL;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT pg_current_xact_id() \gset
+SELECT pg_current_xact_id_if_assigned() IS NOT DISTINCT FROM xid8 :'pg_current_xact_id';
+ ?column? 
+----------
+ t
+(1 row)
+
+COMMIT;
+-- test xid status functions
+BEGIN;
+SELECT pg_current_xact_id() AS committed \gset
+COMMIT;
+BEGIN;
+SELECT pg_current_xact_id() AS rolledback \gset
+ROLLBACK;
+BEGIN;
+SELECT pg_current_xact_id() AS inprogress \gset
+SELECT pg_xact_status(:committed::text::xid8) AS committed;
+ committed 
+-----------
+ committed
+(1 row)
+
+SELECT pg_xact_status(:rolledback::text::xid8) AS rolledback;
+ rolledback 
+------------
+ aborted
+(1 row)
+
+SELECT pg_xact_status(:inprogress::text::xid8) AS inprogress;
+ inprogress  
+-------------
+ in progress
+(1 row)
+
+SELECT pg_xact_status('1'::xid8); -- BootstrapTransactionId is always committed
+ pg_xact_status 
+----------------
+ committed
+(1 row)
+
+SELECT pg_xact_status('2'::xid8); -- FrozenTransactionId is always committed
+ pg_xact_status 
+----------------
+ committed
+(1 row)
+
+SELECT pg_xact_status('3'::xid8); -- in regress testing FirstNormalTransactionId will always be behind oldestXmin
+ pg_xact_status 
+----------------
+(1 row)
+
+COMMIT;
+BEGIN;
+CREATE FUNCTION test_future_xid_status(xid8)
+RETURNS void
+LANGUAGE plpgsql
+AS
+$$
+BEGIN
+  PERFORM pg_xact_status($1);
+  RAISE EXCEPTION 'didn''t ERROR at xid in the future as expected';
+EXCEPTION
+  WHEN invalid_parameter_value THEN
+    RAISE NOTICE 'Got expected error for xid in the future';
+END;
+$$;
+SELECT test_future_xid_status((:inprogress + 10000)::text::xid8);
+NOTICE:  Got expected error for xid in the future
+ test_future_xid_status 
+------------------------
+(1 row)
+
+ROLLBACK;
index 8eca21823d6c8a57be4fa824cb7657fe101aa423..fb5c9139d1529bbed20d926f875e65419368a67b 100644 (file)
@@ -1645,7 +1645,7 @@ from pg_locks l join pg_class c on l.relation = c.oid
 where virtualtransaction = (
         select virtualtransaction
         from pg_locks
-        where transactionid = txid_current()::integer)
+        where transactionid = pg_current_xact_id()::xid)
 and locktype = 'relation'
 and relnamespace != (select oid from pg_namespace where nspname = 'pg_catalog')
 and c.relname != 'my_locks'
@@ -1732,7 +1732,7 @@ from pg_locks l join pg_class c on l.relation = c.oid
 where virtualtransaction = (
         select virtualtransaction
         from pg_locks
-        where transactionid = txid_current()::integer)
+        where transactionid = pg_current_xact_id()::xid)
 and locktype = 'relation'
 and relnamespace != (select oid from pg_namespace where nspname = 'pg_catalog')
 and c.relname = 'my_locks'
index 251bac0a43162ac5cd7459331e9a1eada0b0dd79..b57f67ff8b5e4aebd36f3b2f81a0d7d382ad1c1a 100644 (file)
@@ -5,9 +5,9 @@
 --
 
 -- should fail
-select txid_current();
+select pg_current_xact_id();
 
-select length(txid_current_snapshot()::text) >= 4;
+select length(pg_current_snapshot()::text) >= 4;
 
 select pg_start_backup('should fail');
 select pg_switch_wal();
index bd6decf0ef4db9505558a24d590e3cd4d3b1d4e7..8d5ac98a892060212e59c9c98af75eddb76baff0 100644 (file)
@@ -1,4 +1,7 @@
 -- txid_snapshot data type and related functions
+-- Note: these are backward-compatibility functions and types, and have been
+-- replaced by new xid8-based variants.  See xid.sql.  The txid variants will
+-- be removed in a future release.
 
 -- i/o
 select '12:13:'::txid_snapshot;
index bb9c24e40f817bb18630fd8dc4f11a8cf7f9e213..8c558a7bc7286f01331fbf97236e97c08ed9e622 100644 (file)
@@ -117,18 +117,16 @@ INSERT INTO upsert_test VALUES (1, 'Bat') ON CONFLICT(a)
 -- ON CONFLICT using system attributes in RETURNING, testing both the
 -- inserting and updating paths. See bug report at:
 -- https://www.postgresql.org/message-id/73436355-6432-49B1-92ED-1FE4F7E7E100%40finefun.com.au
-CREATE FUNCTION xid_current() RETURNS xid LANGUAGE SQL AS $$SELECT (txid_current() % ((1::int8<<32)))::text::xid;$$;
 INSERT INTO upsert_test VALUES (2, 'Beeble') ON CONFLICT(a)
   DO UPDATE SET (b, a) = (SELECT b || ', Excluded', a from upsert_test i WHERE i.a = excluded.a)
-  RETURNING tableoid::regclass, xmin = xid_current() AS xmin_correct, xmax = 0 AS xmax_correct;
+  RETURNING tableoid::regclass, xmin = pg_current_xact_id()::xid AS xmin_correct, xmax = 0 AS xmax_correct;
 -- currently xmax is set after a conflict - that's probably not good,
 -- but it seems worthwhile to have to be explicit if that changes.
 INSERT INTO upsert_test VALUES (2, 'Brox') ON CONFLICT(a)
   DO UPDATE SET (b, a) = (SELECT b || ', Excluded', a from upsert_test i WHERE i.a = excluded.a)
-  RETURNING tableoid::regclass, xmin = xid_current() AS xmin_correct, xmax = xid_current() AS xmax_correct;
+  RETURNING tableoid::regclass, xmin = pg_current_xact_id()::xid AS xmin_correct, xmax = pg_current_xact_id()::xid AS xmax_correct;
 
 
-DROP FUNCTION xid_current();
 DROP TABLE update_test;
 DROP TABLE upsert_test;
 
index a4fbca51766156b1c5198a6a8179ca858381207e..565714d4620d54bf21d8f74e722c04831e87d3d1 100644 (file)
@@ -46,3 +46,107 @@ 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;
+
+
+-- 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)
+
+-- i/o
+select '12:13:'::pg_snapshot;
+select '12:18:14,16'::pg_snapshot;
+select '12:16:14,14'::pg_snapshot;
+
+-- errors
+select '31:12:'::pg_snapshot;
+select '0:1:'::pg_snapshot;
+select '12:13:0'::pg_snapshot;
+select '12:16:14,13'::pg_snapshot;
+
+create temp table snapshot_test (
+   nr  integer,
+   snap    pg_snapshot
+);
+
+insert into snapshot_test values (1, '12:13:');
+insert into snapshot_test values (2, '12:20:13,15,18');
+insert into snapshot_test values (3, '100001:100009:100005,100007,100008');
+insert into snapshot_test values (4, '100:150:101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131');
+select snap from snapshot_test order by nr;
+
+select  pg_snapshot_xmin(snap),
+   pg_snapshot_xmax(snap),
+   pg_snapshot_xip(snap)
+from snapshot_test order by nr;
+
+select id, pg_visible_in_snapshot(id::text::xid8, snap)
+from snapshot_test, generate_series(11, 21) id
+where nr = 2;
+
+-- test bsearch
+select id, pg_visible_in_snapshot(id::text::xid8, snap)
+from snapshot_test, generate_series(90, 160) id
+where nr = 4;
+
+-- test current values also
+select pg_current_xact_id() >= pg_snapshot_xmin(pg_current_snapshot());
+
+-- we can't assume current is always less than xmax, however
+
+select pg_visible_in_snapshot(pg_current_xact_id(), pg_current_snapshot());
+
+-- test 64bitness
+
+select pg_snapshot '1000100010001000:1000100010001100:1000100010001012,1000100010001013';
+select pg_visible_in_snapshot('1000100010001012', '1000100010001000:1000100010001100:1000100010001012,1000100010001013');
+select pg_visible_in_snapshot('1000100010001015', '1000100010001000:1000100010001100:1000100010001012,1000100010001013');
+
+-- test 64bit overflow
+SELECT pg_snapshot '1:9223372036854775807:3';
+SELECT pg_snapshot '1:9223372036854775808:3';
+
+-- test pg_current_xact_id_if_assigned
+BEGIN;
+SELECT pg_current_xact_id_if_assigned() IS NULL;
+SELECT pg_current_xact_id() \gset
+SELECT pg_current_xact_id_if_assigned() IS NOT DISTINCT FROM xid8 :'pg_current_xact_id';
+COMMIT;
+
+-- test xid status functions
+BEGIN;
+SELECT pg_current_xact_id() AS committed \gset
+COMMIT;
+
+BEGIN;
+SELECT pg_current_xact_id() AS rolledback \gset
+ROLLBACK;
+
+BEGIN;
+SELECT pg_current_xact_id() AS inprogress \gset
+
+SELECT pg_xact_status(:committed::text::xid8) AS committed;
+SELECT pg_xact_status(:rolledback::text::xid8) AS rolledback;
+SELECT pg_xact_status(:inprogress::text::xid8) AS inprogress;
+SELECT pg_xact_status('1'::xid8); -- BootstrapTransactionId is always committed
+SELECT pg_xact_status('2'::xid8); -- FrozenTransactionId is always committed
+SELECT pg_xact_status('3'::xid8); -- in regress testing FirstNormalTransactionId will always be behind oldestXmin
+
+COMMIT;
+
+BEGIN;
+CREATE FUNCTION test_future_xid_status(xid8)
+RETURNS void
+LANGUAGE plpgsql
+AS
+$$
+BEGIN
+  PERFORM pg_xact_status($1);
+  RAISE EXCEPTION 'didn''t ERROR at xid in the future as expected';
+EXCEPTION
+  WHEN invalid_parameter_value THEN
+    RAISE NOTICE 'Got expected error for xid in the future';
+END;
+$$;
+SELECT test_future_xid_status((:inprogress + 10000)::text::xid8);
+ROLLBACK;
index 34623523a70156e1ad44be049e59e7cecd42e158..525d58e7f01d0bf14786f52ea6962ec9b4945e2e 100644 (file)
@@ -3099,6 +3099,7 @@ pg_sha224_ctx
 pg_sha256_ctx
 pg_sha384_ctx
 pg_sha512_ctx
+pg_snapshot
 pg_stack_base_t
 pg_time_t
 pg_tz