PostgreSQL Source Code git master
xid8funcs.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 * xid8funcs.c
3 *
4 * Export internal transaction IDs to user level.
5 *
6 * Note that only top-level transaction IDs are exposed to user sessions.
7 * This is important because xid8s frequently persist beyond the global
8 * xmin horizon, or may even be shipped to other machines, so we cannot
9 * rely on being able to correlate subtransaction IDs with their parents
10 * via functions such as SubTransGetTopmostTransaction().
11 *
12 * These functions are used to support the txid_XXX functions and the newer
13 * pg_current_xact_id, pg_current_snapshot and related fmgr functions, since
14 * the only difference between them is whether they expose xid8 or int8 values
15 * to users. The txid_XXX variants should eventually be dropped.
16 *
17 *
18 * Copyright (c) 2003-2025, PostgreSQL Global Development Group
19 * Author: Jan Wieck, Afilias USA INC.
20 * 64-bit txids: Marko Kreen, Skype Technologies
21 *
22 * src/backend/utils/adt/xid8funcs.c
23 *
24 *-------------------------------------------------------------------------
25 */
26
27#include "postgres.h"
28
29#include "access/transam.h"
30#include "access/xact.h"
31#include "funcapi.h"
32#include "lib/qunique.h"
33#include "libpq/pqformat.h"
34#include "miscadmin.h"
35#include "storage/lwlock.h"
36#include "storage/procarray.h"
37#include "storage/procnumber.h"
38#include "utils/builtins.h"
39#include "utils/memutils.h"
40#include "utils/snapmgr.h"
41#include "utils/xid8.h"
42#include "varatt.h"
43
44
45/*
46 * If defined, use bsearch() function for searching for xid8s in snapshots
47 * that have more than the specified number of values.
48 */
49#define USE_BSEARCH_IF_NXIP_GREATER 30
50
51
52/*
53 * Snapshot containing FullTransactionIds.
54 */
55typedef struct
56{
57 /*
58 * 4-byte length hdr, should not be touched directly.
59 *
60 * Explicit embedding is ok as we want always correct alignment anyway.
61 */
63
64 uint32 nxip; /* number of fxids in xip array */
67 /* in-progress fxids, xmin <= xip[i] < xmax: */
70
71#define PG_SNAPSHOT_SIZE(nxip) \
72 (offsetof(pg_snapshot, xip) + sizeof(FullTransactionId) * (nxip))
73#define PG_SNAPSHOT_MAX_NXIP \
74 ((MaxAllocSize - offsetof(pg_snapshot, xip)) / sizeof(FullTransactionId))
75
76/*
77 * Compile-time limits on the procarray (MAX_BACKENDS processes plus
78 * MAX_BACKENDS prepared transactions) guarantee nxip won't be too large.
79 */
81 "possible overflow in pg_current_snapshot()");
82
83
84/*
85 * Helper to get a TransactionId from a 64-bit xid with wraparound detection.
86 *
87 * It is an ERROR if the xid is in the future. Otherwise, returns true if
88 * the transaction is still new enough that we can determine whether it
89 * committed and false otherwise. If *extracted_xid is not NULL, it is set
90 * to the low 32 bits of the transaction ID (i.e. the actual XID, without the
91 * epoch).
92 *
93 * The caller must hold XactTruncationLock since it's dealing with arbitrary
94 * XIDs, and must continue to hold it until it's done with any clog lookups
95 * relating to those XIDs.
96 */
97static bool
99{
101 FullTransactionId now_fullxid;
102 TransactionId oldest_clog_xid;
103 FullTransactionId oldest_clog_fxid;
104
105 now_fullxid = ReadNextFullTransactionId();
106
107 if (extracted_xid != NULL)
108 *extracted_xid = xid;
109
110 if (!TransactionIdIsValid(xid))
111 return false;
112
113 /* For non-normal transaction IDs, we can ignore the epoch. */
114 if (!TransactionIdIsNormal(xid))
115 return true;
116
117 /* If the transaction ID is in the future, throw an error. */
118 if (!FullTransactionIdPrecedes(fxid, now_fullxid))
120 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
121 errmsg("transaction ID %" PRIu64 " is in the future",
123
124 /*
125 * TransamVariables->oldestClogXid is protected by XactTruncationLock, but
126 * we don't acquire that lock here. Instead, we require the caller to
127 * acquire it, because the caller is presumably going to look up the
128 * returned XID. If we took and released the lock within this function, a
129 * CLOG truncation could occur before the caller finished with the XID.
130 */
131 Assert(LWLockHeldByMe(XactTruncationLock));
132
133 /*
134 * If fxid is not older than TransamVariables->oldestClogXid, the relevant
135 * CLOG entry is guaranteed to still exist.
136 *
137 * TransamVariables->oldestXid governs allowable XIDs. Usually,
138 * oldestClogXid==oldestXid. It's also possible for oldestClogXid to
139 * follow oldestXid, in which case oldestXid might advance after our
140 * ReadNextFullTransactionId() call. If oldestXid has advanced, that
141 * advancement reinstated the usual oldestClogXid==oldestXid. Whether or
142 * not that happened, oldestClogXid is allowable relative to now_fullxid.
143 */
144 oldest_clog_xid = TransamVariables->oldestClogXid;
145 oldest_clog_fxid =
146 FullTransactionIdFromAllowableAt(now_fullxid, oldest_clog_xid);
147 return !FullTransactionIdPrecedes(fxid, oldest_clog_fxid);
148}
149
150/*
151 * txid comparator for qsort/bsearch
152 */
153static int
154cmp_fxid(const void *aa, const void *bb)
155{
156 FullTransactionId a = *(const FullTransactionId *) aa;
157 FullTransactionId b = *(const FullTransactionId *) bb;
158
160 return -1;
162 return 1;
163 return 0;
164}
165
166/*
167 * Sort a snapshot's txids, so we can use bsearch() later. Also remove
168 * any duplicates.
169 *
170 * For consistency of on-disk representation, we always sort even if bsearch
171 * will not be used.
172 */
173static void
175{
176 if (snap->nxip > 1)
177 {
178 qsort(snap->xip, snap->nxip, sizeof(FullTransactionId), cmp_fxid);
179 snap->nxip = qunique(snap->xip, snap->nxip, sizeof(FullTransactionId),
180 cmp_fxid);
181 }
182}
183
184/*
185 * check fxid visibility.
186 */
187static bool
189{
191 return true;
192 else if (!FullTransactionIdPrecedes(value, snap->xmax))
193 return false;
194#ifdef USE_BSEARCH_IF_NXIP_GREATER
195 else if (snap->nxip > USE_BSEARCH_IF_NXIP_GREATER)
196 {
197 void *res;
198
199 res = bsearch(&value, snap->xip, snap->nxip, sizeof(FullTransactionId),
200 cmp_fxid);
201 /* if found, transaction is still in progress */
202 return (res) ? false : true;
203 }
204#endif
205 else
206 {
207 uint32 i;
208
209 for (i = 0; i < snap->nxip; i++)
210 {
211 if (FullTransactionIdEquals(value, snap->xip[i]))
212 return false;
213 }
214 return true;
215 }
216}
217
218/*
219 * helper functions to use StringInfo for pg_snapshot creation.
220 */
221
222static StringInfo
224{
225 pg_snapshot snap;
227
228 snap.xmin = xmin;
229 snap.xmax = xmax;
230 snap.nxip = 0;
231
234 return buf;
235}
236
237static void
239{
240 pg_snapshot *snap = (pg_snapshot *) buf->data;
241
242 /* do this before possible realloc */
243 snap->nxip++;
244
245 appendBinaryStringInfo(buf, &fxid, sizeof(fxid));
246}
247
248static pg_snapshot *
250{
251 pg_snapshot *snap = (pg_snapshot *) buf->data;
252
253 SET_VARSIZE(snap, buf->len);
254
255 /* buf is not needed anymore */
256 buf->data = NULL;
257 pfree(buf);
258
259 return snap;
260}
261
262/*
263 * parse snapshot from cstring
264 */
265static pg_snapshot *
266parse_snapshot(const char *str, Node *escontext)
267{
272 const char *str_start = str;
273 char *endp;
275
276 xmin = FullTransactionIdFromU64(strtou64(str, &endp, 10));
277 if (*endp != ':')
278 goto bad_format;
279 str = endp + 1;
280
281 xmax = FullTransactionIdFromU64(strtou64(str, &endp, 10));
282 if (*endp != ':')
283 goto bad_format;
284 str = endp + 1;
285
286 /* it should look sane */
287 if (!FullTransactionIdIsValid(xmin) ||
289 FullTransactionIdPrecedes(xmax, xmin))
290 goto bad_format;
291
292 /* allocate buffer */
293 buf = buf_init(xmin, xmax);
294
295 /* loop over values */
296 while (*str != '\0')
297 {
298 /* read next value */
299 val = FullTransactionIdFromU64(strtou64(str, &endp, 10));
300 str = endp;
301
302 /* require the input to be in order */
303 if (FullTransactionIdPrecedes(val, xmin) ||
306 goto bad_format;
307
308 /* skip duplicates */
309 if (!FullTransactionIdEquals(val, last_val))
311 last_val = val;
312
313 if (*str == ',')
314 str++;
315 else if (*str != '\0')
316 goto bad_format;
317 }
318
319 return buf_finalize(buf);
320
321bad_format:
322 ereturn(escontext, NULL,
323 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
324 errmsg("invalid input syntax for type %s: \"%s\"",
325 "pg_snapshot", str_start)));
326}
327
328/*
329 * pg_current_xact_id() returns xid8
330 *
331 * Return the current toplevel full transaction ID.
332 * If the current transaction does not have one, one is assigned.
333 */
334Datum
336{
337 /*
338 * Must prevent during recovery because if an xid is not assigned we try
339 * to assign one, which would fail. Programs already rely on this function
340 * to always return a valid current xid, so we should not change this to
341 * return NULL or similar invalid xid.
342 */
343 PreventCommandDuringRecovery("pg_current_xact_id()");
344
346}
347
348/*
349 * Same as pg_current_xact_id() but doesn't assign a new xid if there
350 * isn't one yet.
351 */
352Datum
354{
356
357 if (!FullTransactionIdIsValid(topfxid))
359
361}
362
363/*
364 * pg_current_snapshot() returns pg_snapshot
365 *
366 * Return current snapshot
367 *
368 * Note that only top-transaction XIDs are included in the snapshot.
369 */
370Datum
372{
373 pg_snapshot *snap;
374 uint32 nxip,
375 i;
378
380 if (cur == NULL)
381 elog(ERROR, "no active snapshot set");
382
383 /* allocate */
384 nxip = cur->xcnt;
385 snap = palloc(PG_SNAPSHOT_SIZE(nxip));
386
387 /*
388 * Fill. This is the current backend's active snapshot, so MyProc->xmin
389 * is <= all these XIDs. As long as that remains so, oldestXid can't
390 * advance past any of these XIDs. Hence, these XIDs remain allowable
391 * relative to next_fxid.
392 */
393 snap->xmin = FullTransactionIdFromAllowableAt(next_fxid, cur->xmin);
394 snap->xmax = FullTransactionIdFromAllowableAt(next_fxid, cur->xmax);
395 snap->nxip = nxip;
396 for (i = 0; i < nxip; i++)
397 snap->xip[i] =
398 FullTransactionIdFromAllowableAt(next_fxid, cur->xip[i]);
399
400 /*
401 * We want them guaranteed to be in ascending order. This also removes
402 * any duplicate xids. Normally, an XID can only be assigned to one
403 * backend, but when preparing a transaction for two-phase commit, there
404 * is a transient state when both the original backend and the dummy
405 * PGPROC entry reserved for the prepared transaction hold the same XID.
406 */
407 sort_snapshot(snap);
408
409 /* set size after sorting, because it may have removed duplicate xips */
410 SET_VARSIZE(snap, PG_SNAPSHOT_SIZE(snap->nxip));
411
412 PG_RETURN_POINTER(snap);
413}
414
415/*
416 * pg_snapshot_in(cstring) returns pg_snapshot
417 *
418 * input function for type pg_snapshot
419 */
420Datum
422{
423 char *str = PG_GETARG_CSTRING(0);
424 pg_snapshot *snap;
425
426 snap = parse_snapshot(str, fcinfo->context);
427
428 PG_RETURN_POINTER(snap);
429}
430
431/*
432 * pg_snapshot_out(pg_snapshot) returns cstring
433 *
434 * output function for type pg_snapshot
435 */
436Datum
438{
441 uint32 i;
442
444
449
450 for (i = 0; i < snap->nxip; i++)
451 {
452 if (i > 0)
456 }
457
459}
460
461/*
462 * pg_snapshot_recv(internal) returns pg_snapshot
463 *
464 * binary input function for type pg_snapshot
465 *
466 * format: int4 nxip, int8 xmin, int8 xmax, int8 xip
467 */
468Datum
470{
472 pg_snapshot *snap;
474 int nxip;
475 int i;
478
479 /* load and validate nxip */
480 nxip = pq_getmsgint(buf, 4);
481 if (nxip < 0 || nxip > PG_SNAPSHOT_MAX_NXIP)
482 goto bad_format;
483
486 if (!FullTransactionIdIsValid(xmin) ||
488 FullTransactionIdPrecedes(xmax, xmin))
489 goto bad_format;
490
491 snap = palloc(PG_SNAPSHOT_SIZE(nxip));
492 snap->xmin = xmin;
493 snap->xmax = xmax;
494
495 for (i = 0; i < nxip; i++)
496 {
499
500 if (FullTransactionIdPrecedes(cur, last) ||
503 goto bad_format;
504
505 /* skip duplicate xips */
506 if (FullTransactionIdEquals(cur, last))
507 {
508 i--;
509 nxip--;
510 continue;
511 }
512
513 snap->xip[i] = cur;
514 last = cur;
515 }
516 snap->nxip = nxip;
517 SET_VARSIZE(snap, PG_SNAPSHOT_SIZE(nxip));
518 PG_RETURN_POINTER(snap);
519
520bad_format:
522 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
523 errmsg("invalid external pg_snapshot data")));
524 PG_RETURN_POINTER(NULL); /* keep compiler quiet */
525}
526
527/*
528 * pg_snapshot_send(pg_snapshot) returns bytea
529 *
530 * binary output function for type pg_snapshot
531 *
532 * format: int4 nxip, u64 xmin, u64 xmax, u64 xip...
533 */
534Datum
536{
539 uint32 i;
540
542 pq_sendint32(&buf, snap->nxip);
545 for (i = 0; i < snap->nxip; i++)
548}
549
550/*
551 * pg_visible_in_snapshot(xid8, pg_snapshot) returns bool
552 *
553 * is txid visible in snapshot ?
554 */
555Datum
557{
560
562}
563
564/*
565 * pg_snapshot_xmin(pg_snapshot) returns xid8
566 *
567 * return snapshot's xmin
568 */
569Datum
571{
573
575}
576
577/*
578 * pg_snapshot_xmax(pg_snapshot) returns xid8
579 *
580 * return snapshot's xmax
581 */
582Datum
584{
586
588}
589
590/*
591 * pg_snapshot_xip(pg_snapshot) returns setof xid8
592 *
593 * return in-progress xid8s in snapshot.
594 */
595Datum
597{
598 FuncCallContext *fctx;
599 pg_snapshot *snap;
601
602 /* on first call initialize fctx and get copy of snapshot */
603 if (SRF_IS_FIRSTCALL())
604 {
606
607 fctx = SRF_FIRSTCALL_INIT();
608
609 /* make a copy of user snapshot */
611 memcpy(snap, arg, VARSIZE(arg));
612
613 fctx->user_fctx = snap;
614 }
615
616 /* return values one-by-one */
617 fctx = SRF_PERCALL_SETUP();
618 snap = fctx->user_fctx;
619 if (fctx->call_cntr < snap->nxip)
620 {
621 value = snap->xip[fctx->call_cntr];
623 }
624 else
625 {
626 SRF_RETURN_DONE(fctx);
627 }
628}
629
630/*
631 * Report the status of a recent transaction ID, or null for wrapped,
632 * truncated away or otherwise too old XIDs.
633 *
634 * The passed epoch-qualified xid is treated as a normal xid, not a
635 * multixact id.
636 *
637 * If it points to a committed subxact the result is the subxact status even
638 * though the parent xact may still be in progress or may have aborted.
639 */
640Datum
642{
643 const char *status;
645 TransactionId xid;
646
647 /*
648 * We must protect against concurrent truncation of clog entries to avoid
649 * an I/O error on SLRU lookup.
650 */
651 LWLockAcquire(XactTruncationLock, LW_SHARED);
652 if (TransactionIdInRecentPast(fxid, &xid))
653 {
655
656 /*
657 * Like when doing visibility checks on a row, check whether the
658 * transaction is still in progress before looking into the CLOG.
659 * Otherwise we would incorrectly return "committed" for a transaction
660 * that is committing and has already updated the CLOG, but hasn't
661 * removed its XID from the proc array yet. (See comment on that race
662 * condition at the top of heapam_visibility.c)
663 */
665 status = "in progress";
666 else if (TransactionIdDidCommit(xid))
667 status = "committed";
668 else
669 {
670 /* it must have aborted or crashed */
671 status = "aborted";
672 }
673 }
674 else
675 {
676 status = NULL;
677 }
678 LWLockRelease(XactTruncationLock);
679
680 if (status == NULL)
682 else
684}
int64_t int64
Definition: c.h:540
#define FLEXIBLE_ARRAY_MEMBER
Definition: c.h:475
#define UINT64_FORMAT
Definition: c.h:562
int32_t int32
Definition: c.h:539
uint64_t uint64
Definition: c.h:544
uint32_t uint32
Definition: c.h:543
uint32 TransactionId
Definition: c.h:662
struct cursor * cur
Definition: ecpg.c:29
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ereturn(context, dummy_value,...)
Definition: elog.h:278
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:150
#define PG_GETARG_VARLENA_P(n)
Definition: fmgr.h:287
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
Assert(PointerIsAligned(start, uint64))
const char * str
long val
Definition: informix.c:689
static struct @171 value
int b
Definition: isn.c:74
return false
Definition: isn.c:135
int a
Definition: isn.c:73
int i
Definition: isn.c:77
bool LWLockHeldByMe(LWLock *lock)
Definition: lwlock.c:1977
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1174
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1894
@ LW_SHARED
Definition: lwlock.h:113
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1229
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc(Size size)
Definition: mcxt.c:1365
void * arg
static char * buf
Definition: pg_test_fsync.c:72
#define qsort(a, b, c, d)
Definition: port.h:479
uint64_t Datum
Definition: postgres.h:70
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:415
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:326
int64 pq_getmsgint64(StringInfo msg)
Definition: pqformat.c:453
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:346
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:144
static void pq_sendint64(StringInfo buf, uint64 i)
Definition: pqformat.h:152
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:1402
#define MAX_BACKENDS
Definition: procnumber.h:39
static size_t qunique(void *array, size_t elements, size_t width, int(*compare)(const void *, const void *))
Definition: qunique.h:21
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:798
struct StringInfoData * StringInfo
Definition: string.h:15
StringInfo makeStringInfo(void)
Definition: stringinfo.c:72
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:281
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
void * user_fctx
Definition: funcapi.h:82
uint64 call_cntr
Definition: funcapi.h:65
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
Definition: nodes.h:135
TransactionId oldestClogXid
Definition: transam.h:253
FullTransactionId xip[FLEXIBLE_ARRAY_MEMBER]
Definition: xid8funcs.c:68
int32 __varsz
Definition: xid8funcs.c:62
FullTransactionId xmax
Definition: xid8funcs.c:66
uint32 nxip
Definition: xid8funcs.c:64
FullTransactionId xmin
Definition: xid8funcs.c:65
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:126
#define FullTransactionIdEquals(a, b)
Definition: transam.h:50
static FullTransactionId FullTransactionIdFromAllowableAt(FullTransactionId nextFullXid, TransactionId xid)
Definition: transam.h:443
#define U64FromFullTransactionId(x)
Definition: transam.h:49
static FullTransactionId FullTransactionIdFromU64(uint64 value)
Definition: transam.h:81
#define FullTransactionIdFollowsOrEquals(a, b)
Definition: transam.h:54
#define XidFromFullTransactionId(x)
Definition: transam.h:48
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
#define InvalidFullTransactionId
Definition: transam.h:56
#define FullTransactionIdPrecedes(a, b)
Definition: transam.h:51
#define FullTransactionIdIsValid(x)
Definition: transam.h:55
void PreventCommandDuringRecovery(const char *cmdname)
Definition: utility.c:443
static Size VARSIZE(const void *PTR)
Definition: varatt.h:298
static void SET_VARSIZE(void *PTR, Size len)
Definition: varatt.h:432
text * cstring_to_text(const char *s)
Definition: varlena.c:181
FullTransactionId ReadNextFullTransactionId(void)
Definition: varsup.c:288
TransamVariablesData * TransamVariables
Definition: varsup.c:34
FullTransactionId GetTopFullTransactionId(void)
Definition: xact.c:484
FullTransactionId GetTopFullTransactionIdIfAny(void)
Definition: xact.c:500
#define PG_GETARG_FULLTRANSACTIONID(X)
Definition: xid8.h:29
static Datum FullTransactionIdGetDatum(FullTransactionId X)
Definition: xid8.h:24
#define PG_RETURN_FULLTRANSACTIONID(X)
Definition: xid8.h:30
static bool TransactionIdInRecentPast(FullTransactionId fxid, TransactionId *extracted_xid)
Definition: xid8funcs.c:98
Datum pg_snapshot_send(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:535
static pg_snapshot * buf_finalize(StringInfo buf)
Definition: xid8funcs.c:249
Datum pg_current_xact_id_if_assigned(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:353
static StringInfo buf_init(FullTransactionId xmin, FullTransactionId xmax)
Definition: xid8funcs.c:223
static bool is_visible_fxid(FullTransactionId value, const pg_snapshot *snap)
Definition: xid8funcs.c:188
static int cmp_fxid(const void *aa, const void *bb)
Definition: xid8funcs.c:154
#define USE_BSEARCH_IF_NXIP_GREATER
Definition: xid8funcs.c:49
Datum pg_snapshot_out(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:437
#define PG_SNAPSHOT_SIZE(nxip)
Definition: xid8funcs.c:71
#define PG_SNAPSHOT_MAX_NXIP
Definition: xid8funcs.c:73
Datum pg_current_xact_id(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:335
static pg_snapshot * parse_snapshot(const char *str, Node *escontext)
Definition: xid8funcs.c:266
Datum pg_snapshot_recv(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:469
Datum pg_snapshot_in(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:421
Datum pg_xact_status(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:641
Datum pg_current_snapshot(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:371
static void buf_add_txid(StringInfo buf, FullTransactionId fxid)
Definition: xid8funcs.c:238
Datum pg_snapshot_xmin(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:570
Datum pg_snapshot_xip(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:596
static void sort_snapshot(pg_snapshot *snap)
Definition: xid8funcs.c:174
Datum pg_visible_in_snapshot(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:556
StaticAssertDecl(MAX_BACKENDS *2<=PG_SNAPSHOT_MAX_NXIP, "possible overflow in pg_current_snapshot()")
Datum pg_snapshot_xmax(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:583