]> granicus.if.org Git - postgresql/commitdiff
Migrate the former contrib/txid module into core. This will make it easier
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 13 Oct 2007 23:06:28 +0000 (23:06 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 13 Oct 2007 23:06:28 +0000 (23:06 +0000)
for Slony and Skytools to depend on it.  Per discussion.

12 files changed:
doc/src/sgml/datatype.sgml
doc/src/sgml/func.sgml
src/backend/utils/adt/Makefile
src/backend/utils/adt/txid.c [new file with mode: 0644]
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/catalog/pg_type.h
src/include/utils/builtins.h
src/test/regress/expected/txid.out [new file with mode: 0644]
src/test/regress/parallel_schedule
src/test/regress/serial_schedule
src/test/regress/sql/txid.sql [new file with mode: 0644]

index 67f96ce1f73697bdb449c478e2c0ceda82c6d939..326e4570303c78f3a601503aa15c145acd5d5a63 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.209 2007/08/31 04:52:29 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.210 2007/10/13 23:06:26 tgl Exp $ -->
 
  <chapter id="datatype">
   <title id="datatype-title">Data Types</title>
        <entry>full text search document</entry>
       </row>
 
+      <row>
+       <entry><type>txid_snapshot</type></entry>
+       <entry></entry>
+       <entry>user-level transaction ID snapshot</entry>
+      </row>
+
       <row>
        <entry><type>uuid</type></entry>
        <entry></entry>
index 0eeb1545d985e2e56777710ed6650554208673ee..8d4f4179ac8eecec8c544c7c0e703bfd41122beb 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.400 2007/10/11 02:43:55 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.401 2007/10/13 23:06:26 tgl Exp $ -->
 
  <chapter id="functions">
   <title>Functions and Operators</title>
@@ -12048,6 +12048,84 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
     databases within each cluster and their descriptions are stored globally
     as well.
    </para>
+
+   <indexterm>
+    <primary>txid_current</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>txid_current_snapshot</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>txid_snapshot_xmin</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>txid_snapshot_xmax</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>txid_snapshot_xip</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>txid_visible_in_snapshot</primary>
+   </indexterm>
+
+   <para>
+    The functions shown in <xref linkend="functions-txid-snapshot">
+    export server internal transaction info to user level.
+   </para>
+
+   <table id="functions-txid-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>txid_current</function>()</literal></entry>
+       <entry><type>bigint</type></entry>
+       <entry>get current transaction ID</entry>
+      </row>
+      <row>
+       <entry><literal><function>txid_current_snapshot</function>()</literal></entry>
+       <entry><type>txid_snapshot</type></entry>
+       <entry>get current snapshot</entry>
+      </row>
+      <row>
+       <entry><literal><function>txid_snapshot_xmin</function>(<parameter>txid_snapshot</parameter>)</literal></entry>
+       <entry><type>bigint</type></entry>
+       <entry>get xmin of snapshot</entry>
+      </row>
+      <row>
+       <entry><literal><function>txid_snapshot_xmax</function>(<parameter>txid_snapshot</parameter>)</literal></entry>
+       <entry><type>bigint</type></entry>
+       <entry>get xmax of snapshot</entry>
+      </row>
+      <row>
+       <entry><literal><function>txid_snapshot_xip</function>(<parameter>txid_snapshot</parameter>)</literal></entry>
+       <entry><type>setof bigint</type></entry>
+       <entry>get in-progress transaction IDs in snapshot</entry>
+      </row>
+      <row>
+       <entry><literal><function>txid_visible_in_snapshot</function>(<parameter>bigint</parameter>, <parameter>txid_snapshot</parameter>)</literal></entry>
+       <entry><type>boolean</type></entry>
+       <entry>is transaction ID visible in snapshot?</entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+
+   <para>
+    The internal transaction ID type (<type>xid</>) is 32 bits wide and so
+    it wraps around every 4 billion transactions.  However, these functions
+    export a 64-bit format that is extended with an <quote>epoch</> counter
+    so that it will not wrap around for the life of an installation.
+   </para>
   </sect1>
 
  <sect1 id="functions-admin">
index 9a75c736df650dbf215a6c9f1bfcb35e70a4d1a8..4b90e0739e6c375fe69687046a47729c124b67e0 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Makefile for utils/adt
 #
-# $PostgreSQL: pgsql/src/backend/utils/adt/Makefile,v 1.67 2007/09/07 15:09:56 teodor Exp $
+# $PostgreSQL: pgsql/src/backend/utils/adt/Makefile,v 1.68 2007/10/13 23:06:26 tgl Exp $
 #
 
 subdir = src/backend/utils/adt
@@ -28,8 +28,8 @@ OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \
        ascii.o quote.o pgstatfuncs.o encode.o dbsize.o genfile.o \
        tsginidx.o tsgistidx.o tsquery.o tsquery_cleanup.o tsquery_gist.o \
        tsquery_op.o tsquery_rewrite.o tsquery_util.o tsrank.o \
-       tsvector.o tsvector_op.o tsvector_parser.o\
-       uuid.o xml.o
+       tsvector.o tsvector_op.o tsvector_parser.o \
+       txid.o uuid.o xml.o
 
 like.o: like.c like_match.c
 
diff --git a/src/backend/utils/adt/txid.c b/src/backend/utils/adt/txid.c
new file mode 100644 (file)
index 0000000..f4267df
--- /dev/null
@@ -0,0 +1,583 @@
+/*-------------------------------------------------------------------------
+ * txid.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
+ * 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().
+ *
+ *
+ *     Copyright (c) 2003-2007, PostgreSQL Global Development Group
+ *     Author: Jan Wieck, Afilias USA INC.
+ *     64-bit txids: Marko Kreen, Skype Technologies
+ *
+ *     $PostgreSQL: pgsql/src/backend/utils/adt/txid.c,v 1.1 2007/10/13 23:06:26 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/transam.h"
+#include "access/xact.h"
+#include "funcapi.h"
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
+
+
+#ifndef INT64_IS_BUSTED
+/* txid will be signed int8 in database, so must limit to 63 bits */
+#define MAX_TXID   UINT64CONST(0x7FFFFFFFFFFFFFFF)
+#else
+/* we only really have 32 bits to work with :-( */
+#define MAX_TXID   UINT64CONST(0x7FFFFFFF)
+#endif
+
+/* 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
+ * that have more than the specified number of values.
+ */
+#define USE_BSEARCH_IF_NXIP_GREATER 30
+
+
+/*
+ * Snapshot containing 8byte txids.
+ */
+typedef struct
+{
+       /*
+        * 4-byte length hdr, should not be touched directly.
+        *
+        * Explicit embedding is ok as we want always correct
+        * alignment anyway.
+        */
+    int32       __varsz;
+       
+    uint32      nxip;          /* number of txids in xip array */
+    txid               xmin;
+    txid               xmax;
+    txid               xip[1];         /* in-progress txids, xmin <= xip[i] < xmax */
+}   TxidSnapshot;
+
+#define TXID_SNAPSHOT_SIZE(nxip) \
+       (offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip))
+
+/*
+ * 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)
+{
+       GetNextXidAndEpoch(&state->last_xid, &state->epoch);
+}
+
+/*
+ * do a TransactionId -> txid conversion for an XID near the given epoch
+ */
+static txid
+convert_xid(TransactionId xid, const TxidEpoch *state)
+{
+#ifndef INT64_IS_BUSTED
+       uint64 epoch;
+
+       /* return special xid's as-is */
+       if (!TransactionIdIsNormal(xid))
+               return (txid) 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))
+               epoch--;
+       else if (xid < state->last_xid &&
+                        TransactionIdFollows(xid, state->last_xid))
+               epoch++;
+
+       return (epoch << 32) | xid;
+#else /* INT64_IS_BUSTED */
+       /* we can't do anything with the epoch, so ignore it */
+       return (txid) xid & MAX_TXID;
+#endif /* INT64_IS_BUSTED */
+}
+
+/*
+ * txid comparator for qsort/bsearch
+ */
+static int
+cmp_txid(const void *aa, const void *bb)
+{
+       txid    a = *(const txid *) aa;
+       txid    b = *(const txid *) bb;
+
+       if (a < b)
+               return -1;
+       if (a > b)
+               return 1;
+       return 0;
+}
+
+/*
+ * sort a snapshot's txids, so we can use bsearch() later.
+ *
+ * For consistency of on-disk representation, we always sort even if bsearch
+ * will not be used.
+ */
+static void
+sort_snapshot(TxidSnapshot *snap)
+{
+       if (snap->nxip > 1)
+               qsort(snap->xip, snap->nxip, sizeof(txid), cmp_txid);
+}
+
+/*
+ * check txid visibility.
+ */
+static bool
+is_visible_txid(txid value, const TxidSnapshot *snap)
+{
+       if (value < snap->xmin)
+               return true;
+       else if (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);
+               /* if found, transaction is still in progress */
+               return (res) ? false : true;
+       }
+#endif
+       else
+       {
+               uint32 i;
+
+               for (i = 0; i < snap->nxip; i++)
+               {
+                       if (value == snap->xip[i])
+                               return false;
+               }
+               return true;
+       }
+}
+
+/*
+ * helper functions to use StringInfo for TxidSnapshot creation.
+ */
+
+static StringInfo
+buf_init(txid xmin, txid xmax)
+{
+       TxidSnapshot snap;
+       StringInfo buf;
+
+       snap.xmin = xmin;
+       snap.xmax = xmax;
+       snap.nxip = 0;
+
+       buf = makeStringInfo();
+       appendBinaryStringInfo(buf, (char *)&snap, TXID_SNAPSHOT_SIZE(0));
+       return buf;
+}
+
+static void
+buf_add_txid(StringInfo buf, txid xid)
+{
+       TxidSnapshot *snap = (TxidSnapshot *)buf->data;
+
+       /* do this before possible realloc */
+       snap->nxip++;
+
+       appendBinaryStringInfo(buf, (char *)&xid, sizeof(xid));
+}
+
+static TxidSnapshot *
+buf_finalize(StringInfo buf)
+{
+       TxidSnapshot *snap = (TxidSnapshot *)buf->data;
+
+       SET_VARSIZE(snap, buf->len);
+
+       /* buf is not needed anymore */
+       buf->data = NULL;
+       pfree(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 *
+parse_snapshot(const char *str)
+{
+       txid            xmin;
+       txid            xmax;
+       txid            last_val = 0, val;
+       const char *str_start = str;
+       const char *endp;
+       StringInfo  buf;
+
+       xmin = str2txid(str, &endp);
+       if (*endp != ':')
+               goto bad_format;
+       str = endp + 1;
+
+       xmax = str2txid(str, &endp);
+       if (*endp != ':')
+               goto bad_format;
+       str = endp + 1;
+
+       /* it should look sane */
+       if (xmin == 0 || xmax == 0 || xmin > xmax)
+               goto bad_format;
+
+       /* allocate buffer */
+       buf = buf_init(xmin, xmax);
+
+       /* loop over values */
+       while (*str != '\0')
+       {
+               /* read next value */
+               val = str2txid(str, &endp);
+               str = endp;
+
+               /* require the input to be in order */
+               if (val < xmin || val >= xmax || val <= last_val)
+                       goto bad_format;
+               
+               buf_add_txid(buf, val);
+               last_val = val;
+
+               if (*str == ',')
+                       str++;
+               else if (*str != '\0')
+                       goto bad_format;
+       }
+
+       return buf_finalize(buf);
+
+bad_format:
+       elog(ERROR, "invalid input for txid_snapshot: \"%s\"", str_start);
+       return NULL;
+}
+
+/*
+ * 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
+ *
+ *             Return the current toplevel transaction ID as TXID
+ */
+Datum
+txid_current(PG_FUNCTION_ARGS)
+{
+       txid val;
+       TxidEpoch state;
+
+       load_xid_epoch(&state);
+
+       val = convert_xid(GetTopTransactionId(), &state);
+
+       PG_RETURN_INT64(val);
+}
+
+/*
+ * txid_current_snapshot() returns txid_snapshot
+ *
+ *             Return current snapshot in TXID format
+ *
+ * Note that only top-transaction XIDs are included in the snapshot.
+ */
+Datum
+txid_current_snapshot(PG_FUNCTION_ARGS)
+{
+       TxidSnapshot *snap;
+       uint32 nxip, i, size;
+       TxidEpoch state;
+       Snapshot cur;
+
+       cur = ActiveSnapshot;
+       if (cur == NULL)
+               elog(ERROR, "txid_current_snapshot: ActiveSnapshot == NULL");
+
+       load_xid_epoch(&state);
+
+       /* allocate */
+       nxip = cur->xcnt;
+       size = TXID_SNAPSHOT_SIZE(nxip);
+       snap = palloc(size);
+       SET_VARSIZE(snap, size);
+
+       /* fill */
+       snap->xmin = convert_xid(cur->xmin, &state);
+       snap->xmax = convert_xid(cur->xmax, &state);
+       snap->nxip = nxip;
+       for (i = 0; i < nxip; i++)
+               snap->xip[i] = convert_xid(cur->xip[i], &state);
+
+       /* we want them guaranteed to be in ascending order */
+       sort_snapshot(snap);
+
+       PG_RETURN_POINTER(snap);
+}
+
+/*
+ * txid_snapshot_in(cstring) returns txid_snapshot
+ *
+ *             input function for type txid_snapshot
+ */
+Datum
+txid_snapshot_in(PG_FUNCTION_ARGS)
+{
+       char       *str = PG_GETARG_CSTRING(0);
+       TxidSnapshot *snap;
+
+       snap = parse_snapshot(str);
+
+       PG_RETURN_POINTER(snap);
+}
+
+/*
+ * txid_snapshot_out(txid_snapshot) returns cstring
+ *
+ *             output function for type txid_snapshot
+ */
+Datum
+txid_snapshot_out(PG_FUNCTION_ARGS)
+{
+       TxidSnapshot   *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
+       StringInfoData  str;
+       uint32                  i;
+
+       initStringInfo(&str);
+
+       appendStringInfo(&str, TXID_FMT ":", snap->xmin);
+       appendStringInfo(&str, TXID_FMT ":", snap->xmax);
+
+       for (i = 0; i < snap->nxip; i++)
+       {
+               if (i > 0)
+                       appendStringInfoChar(&str, ',');
+               appendStringInfo(&str, TXID_FMT, snap->xip[i]);
+       }
+
+       PG_RETURN_CSTRING(str.data);
+}
+
+/*
+ * txid_snapshot_recv(internal) returns txid_snapshot
+ *
+ *             binary input function for type txid_snapshot
+ *
+ *             format: int4 nxip, int8 xmin, int8 xmax, int8 xip
+ */
+Datum
+txid_snapshot_recv(PG_FUNCTION_ARGS)
+{
+       StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
+       TxidSnapshot *snap;
+       txid last = 0;
+       int nxip;
+       int i;
+       int avail;
+       int expect;
+       txid xmin, xmax;
+
+       /*
+        * load nxip and check for nonsense.
+        *
+        * (nxip > avail) check is against int overflows in 'expect'.
+        */
+       nxip = pq_getmsgint(buf, 4);
+       avail = buf->len - buf->cursor;
+       expect = 8 + 8 + nxip * 8;
+       if (nxip < 0 || nxip > avail || expect > avail)
+               goto bad_format;
+
+       xmin = pq_getmsgint64(buf);
+       xmax = pq_getmsgint64(buf);
+       if (xmin == 0 || xmax == 0 || xmin > xmax || xmax > MAX_TXID)
+               goto bad_format;
+
+       snap = palloc(TXID_SNAPSHOT_SIZE(nxip));
+       snap->xmin = xmin;
+       snap->xmax = xmax;
+       snap->nxip = nxip;
+       SET_VARSIZE(snap, TXID_SNAPSHOT_SIZE(nxip));
+
+       for (i = 0; i < nxip; i++)
+       {
+               txid cur =  pq_getmsgint64(buf);
+               if (cur <= last || cur < xmin || cur >= xmax)
+                       goto bad_format;
+               snap->xip[i] = cur;
+               last = cur;
+       }
+       PG_RETURN_POINTER(snap);
+
+bad_format:
+       elog(ERROR, "invalid snapshot data");
+       return (Datum)NULL;
+}
+
+/*
+ * txid_snapshot_send(txid_snapshot) returns bytea
+ *
+ *             binary output function for type txid_snapshot
+ *
+ *             format: int4 nxip, int8 xmin, int8 xmax, int8 xip
+ */
+Datum
+txid_snapshot_send(PG_FUNCTION_ARGS)
+{
+       TxidSnapshot *snap = (TxidSnapshot *)PG_GETARG_VARLENA_P(0);
+       StringInfoData buf;
+       uint32 i;
+
+       pq_begintypsend(&buf);
+       pq_sendint(&buf, snap->nxip, 4);
+       pq_sendint64(&buf, snap->xmin);
+       pq_sendint64(&buf, snap->xmax);
+       for (i = 0; i < snap->nxip; i++)
+               pq_sendint64(&buf, snap->xip[i]);
+       PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+/*
+ * txid_visible_in_snapshot(int8, txid_snapshot) returns bool
+ *
+ *             is txid visible in snapshot ?
+ */
+Datum
+txid_visible_in_snapshot(PG_FUNCTION_ARGS)
+{
+       txid value = PG_GETARG_INT64(0);
+       TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(1);
+       
+       PG_RETURN_BOOL(is_visible_txid(value, snap));
+}
+
+/*
+ * txid_snapshot_xmin(txid_snapshot) returns int8
+ *
+ *             return snapshot's xmin
+ */
+Datum
+txid_snapshot_xmin(PG_FUNCTION_ARGS)
+{
+       TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
+
+       PG_RETURN_INT64(snap->xmin);
+}
+
+/*
+ * txid_snapshot_xmax(txid_snapshot) returns int8
+ *
+ *             return snapshot's xmax
+ */
+Datum
+txid_snapshot_xmax(PG_FUNCTION_ARGS)
+{
+       TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
+
+       PG_RETURN_INT64(snap->xmax);
+}
+
+/*
+ * txid_snapshot_xip(txid_snapshot) returns setof int8
+ *
+ *             return in-progress TXIDs in snapshot.
+ */
+Datum
+txid_snapshot_xip(PG_FUNCTION_ARGS)
+{
+       FuncCallContext *fctx;
+       TxidSnapshot *snap;
+       txid value;
+
+       /* on first call initialize snap_state and get copy of snapshot */
+       if (SRF_IS_FIRSTCALL()) {
+               TxidSnapshot *arg = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
+
+               fctx = SRF_FIRSTCALL_INIT();
+
+               /* make a copy of user snapshot */
+               snap = MemoryContextAlloc(fctx->multi_call_memory_ctx, VARSIZE(arg));
+               memcpy(snap, arg, VARSIZE(arg));
+
+               fctx->user_fctx = snap;
+       }
+
+       /* return values one-by-one */
+       fctx = SRF_PERCALL_SETUP();
+       snap = fctx->user_fctx;
+       if (fctx->call_cntr < snap->nxip) {
+               value = snap->xip[fctx->call_cntr];
+               SRF_RETURN_NEXT(fctx, Int64GetDatum(value));
+       } else {
+               SRF_RETURN_DONE(fctx);
+       }
+}
index 4c9e6ea868ebac17b67dee61ea920176278c461d..8c2d5f7a4a96113ebb67153e8ca9a533a4fdad5a 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.431 2007/10/13 20:18:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.432 2007/10/13 23:06:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200710131
+#define CATALOG_VERSION_NO     200710141
 
 #endif
index 9578ff1e735bff17bb92eb184434e7215330b855..1ed01b527b1b42fc6e4d3cf32c6075c03f4128a1 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.473 2007/09/25 20:03:38 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.474 2007/10/13 23:06:26 tgl Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -4399,6 +4399,28 @@ DESCR("I/O");
 DATA(insert OID = 3774 (  regdictionarysend    PGNSP PGUID 12 1 0 f f t f i 1 17 "3769" _null_ _null_ _null_ regdictionarysend - _null_ _null_ ));
 DESCR("I/O");
 
+/* txid */
+DATA(insert OID = 2939 (  txid_snapshot_in                     PGNSP PGUID 12 1  0 f f t f i 1 2970 "2275"     _null_ _null_ _null_ txid_snapshot_in - _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2940 (  txid_snapshot_out                    PGNSP PGUID 12 1  0 f f t f i 1 2275 "2970" _null_ _null_ _null_ txid_snapshot_out - _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2941 (  txid_snapshot_recv           PGNSP PGUID 12 1  0 f f t f i 1 2970 "2281"     _null_ _null_ _null_ txid_snapshot_recv - _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2942 (  txid_snapshot_send           PGNSP PGUID 12 1  0 f f t f i 1 17 "2970"       _null_ _null_ _null_ txid_snapshot_send - _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2943 (  txid_current                         PGNSP PGUID 12 1  0 f f t f s 0 20 ""           _null_ _null_ _null_ txid_current - _null_ _null_ ));
+DESCR("get current transaction ID");
+DATA(insert OID = 2944 (  txid_current_snapshot                PGNSP PGUID 12 1  0 f f t f s 0 2970 ""         _null_ _null_ _null_ txid_current_snapshot - _null_ _null_ ));
+DESCR("get current snapshot");
+DATA(insert OID = 2945 (  txid_snapshot_xmin           PGNSP PGUID 12 1  0 f f t f i 1 20 "2970"       _null_ _null_ _null_ txid_snapshot_xmin - _null_ _null_ ));
+DESCR("get xmin of snapshot");
+DATA(insert OID = 2946 (  txid_snapshot_xmax           PGNSP PGUID 12 1  0 f f t f i 1 20 "2970"       _null_ _null_ _null_ txid_snapshot_xmax - _null_ _null_ ));
+DESCR("get xmax of snapshot");
+DATA(insert OID = 2947 (  txid_snapshot_xip                    PGNSP PGUID 12 1 50 f f t t i 1 20 "2970"       _null_ _null_ _null_ txid_snapshot_xip - _null_ _null_ ));
+DESCR("get set of in-progress txids in snapshot");
+DATA(insert OID = 2948 (  txid_visible_in_snapshot     PGNSP PGUID 12 1  0 f f t f i 2 16 "20 2970" _null_ _null_ _null_ txid_visible_in_snapshot - _null_ _null_ ));
+DESCR("is txid visible in snapshot?");
+
 
 /*
  * Symbolic values for provolatile column: these indicate whether the result
index 2c81dafb2f6c9a2c46b00d1b7042db91ac8f1f70..7fd0b41da7cae10a039fa8623e0a4dfe11e8fcf0 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.188 2007/09/03 02:30:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.189 2007/10/13 23:06:27 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -572,6 +572,10 @@ DATA(insert OID = 3645 ( _tsquery          PGNSP PGUID -1 f b t \054 0     3615 0 array_in a
 DATA(insert OID = 3735 ( _regconfig            PGNSP PGUID -1 f b t \054 0 3734 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
 DATA(insert OID = 3770 ( _regdictionary        PGNSP PGUID -1 f b t \054 0 3769 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
 
+DATA(insert OID = 2970 ( txid_snapshot PGNSP PGUID -1 f b t \054 0 0 2949 txid_snapshot_in txid_snapshot_out txid_snapshot_recv txid_snapshot_send - - - d x f 0 -1 0 _null_ _null_ ));
+DESCR("txid snapshot");
+DATA(insert OID = 2949 ( _txid_snapshot        PGNSP PGUID -1 f b t \054 0     2970 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ ));
+
 /*
  * pseudo-types
  *
index d1b11a5e6253528a43cda7f96c60947e10a23481..780c4c51d0ab37e67cd1e5b5c6266bf052974c00 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.304 2007/09/24 01:29:30 adunstan Exp $
+ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.305 2007/10/13 23:06:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -938,14 +938,17 @@ extern Datum pg_advisory_unlock_int4(PG_FUNCTION_ARGS);
 extern Datum pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS);
 extern Datum pg_advisory_unlock_all(PG_FUNCTION_ARGS);
 
-/* access/transam/twophase.c */
-extern Datum pg_prepared_xact(PG_FUNCTION_ARGS);
-
-/* commands/prepare.c */
-extern Datum pg_prepared_statement(PG_FUNCTION_ARGS);
-
-/* utils/mmgr/portalmem.c */
-extern Datum pg_cursor(PG_FUNCTION_ARGS);
+/* txid.c */
+extern Datum txid_snapshot_in(PG_FUNCTION_ARGS);
+extern Datum txid_snapshot_out(PG_FUNCTION_ARGS);
+extern Datum txid_snapshot_recv(PG_FUNCTION_ARGS);
+extern Datum txid_snapshot_send(PG_FUNCTION_ARGS);
+extern Datum txid_current(PG_FUNCTION_ARGS);
+extern Datum txid_current_snapshot(PG_FUNCTION_ARGS);
+extern Datum txid_snapshot_xmin(PG_FUNCTION_ARGS);
+extern Datum txid_snapshot_xmax(PG_FUNCTION_ARGS);
+extern Datum txid_snapshot_xip(PG_FUNCTION_ARGS);
+extern Datum txid_visible_in_snapshot(PG_FUNCTION_ARGS);
 
 /* uuid.c */
 extern Datum uuid_in(PG_FUNCTION_ARGS);
@@ -961,4 +964,13 @@ extern Datum uuid_ne(PG_FUNCTION_ARGS);
 extern Datum uuid_cmp(PG_FUNCTION_ARGS);
 extern Datum uuid_hash(PG_FUNCTION_ARGS);
 
+/* access/transam/twophase.c */
+extern Datum pg_prepared_xact(PG_FUNCTION_ARGS);
+
+/* commands/prepare.c */
+extern Datum pg_prepared_statement(PG_FUNCTION_ARGS);
+
+/* utils/mmgr/portalmem.c */
+extern Datum pg_cursor(PG_FUNCTION_ARGS);
+
 #endif   /* BUILTINS_H */
diff --git a/src/test/regress/expected/txid.out b/src/test/regress/expected/txid.out
new file mode 100644 (file)
index 0000000..59b6293
--- /dev/null
@@ -0,0 +1,226 @@
+-- txid_snapshot data type and related functions
+-- i/o
+select '12:13:'::txid_snapshot;
+ txid_snapshot 
+---------------
+ 12:13:
+(1 row)
+
+select '12:18:14,16'::txid_snapshot;
+ txid_snapshot 
+---------------
+ 12:18:14,16
+(1 row)
+
+-- errors
+select '31:12:'::txid_snapshot;
+ERROR:  invalid input for txid_snapshot: "31:12:"
+select '0:1:'::txid_snapshot;
+ERROR:  invalid input for txid_snapshot: "0:1:"
+select '12:13:0'::txid_snapshot;
+ERROR:  invalid input for txid_snapshot: "12:13:0"
+select '12:16:14,13'::txid_snapshot;
+ERROR:  invalid input for txid_snapshot: "12:16:14,13"
+select '12:16:14,14'::txid_snapshot;
+ERROR:  invalid input for txid_snapshot: "12:16:14,14"
+create temp table snapshot_test (
+       nr      integer,
+       snap    txid_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  txid_snapshot_xmin(snap),
+       txid_snapshot_xmax(snap),
+       txid_snapshot_xip(snap)
+from snapshot_test order by nr;
+ txid_snapshot_xmin | txid_snapshot_xmax | txid_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, txid_visible_in_snapshot(id, snap)
+from snapshot_test, generate_series(11, 21) id
+where nr = 2;
+ id | txid_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, txid_visible_in_snapshot(id, snap)
+from snapshot_test, generate_series(90, 160) id
+where nr = 4;
+ id  | txid_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 txid_current() >= txid_snapshot_xmin(txid_current_snapshot());
+ ?column? 
+----------
+ t
+(1 row)
+
+-- we can't assume current is always less than xmax, however
+select txid_visible_in_snapshot(txid_current(), txid_current_snapshot());
+ txid_visible_in_snapshot 
+--------------------------
+ f
+(1 row)
+
+-- test 64bitness
+select txid_snapshot '1000100010001000:1000100010001100:1000100010001012,1000100010001013';
+                            txid_snapshot                            
+---------------------------------------------------------------------
+ 1000100010001000:1000100010001100:1000100010001012,1000100010001013
+(1 row)
+
+select txid_visible_in_snapshot('1000100010001012', '1000100010001000:1000100010001100:1000100010001012,1000100010001013');
+ txid_visible_in_snapshot 
+--------------------------
+ f
+(1 row)
+
+select txid_visible_in_snapshot('1000100010001015', '1000100010001000:1000100010001100:1000100010001012,1000100010001013');
+ txid_visible_in_snapshot 
+--------------------------
+ t
+(1 row)
+
+-- test 64bit overflow
+SELECT txid_snapshot '1:9223372036854775807:3';
+      txid_snapshot      
+-------------------------
+ 1:9223372036854775807:3
+(1 row)
+
+SELECT txid_snapshot '1:9223372036854775808:3';
+ERROR:  invalid input for txid_snapshot: "1:9223372036854775808:3"
index 4d5af5b16d5d59e6ea1faf115aba3536236fdd5e..6d33f3802045456a48916a5b372338d9eede6219 100644 (file)
@@ -1,5 +1,5 @@
 # ----------
-# $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.44 2007/09/11 11:54:42 teodor Exp $
+# $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.45 2007/10/13 23:06:27 tgl Exp $
 #
 # By convention, we put no more than twenty tests in any one parallel group;
 # this limits the number of connections needed to run the tests.
@@ -8,7 +8,7 @@
 # ----------
 # The first group of parallel tests
 # ----------
-test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric uuid enum
+test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric txid uuid enum
 
 # Depends on things setup during char, varchar and text
 test: strings
index 856682469cce9411a3208b392a9f6745eff8a9bd..fdb8446f657568bfca41c5e3784ba841ac47fd40 100644 (file)
@@ -1,4 +1,4 @@
-# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.41 2007/09/11 11:54:42 teodor Exp $
+# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.42 2007/10/13 23:06:27 tgl Exp $
 # This should probably be in an order similar to parallel_schedule.
 test: boolean
 test: char
@@ -13,6 +13,7 @@ test: float4
 test: float8
 test: bit
 test: numeric
+test: txid
 test: uuid
 test: enum
 test: strings
diff --git a/src/test/regress/sql/txid.sql b/src/test/regress/sql/txid.sql
new file mode 100644 (file)
index 0000000..ecae10e
--- /dev/null
@@ -0,0 +1,54 @@
+-- txid_snapshot data type and related functions
+
+-- i/o
+select '12:13:'::txid_snapshot;
+select '12:18:14,16'::txid_snapshot;
+
+-- errors
+select '31:12:'::txid_snapshot;
+select '0:1:'::txid_snapshot;
+select '12:13:0'::txid_snapshot;
+select '12:16:14,13'::txid_snapshot;
+select '12:16:14,14'::txid_snapshot;
+
+create temp table snapshot_test (
+       nr      integer,
+       snap    txid_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  txid_snapshot_xmin(snap),
+       txid_snapshot_xmax(snap),
+       txid_snapshot_xip(snap)
+from snapshot_test order by nr;
+
+select id, txid_visible_in_snapshot(id, snap)
+from snapshot_test, generate_series(11, 21) id
+where nr = 2;
+
+-- test bsearch
+select id, txid_visible_in_snapshot(id, snap)
+from snapshot_test, generate_series(90, 160) id
+where nr = 4;
+
+-- test current values also
+select txid_current() >= txid_snapshot_xmin(txid_current_snapshot());
+
+-- we can't assume current is always less than xmax, however
+
+select txid_visible_in_snapshot(txid_current(), txid_current_snapshot());
+
+-- test 64bitness
+
+select txid_snapshot '1000100010001000:1000100010001100:1000100010001012,1000100010001013';
+select txid_visible_in_snapshot('1000100010001012', '1000100010001000:1000100010001100:1000100010001012,1000100010001013');
+select txid_visible_in_snapshot('1000100010001015', '1000100010001000:1000100010001100:1000100010001012,1000100010001013');
+
+-- test 64bit overflow
+SELECT txid_snapshot '1:9223372036854775807:3';
+SELECT txid_snapshot '1:9223372036854775808:3';