From 2035acec2af2c755090f70b87e32a02519ba37d1 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Sun, 1 Sep 2019 16:47:02 +1200 Subject: [PATCH 2/2] Introduce xid8 variants of the txid_XXX() fmgr functions. The txid_XXX() family of functions exposes 64 bit transaction IDs to users as int8. Now that we have an SQL type for FullTransactionId, define a set of functions xid8_XXX() corresponding to the txid_XXX() functions. 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 were already using the wrong signedness, and since we'll presumably drop the txid_XXX() variants after a period of time, it seems reasonable to switch to FullTransactionId internally and share the code for both. Author: Thomas Munro Reviewed-by: Takao Fujii Discussion: https://postgr.es/m/20190725000636.666m5mad25wfbrri%40alap3.anarazel.de --- doc/src/sgml/func.sgml | 112 ++++++++- src/backend/utils/adt/txid.c | 286 +++++++++-------------- src/include/access/transam.h | 3 + src/include/catalog/pg_proc.dat | 41 ++++ src/include/catalog/pg_type.dat | 5 + src/test/regress/expected/opr_sanity.out | 11 +- 6 files changed, 269 insertions(+), 189 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 28eb322f3f..7450c390de 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -19471,6 +19471,38 @@ SELECT collation for ('foo' COLLATE "de_DE"); are stored globally as well. + + xid8_current + + + + xid8_current_if_assigned + + + + xid8_current_snapshot + + + + xid8_snapshot_xip + + + + xid8_snapshot_xmax + + + + xid8_snapshot_xmin + + + + xid8_visible_in_snapshot + + + + xid8_status + + txid_current @@ -19504,12 +19536,74 @@ SELECT collation for ('foo' COLLATE "de_DE"); - The functions shown in + The functions shown in provide server transaction information in an exportable form. The main use of these functions is to determine which transactions were committed between two snapshots. + + Transaction IDs and Snapshots + + + Name Return Type Description + + + + + xid8_current() + xid8 + get current transaction ID, assigning a new one if the current transaction does not have one + + + xid8_current_if_assigned() + xid8 + same as xid8_current() but returns null instead of assigning a new transaction ID if none is already assigned + + + xid8_current_snapshot() + xid8_snapshot + get current snapshot + + + xid8_snapshot_xip(xid8_snapshot) + setof bigint + get in-progress transaction IDs in snapshot + + + xid8_snapshot_xmax(xid8_snapshot) + xid8 + get xmax of snapshot + + + xid8_snapshot_xmin(xid8_snapshot) + xid8 + get xmin of snapshot + + + xid8_visible_in_snapshot(xid8, xid8_snapshot) + boolean + is transaction ID visible in snapshot? (do not use with subtransaction ids) + + + xid8_status(xid8) + text + report the status of the given transaction: committed, aborted, in progress, or null if the transaction ID is too old + + + +
+ + + In releases of PostgreSQL before 13 there was + no xid8 type, so variants of these functions were provided + that used bigint. The older functions with + txid + in the name are still supported for backwards compatibility, but may be + removed from a future release. The bigint variants are shown + in . + + Transaction IDs and Snapshots @@ -19521,42 +19615,42 @@ SELECT collation for ('foo' COLLATE "de_DE"); txid_current() bigint - get current transaction ID, assigning a new one if the current transaction does not have one + see xid8_current() txid_current_if_assigned() bigint - same as txid_current() but returns null instead of assigning a new transaction ID if none is already assigned + see xid8_current_if_assigned() txid_current_snapshot() txid_snapshot - get current snapshot + see xid8_snapshot() txid_snapshot_xip(txid_snapshot) setof bigint - get in-progress transaction IDs in snapshot + see xid8_snapshot_xip() txid_snapshot_xmax(txid_snapshot) bigint - get xmax of snapshot + see xid8_snapshot_xmax() txid_snapshot_xmin(txid_snapshot) bigint - get xmin of snapshot + see xid8_snapshot_xmin() txid_visible_in_snapshot(bigint, txid_snapshot) boolean - is transaction ID visible in snapshot? (do not use with subtransaction ids) + see xid8_visible_in_snapshot() txid_status(bigint) text - report the status of the given transaction: committed, aborted, in progress, or null if the transaction ID is too old + see xid8_status() diff --git a/src/backend/utils/adt/txid.c b/src/backend/utils/adt/txid.c index 90b2c9b694..56ad2b364e 100644 --- a/src/backend/utils/adt/txid.c +++ b/src/backend/utils/adt/txid.c @@ -9,6 +9,12 @@ * rely on being able to correlate subtransaction IDs with their parents * via functions such as SubTransGetTopmostTransaction(). * + * These functions are used to support both txid_XXX and xid8_XXX fmgr + * functions, since the only difference between them is whether they + * expose xid8 or int8 values to users. This works because the types + * are binary compatible for the first 2^63 transactions. The txid_XXX + * variants should eventually be dropped. + * * * Copyright (c) 2003-2019, PostgreSQL Global Development Group * Author: Jan Wieck, Afilias USA INC. @@ -33,17 +39,9 @@ #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 * that have more than the specified number of values. @@ -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]; + uint32 nxip; /* number of fxids in xip array */ + FullTransactionId xmin; + FullTransactionId xmax; + /* in-progress fxids, xmin <= xip[i] < xmax: */ + FullTransactionId xip[FLEXIBLE_ARRAY_MEMBER]; } TxidSnapshot; #define TXID_SNAPSHOT_SIZE(nxip) \ - (offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip)) + (offsetof(TxidSnapshot, xip) + sizeof(FullTransactionId) * (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(); - - state->last_xid = XidFromFullTransactionId(fullXid); - state->epoch = EpochFromFullTransactionId(fullXid); -} + ((MaxAllocSize - offsetof(TxidSnapshot, 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,37 @@ TransactionIdInRecentPast(uint64 xid_with_epoch, TransactionId *extracted_xid) } /* - * do a TransactionId -> txid conversion for an XID near the given epoch + * Do a TransactionId -> fxid conversion for an XID that is known to precede + * the given 'next_fxid'. */ -static txid -convert_xid(TransactionId xid, const TxidEpoch *state) +static FullTransactionId +convert_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 */ 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)) + 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; } @@ -213,21 +186,21 @@ cmp_txid(const void *aa, const void *bb) static void sort_snapshot(TxidSnapshot *snap) { - txid last = 0; + FullTransactionId last = InvalidFullTransactionId; int nxip, idx1, idx2; if (snap->nxip > 1) { - qsort(snap->xip, snap->nxip, sizeof(txid), cmp_txid); + qsort(snap->xip, snap->nxip, sizeof(FullTransactionId), cmp_fxid); /* remove duplicates */ nxip = snap->nxip; idx1 = idx2 = 0; while (idx1 < nxip) { - if (snap->xip[idx1] != last) + if (!FullTransactionIdEquals(snap->xip[idx1], last)) last = snap->xip[idx2++] = snap->xip[idx1]; else snap->nxip--; @@ -237,21 +210,22 @@ sort_snapshot(TxidSnapshot *snap) } /* - * check txid visibility. + * check fxid visibility. */ static bool -is_visible_txid(txid value, const TxidSnapshot *snap) +is_visible_fxid(FullTransactionId value, const TxidSnapshot *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; } @@ -262,7 +236,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; @@ -274,7 +248,7 @@ is_visible_txid(txid value, const TxidSnapshot *snap) */ static StringInfo -buf_init(txid xmin, txid xmax) +buf_init(FullTransactionId xmin, FullTransactionId xmax) { TxidSnapshot snap; StringInfo buf; @@ -289,14 +263,14 @@ buf_init(txid xmin, txid xmax) } static void -buf_add_txid(StringInfo buf, txid xid) +buf_add_txid(StringInfo buf, FullTransactionId fxid) { TxidSnapshot *snap = (TxidSnapshot *) buf->data; /* do this before possible realloc */ snap->nxip++; - appendBinaryStringInfo(buf, (char *) &xid, sizeof(xid)); + appendBinaryStringInfo(buf, (char *) &fxid, sizeof(fxid)); } static TxidSnapshot * @@ -313,68 +287,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 * 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 */ @@ -384,15 +324,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; @@ -421,33 +363,23 @@ bad_format: */ /* - * txid_current() returns int8 + * txid_current() 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) { - 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); - - val = convert_xid(GetTopTransactionId(), &state); + PreventCommandDuringRecovery("xid8_current()"); - PG_RETURN_INT64(val); + PG_RETURN_FULLTRANSACTIONID(GetTopFullTransactionId()); } /* @@ -457,18 +389,12 @@ txid_current(PG_FUNCTION_ARGS) Datum txid_current_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); } /* @@ -484,15 +410,13 @@ txid_current_snapshot(PG_FUNCTION_ARGS) TxidSnapshot *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. @@ -505,11 +429,11 @@ txid_current_snapshot(PG_FUNCTION_ARGS) snap = palloc(TXID_SNAPSHOT_SIZE(nxip)); /* fill */ - snap->xmin = convert_xid(cur->xmin, &state); - snap->xmax = convert_xid(cur->xmax, &state); + snap->xmin = convert_xid(cur->xmin, next_fxid); + snap->xmax = convert_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] = convert_xid(cur->xip[i], next_fxid); /* * We want them guaranteed to be in ascending order. This also removes @@ -556,14 +480,17 @@ txid_snapshot_out(PG_FUNCTION_ARGS) 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); @@ -581,20 +508,22 @@ txid_snapshot_recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); TxidSnapshot *snap; - txid last = 0; + 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) 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)); @@ -603,13 +532,16 @@ txid_snapshot_recv(PG_FUNCTION_ARGS) 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--; @@ -635,7 +567,7 @@ bad_format: * * binary output function for type txid_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) @@ -646,29 +578,29 @@ txid_snapshot_send(PG_FUNCTION_ARGS) 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 + * txid_visible_in_snapshot(xid8, txid_snapshot) returns bool * * is txid visible in snapshot ? */ Datum txid_visible_in_snapshot(PG_FUNCTION_ARGS) { - txid value = PG_GETARG_INT64(0); + FullTransactionId value = PG_GETARG_FULLTRANSACTIONID(0); TxidSnapshot *snap = (TxidSnapshot *) 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 + * txid_snapshot_xmin(txid_snapshot) returns xid8 * * return snapshot's xmin */ @@ -677,11 +609,11 @@ txid_snapshot_xmin(PG_FUNCTION_ARGS) { TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0); - PG_RETURN_INT64(snap->xmin); + PG_RETURN_FULLTRANSACTIONID(snap->xmin); } /* - * txid_snapshot_xmax(txid_snapshot) returns int8 + * txid_snapshot_xmax(txid_snapshot) returns xid8 * * return snapshot's xmax */ @@ -690,11 +622,11 @@ txid_snapshot_xmax(PG_FUNCTION_ARGS) { TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0); - PG_RETURN_INT64(snap->xmax); + PG_RETURN_FULLTRANSACTIONID(snap->xmax); } /* - * txid_snapshot_xip(txid_snapshot) returns setof int8 + * txid_snapshot_xip(txid_snapshot) returns setof xid8 * * return in-progress TXIDs in snapshot. */ @@ -703,7 +635,7 @@ txid_snapshot_xip(PG_FUNCTION_ARGS) { FuncCallContext *fctx; TxidSnapshot *snap; - txid value; + FullTransactionId value; /* on first call initialize fctx and get copy of snapshot */ if (SRF_IS_FIRSTCALL()) @@ -725,7 +657,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 { @@ -747,7 +679,7 @@ Datum txid_status(PG_FUNCTION_ARGS) { const char *status; - uint64 xid_with_epoch = PG_GETARG_INT64(0); + FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0); TransactionId xid; /* @@ -755,7 +687,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)); diff --git a/src/include/access/transam.h b/src/include/access/transam.h index 787451b3b7..884059cbd4 100644 --- a/src/include/access/transam.h +++ b/src/include/access/transam.h @@ -49,6 +49,9 @@ #define U64FromFullTransactionId(x) ((x).value) #define FullTransactionIdEquals(a, b) ((a).value == (b).value) #define FullTransactionIdPrecedes(a, b) ((a).value < (b).value) +#define FullTransactionIdPrecedesOrEquals(a, b) ((a).value <= (b).value) +#define FullTransactionIdFollows(a, b) ((a).value > (b).value) +#define FullTransactionIdFollowsOrEquals(a, b) ((a).value >= (b).value) #define FullTransactionIdIsValid(x) TransactionIdIsValid(XidFromFullTransactionId(x)) #define InvalidFullTransactionId FullTransactionIdFromEpochAndXid(0, InvalidTransactionId) diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 3eb35a4eb6..a7e1230965 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -9423,6 +9423,47 @@ proname => 'txid_status', provolatile => 'v', prorettype => 'text', proargtypes => 'int8', prosrc => 'txid_status' }, +# xid8-based variants of txid functions +{ oid => '9247', descr => 'I/O', + proname => 'xid8_snapshot_in', prorettype => 'xid8_snapshot', + proargtypes => 'cstring', prosrc => 'txid_snapshot_in' }, +{ oid => '9248', descr => 'I/O', + proname => 'xid8_snapshot_out', prorettype => 'cstring', + proargtypes => 'xid8_snapshot', prosrc => 'txid_snapshot_out' }, +{ oid => '9249', descr => 'I/O', + proname => 'xid8_snapshot_recv', prorettype => 'xid8_snapshot', + proargtypes => 'internal', prosrc => 'txid_snapshot_recv' }, +{ oid => '9250', descr => 'I/O', + proname => 'xid8_snapshot_send', prorettype => 'bytea', + proargtypes => 'xid8_snapshot', prosrc => 'txid_snapshot_send' }, +{ oid => '9251', descr => 'get current transaction ID', + proname => 'xid8_current', provolatile => 's', proparallel => 'u', + prorettype => 'xid8', proargtypes => '', prosrc => 'txid_current' }, +{ oid => '9252', descr => 'get current transaction ID', + proname => 'xid8_current_if_assigned', provolatile => 's', proparallel => 'u', + prorettype => 'xid8', proargtypes => '', + prosrc => 'txid_current_if_assigned' }, +{ oid => '9253', descr => 'get current snapshot', + proname => 'xid8_current_snapshot', provolatile => 's', + prorettype => 'xid8_snapshot', proargtypes => '', + prosrc => 'txid_current_snapshot' }, +{ oid => '9254', descr => 'get xmin of snapshot', + proname => 'xid8_snapshot_xmin', prorettype => 'xid8', + proargtypes => 'xid8_snapshot', prosrc => 'txid_snapshot_xmin' }, +{ oid => '9255', descr => 'get xmax of snapshot', + proname => 'xid8_snapshot_xmax', prorettype => 'xid8', + proargtypes => 'xid8_snapshot', prosrc => 'txid_snapshot_xmax' }, +{ oid => '9256', descr => 'get set of in-progress txids in snapshot', + proname => 'xid_snapshot_xip', prorows => '50', proretset => 't', + prorettype => 'xid8', proargtypes => 'xid8_snapshot', + prosrc => 'txid_snapshot_xip' }, +{ oid => '9257', descr => 'is xid8 visible in snapshot?', + proname => 'xid8_visible_in_snapshot', prorettype => 'bool', + proargtypes => 'xid8 xid8_snapshot', prosrc => 'txid_visible_in_snapshot' }, +{ oid => '9258', descr => 'commit status of transaction', + proname => 'xid8_status', provolatile => 'v', prorettype => 'text', + proargtypes => 'xid8', prosrc => 'txid_status' }, + # record comparison using normal comparison rules { oid => '2981', proname => 'record_eq', prorettype => 'bool', proargtypes => 'record record', diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat index c6d20b9946..4aa0d5560d 100644 --- a/src/include/catalog/pg_type.dat +++ b/src/include/catalog/pg_type.dat @@ -455,6 +455,11 @@ 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 => 'xid8 snapshot', + typname => 'xid8_snapshot', typlen => '-1', typbyval => 'f', + typcategory => 'U', typinput => 'xid8_snapshot_in', + typoutput => 'xid8_snapshot_out', typreceive => 'xid8_snapshot_recv', + typsend => 'xid8_snapshot_send', typalign => 'd', typstorage => 'x' }, # range types { oid => '3904', array_type_oid => '3905', descr => 'range of integers', diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index dcaf31eb7b..246419ca1a 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -194,9 +194,11 @@ WHERE p1.oid != p2.oid AND ORDER BY 1, 2; prorettype | prorettype ------------+------------ + 20 | 9560 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 | 9560 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 -- 2.23.0