diff -crN pgsql.orig/doc/src/sgml/datatype.sgml pgsql/doc/src/sgml/datatype.sgml
*** pgsql.orig/doc/src/sgml/datatype.sgml 2007-08-31 07:52:29.000000000 +0300
--- pgsql/doc/src/sgml/datatype.sgml 2007-10-11 16:29:07.000000000 +0300
***************
*** 247,252 ****
--- 247,258 ----
+ txid_snapshot
+
+ user-level transaction id snapshot
+
+
+
uuid
universally unique identifier
diff -crN pgsql.orig/doc/src/sgml/func.sgml pgsql/doc/src/sgml/func.sgml
*** pgsql.orig/doc/src/sgml/func.sgml 2007-09-24 04:29:27.000000000 +0300
--- pgsql/doc/src/sgml/func.sgml 2007-10-11 17:37:04.000000000 +0300
***************
*** 12048,12054 ****
databases within each cluster and their descriptions are stored globally
as well.
!
System Administration Functions
--- 12048,12126 ----
databases within each cluster and their descriptions are stored globally
as well.
!
!
!
! txid_current
!
!
!
! txid_current_snapshot
!
!
!
! txid_snapshot_xmin
!
!
!
! txid_snapshot_xmax
!
!
!
! txid_snapshot_xip
!
!
!
! txid_visible_in_snapshot
!
!
!
! The functions shown in
! export backend internal transaction info to user level.
!
!
!
! Transaction IDs and snapshots
!
!
! Name Return Type Description
!
!
!
!
! txid_current()
! int8
! get current transaction id
!
!
! txid_current_snapshot()
! txid_snapshot
! get current snapshot
!
!
! txid_snapshot_xmin(txid_snapshot)
! int8
! get xmin of snapshot
!
!
! txid_snapshot_xmax(txid_snapshot)
! int8
! get xmax of snapshot
!
!
! txid_snapshot_xip(txid_snapshot)
! setof int8
! get in-progress transaction ids in snapshot
!
!
! txid_visible_in_snapshot(int8, txid_snapshot)
! bool
! check if transaction id is visible in snapshot
!
!
!
!
!
System Administration Functions
diff -crN pgsql.orig/src/backend/utils/adt/Makefile pgsql/src/backend/utils/adt/Makefile
*** pgsql.orig/src/backend/utils/adt/Makefile 2007-09-07 18:09:56.000000000 +0300
--- pgsql/src/backend/utils/adt/Makefile 2007-10-11 16:47:59.000000000 +0300
***************
*** 29,35 ****
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
like.o: like.c like_match.c
--- 29,35 ----
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 txid.o xml.o
like.o: like.c like_match.c
diff -crN pgsql.orig/src/backend/utils/adt/txid.c pgsql/src/backend/utils/adt/txid.c
*** pgsql.orig/src/backend/utils/adt/txid.c 1970-01-01 02:00:00.000000000 +0200
--- pgsql/src/backend/utils/adt/txid.c 2007-10-11 16:02:57.000000000 +0300
***************
*** 0 ****
--- 1,581 ----
+ /*-------------------------------------------------------------------------
+ * txid.c
+ *
+ * Export backend internal tranasction id's to user level.
+ *
+ * Copyright (c) 2003-2007, PostgreSQL Global Development Group
+ * Author: Jan Wieck, Afilias USA INC.
+ *
+ * 64-bit txids: Marko Kreen, Skype Technologies
+ *-------------------------------------------------------------------------
+ */
+
+ #include "postgres.h"
+
+ #include "access/transam.h"
+ #include "access/xact.h"
+ #include "funcapi.h"
+ #include "libpq/pqformat.h"
+ #include "utils/builtins.h"
+
+ #ifdef INT64_IS_BUSTED
+ #error txid needs working int64
+ #endif
+
+ /* txid will be signed int8 in database */
+ #define MAX_TXID UINT64CONST(0x7FFFFFFFFFFFFFFF)
+
+ /*
+ * If defined, use bsearch() function for searching
+ * txid's inside snapshots that have more than given values.
+ */
+ #define USE_BSEARCH_IF_NXIP_GREATER 30
+
+ /* format code for uint64 to appendStringInfo */
+ #define TXID_FMT UINT64_FORMAT
+
+ /* Use unsigned variant internally */
+ typedef uint64 txid;
+
+ /*
+ * Snapshot for 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 */
+ } TxidSnapshot;
+
+ #define TXID_SNAPSHOT_SIZE(nxip) (offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip))
+
+ /*
+ * Epoch values from backend.
+ */
+ typedef struct {
+ uint64 last_value;
+ uint64 epoch;
+ } TxidEpoch;
+
+ /*
+ * do a TransactionId -> txid conversion
+ */
+ static txid
+ convert_xid(TransactionId xid, const TxidEpoch *state)
+ {
+ uint64 epoch;
+
+ /* return special xid's as-is */
+ if (xid < FirstNormalTransactionId)
+ return xid;
+
+ /* xid can on both sides on wrap-around */
+ epoch = state->epoch;
+ if (TransactionIdPrecedes(xid, state->last_value)) {
+ if (xid > state->last_value)
+ epoch--;
+ } else if (TransactionIdFollows(xid, state->last_value)) {
+ if (xid < state->last_value)
+ epoch++;
+ }
+ return (epoch << 32) | xid;
+ }
+
+ /*
+ * Fetch epoch data from backend.
+ */
+ static void
+ load_xid_epoch(TxidEpoch *state)
+ {
+ TransactionId xid;
+ uint32 epoch;
+
+ GetNextXidAndEpoch(&xid, &epoch);
+
+ state->epoch = epoch;
+ state->last_value = xid;
+ }
+
+ /*
+ * compare txid in memory.
+ */
+ static int
+ cmp_txid(const void *aa, const void *bb)
+ {
+ const uint64 *a = aa;
+ const uint64 *b = bb;
+ if (*a < *b)
+ return -1;
+ if (*a > *b)
+ return 1;
+ return 0;
+ }
+
+ /*
+ * order txids, for bsearch().
+ */
+ 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);
+ return (res) ? false : true;
+ }
+ #endif
+ else
+ {
+ int 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 it 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 backend xid machinery. All the others work on data
+ * returned by them.
+ *
+ * So they define what an external transaction will be and their
+ * definitions must match. Eg. if one returns subtransactions ids
+ * then other must also.
+ *
+ * Currently only top-level transaction id's are tracked, so they use
+ * GetTopTransactionId() and ActiveSnapshot->xip respectively.
+ */
+
+ /*
+ * txid_current() returns int8
+ *
+ * Return the current transaction ID
+ */
+ 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
+ */
+ Datum
+ txid_current_snapshot(PG_FUNCTION_ARGS)
+ {
+ TxidSnapshot *snap;
+ unsigned 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 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)
+ {
+ TxidSnapshot *snap;
+ char *str = PG_GETARG_CSTRING(0);
+
+ 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;
+ StringInfoData str;
+ int i;
+
+ snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
+
+ initStringInfo(&str);
+
+ appendStringInfo(&str, TXID_FMT ":", snap->xmin);
+ appendStringInfo(&str, TXID_FMT ":", snap->xmax);
+
+ for (i = 0; i < snap->nxip; i++)
+ {
+ appendStringInfo(&str, "%s" TXID_FMT,
+ ((i > 0) ? "," : ""),
+ snap->xip[i]);
+ }
+
+ PG_FREE_IF_COPY(snap, 0);
+
+ 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;
+ StringInfoData buf;
+ int i;
+
+ snap = (TxidSnapshot *)PG_GETARG_VARLENA_P(0);
+
+ 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);
+ int res;
+
+ res = is_visible_txid(value, snap) ? true : false;
+
+ PG_FREE_IF_COPY(snap, 1);
+ PG_RETURN_BOOL(res);
+ }
+
+ /*
+ * 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);
+ txid res = snap->xmin;
+ PG_FREE_IF_COPY(snap, 0);
+ PG_RETURN_INT64(res);
+ }
+
+ /*
+ * 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);
+ txid res = snap->xmax;
+ PG_FREE_IF_COPY(snap, 0);
+ PG_RETURN_INT64(res);
+ }
+
+ /*
+ * 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;
+
+ fctx = SRF_FIRSTCALL_INIT();
+
+ /* make a copy of user snapshot */
+ arg = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
+ snap = MemoryContextAlloc(fctx->multi_call_memory_ctx, VARSIZE(arg));
+ memcpy(snap, arg, VARSIZE(arg));
+ PG_FREE_IF_COPY(arg, 0);
+
+ 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);
+ }
+ }
+
diff -crN pgsql.orig/src/include/catalog/pg_proc.h pgsql/src/include/catalog/pg_proc.h
*** pgsql.orig/src/include/catalog/pg_proc.h 2007-09-25 23:03:38.000000000 +0300
--- pgsql/src/include/catalog/pg_proc.h 2007-10-11 16:21:36.000000000 +0300
***************
*** 4400,4405 ****
--- 4400,4426 ----
DESCR("I/O");
+ 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 top 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 the 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 the 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 list 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("check if txid is visible in snapshot");
+
/*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,
diff -crN pgsql.orig/src/include/catalog/pg_type.h pgsql/src/include/catalog/pg_type.h
*** pgsql.orig/src/include/catalog/pg_type.h 2007-09-03 05:30:45.000000000 +0300
--- pgsql/src/include/catalog/pg_type.h 2007-10-11 16:21:36.000000000 +0300
***************
*** 566,571 ****
--- 566,579 ----
DESCR("registered text search dictionary");
#define REGDICTIONARYOID 3769
+ DATA(insert OID = 2970 ( txid_snapshot PGNSP PGUID -1 f b t \054 0 0 0 txid_snapshot_in txid_snapshot_out txid_snapshot_recv txid_snapshot_send - - - d x f 0 -1 0 _null_ _null_ ));
+ DESCR("txid snapshot type");
+ #define TXIDSNAPSHOTOID 2970
+ DATA(insert OID = 2034 ( _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_ ));
+ DESCR("txid snapshot array type");
+ #define TXIDSNAPSHOTARRAYOID 2034
+
+
DATA(insert OID = 3643 ( _tsvector PGNSP PGUID -1 f b t \054 0 3614 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 3644 ( _gtsvector PGNSP PGUID -1 f b t \054 0 3642 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 3645 ( _tsquery PGNSP PGUID -1 f b t \054 0 3615 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
diff -crN pgsql.orig/src/include/utils/builtins.h pgsql/src/include/utils/builtins.h
*** pgsql.orig/src/include/utils/builtins.h 2007-09-24 04:29:30.000000000 +0300
--- pgsql/src/include/utils/builtins.h 2007-10-11 16:21:36.000000000 +0300
***************
*** 961,964 ****
--- 961,976 ----
extern Datum uuid_cmp(PG_FUNCTION_ARGS);
extern Datum uuid_hash(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);
+
#endif /* BUILTINS_H */
diff -crN pgsql.orig/src/test/regress/expected/sanity_check.out pgsql/src/test/regress/expected/sanity_check.out
*** pgsql.orig/src/test/regress/expected/sanity_check.out 2007-08-21 04:11:31.000000000 +0300
--- pgsql/src/test/regress/expected/sanity_check.out 2007-10-11 16:21:36.000000000 +0300
***************
*** 129,134 ****
--- 129,135 ----
road | t
shighway | t
slow_emp4000 | f
+ snapshot_test | t
sql_features | f
sql_implementation_info | f
sql_languages | f
***************
*** 148,154 ****
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
! (137 rows)
--
-- another sanity check: every system catalog that has OIDs should have
--- 149,155 ----
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
! (138 rows)
--
-- another sanity check: every system catalog that has OIDs should have
diff -crN pgsql.orig/src/test/regress/expected/txid.out pgsql/src/test/regress/expected/txid.out
*** pgsql.orig/src/test/regress/expected/txid.out 1970-01-01 02:00:00.000000000 +0200
--- pgsql/src/test/regress/expected/txid.out 2007-10-10 17:55:20.000000000 +0300
***************
*** 0 ****
--- 1,220 ----
+ -- i/o
+ select '12:13:'::txid_snapshot;
+ txid_snapshot
+ ---------------
+ 12:13:
+ (1 row)
+
+ select '12:13:1,2'::txid_snapshot;
+ ERROR: invalid input for txid_snapshot: "12:13:1,2"
+ -- 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 table snapshot_test (
+ nr integer not null primary key,
+ snap txid_snapshot not null
+ );
+ NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "snapshot_test_pkey" for table "snapshot_test"
+ 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)
+
+ /* due to lazy xid alloc in 8.3 those are different in 8.2 and 8.3
+ select txid_current() < txid_snapshot_xmax(txid_current_snapshot());
+
+ select txid_visible_in_snapshot(txid_current(), txid_current_snapshot());
+ */
+ -- 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"
diff -crN pgsql.orig/src/test/regress/output/misc.source pgsql/src/test/regress/output/misc.source
*** pgsql.orig/src/test/regress/output/misc.source 2007-08-21 04:11:31.000000000 +0300
--- pgsql/src/test/regress/output/misc.source 2007-10-11 16:21:36.000000000 +0300
***************
*** 650,655 ****
--- 650,656 ----
road
shighway
slow_emp4000
+ snapshot_test
street
stud_emp
student
***************
*** 666,672 ****
toyemp
varchar_tbl
xacttest
! (100 rows)
SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer')));
name
--- 667,673 ----
toyemp
varchar_tbl
xacttest
! (101 rows)
SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer')));
name
diff -crN pgsql.orig/src/test/regress/parallel_schedule pgsql/src/test/regress/parallel_schedule
*** pgsql.orig/src/test/regress/parallel_schedule 2007-09-11 14:54:42.000000000 +0300
--- pgsql/src/test/regress/parallel_schedule 2007-10-11 16:21:36.000000000 +0300
***************
*** 8,14 ****
# ----------
# The first group of parallel tests
# ----------
! test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric uuid enum
# Depends on things setup during char, varchar and text
test: strings
--- 8,14 ----
# ----------
# The first group of parallel tests
# ----------
! test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric uuid enum txid
# Depends on things setup during char, varchar and text
test: strings
diff -crN pgsql.orig/src/test/regress/sql/txid.sql pgsql/src/test/regress/sql/txid.sql
*** pgsql.orig/src/test/regress/sql/txid.sql 1970-01-01 02:00:00.000000000 +0200
--- pgsql/src/test/regress/sql/txid.sql 2007-10-10 17:48:52.000000000 +0300
***************
*** 0 ****
--- 1,56 ----
+
+ -- i/o
+ select '12:13:'::txid_snapshot;
+ select '12:13:1,2'::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 table snapshot_test (
+ nr integer not null primary key,
+ snap txid_snapshot not null
+ );
+
+ 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());
+
+ /* due to lazy xid alloc in 8.3 those are different in 8.2 and 8.3
+ select txid_current() < txid_snapshot_xmax(txid_current_snapshot());
+
+ 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';
+