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"
36#include "storage/lwlock.h"
37#include "storage/procarray.h"
38#include "utils/builtins.h"
39#include "utils/memutils.h"
40#include "utils/snapmgr.h"
41#include "utils/xid8.h"
42
43
44/*
45 * If defined, use bsearch() function for searching for xid8s in snapshots
46 * that have more than the specified number of values.
47 */
48#define USE_BSEARCH_IF_NXIP_GREATER 30
49
50
51/*
52 * Snapshot containing FullTransactionIds.
53 */
54typedef struct
55{
56 /*
57 * 4-byte length hdr, should not be touched directly.
58 *
59 * Explicit embedding is ok as we want always correct alignment anyway.
60 */
62
63 uint32 nxip; /* number of fxids in xip array */
66 /* in-progress fxids, xmin <= xip[i] < xmax: */
69
70#define PG_SNAPSHOT_SIZE(nxip) \
71 (offsetof(pg_snapshot, xip) + sizeof(FullTransactionId) * (nxip))
72#define PG_SNAPSHOT_MAX_NXIP \
73 ((MaxAllocSize - offsetof(pg_snapshot, xip)) / sizeof(FullTransactionId))
74
75/*
76 * Compile-time limits on the procarray (MAX_BACKENDS processes plus
77 * MAX_BACKENDS prepared transactions) guarantee nxip won't be too large.
78 */
80 "possible overflow in pg_current_snapshot()");
81
82
83/*
84 * Helper to get a TransactionId from a 64-bit xid with wraparound detection.
85 *
86 * It is an ERROR if the xid is in the future. Otherwise, returns true if
87 * the transaction is still new enough that we can determine whether it
88 * committed and false otherwise. If *extracted_xid is not NULL, it is set
89 * to the low 32 bits of the transaction ID (i.e. the actual XID, without the
90 * epoch).
91 *
92 * The caller must hold XactTruncationLock since it's dealing with arbitrary
93 * XIDs, and must continue to hold it until it's done with any clog lookups
94 * relating to those XIDs.
95 */
96static bool
98{
100 uint32 now_epoch;
101 TransactionId now_epoch_next_xid;
102 FullTransactionId now_fullxid;
103 TransactionId oldest_xid;
104 FullTransactionId oldest_fxid;
105
106 now_fullxid = ReadNextFullTransactionId();
107 now_epoch_next_xid = XidFromFullTransactionId(now_fullxid);
108 now_epoch = EpochFromFullTransactionId(now_fullxid);
109
110 if (extracted_xid != NULL)
111 *extracted_xid = xid;
112
113 if (!TransactionIdIsValid(xid))
114 return false;
115
116 /* For non-normal transaction IDs, we can ignore the epoch. */
117 if (!TransactionIdIsNormal(xid))
118 return true;
119
120 /* If the transaction ID is in the future, throw an error. */
121 if (!FullTransactionIdPrecedes(fxid, now_fullxid))
123 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
124 errmsg("transaction ID %llu is in the future",
125 (unsigned long long) U64FromFullTransactionId(fxid))));
126
127 /*
128 * TransamVariables->oldestClogXid is protected by XactTruncationLock, but
129 * we don't acquire that lock here. Instead, we require the caller to
130 * acquire it, because the caller is presumably going to look up the
131 * returned XID. If we took and released the lock within this function, a
132 * CLOG truncation could occur before the caller finished with the XID.
133 */
134 Assert(LWLockHeldByMe(XactTruncationLock));
135
136 /*
137 * If fxid is not older than TransamVariables->oldestClogXid, the relevant
138 * CLOG entry is guaranteed to still exist. Convert
139 * TransamVariables->oldestClogXid into a FullTransactionId to compare it
140 * with fxid. Determine the right epoch knowing that oldest_fxid
141 * shouldn't be more than 2^31 older than now_fullxid.
142 */
143 oldest_xid = TransamVariables->oldestClogXid;
144 Assert(TransactionIdPrecedesOrEquals(oldest_xid, now_epoch_next_xid));
145 if (oldest_xid <= now_epoch_next_xid)
146 {
147 oldest_fxid = FullTransactionIdFromEpochAndXid(now_epoch, oldest_xid);
148 }
149 else
150 {
151 Assert(now_epoch > 0);
152 oldest_fxid = FullTransactionIdFromEpochAndXid(now_epoch - 1, oldest_xid);
153 }
154 return !FullTransactionIdPrecedes(fxid, oldest_fxid);
155}
156
157/*
158 * Convert a TransactionId obtained from a snapshot held by the caller to a
159 * FullTransactionId. Use next_fxid as a reference FullTransactionId, so that
160 * we can compute the high order bits. It must have been obtained by the
161 * caller with ReadNextFullTransactionId() after the snapshot was created.
162 */
165{
166 TransactionId next_xid = XidFromFullTransactionId(next_fxid);
168
169 /* Special transaction ID. */
170 if (!TransactionIdIsNormal(xid))
172
173 /*
174 * The 64 bit result must be <= next_fxid, since next_fxid hadn't been
175 * issued yet when the snapshot was created. Every TransactionId in the
176 * snapshot must therefore be from the same epoch as next_fxid, or the
177 * epoch before. We know this because next_fxid is never allow to get
178 * more than one epoch ahead of the TransactionIds in any snapshot.
179 */
180 if (xid > next_xid)
181 epoch--;
182
184}
185
186/*
187 * txid comparator for qsort/bsearch
188 */
189static int
190cmp_fxid(const void *aa, const void *bb)
191{
192 FullTransactionId a = *(const FullTransactionId *) aa;
193 FullTransactionId b = *(const FullTransactionId *) bb;
194
196 return -1;
198 return 1;
199 return 0;
200}
201
202/*
203 * Sort a snapshot's txids, so we can use bsearch() later. Also remove
204 * any duplicates.
205 *
206 * For consistency of on-disk representation, we always sort even if bsearch
207 * will not be used.
208 */
209static void
211{
212 if (snap->nxip > 1)
213 {
214 qsort(snap->xip, snap->nxip, sizeof(FullTransactionId), cmp_fxid);
215 snap->nxip = qunique(snap->xip, snap->nxip, sizeof(FullTransactionId),
216 cmp_fxid);
217 }
218}
219
220/*
221 * check fxid visibility.
222 */
223static bool
225{
227 return true;
228 else if (!FullTransactionIdPrecedes(value, snap->xmax))
229 return false;
230#ifdef USE_BSEARCH_IF_NXIP_GREATER
231 else if (snap->nxip > USE_BSEARCH_IF_NXIP_GREATER)
232 {
233 void *res;
234
235 res = bsearch(&value, snap->xip, snap->nxip, sizeof(FullTransactionId),
236 cmp_fxid);
237 /* if found, transaction is still in progress */
238 return (res) ? false : true;
239 }
240#endif
241 else
242 {
243 uint32 i;
244
245 for (i = 0; i < snap->nxip; i++)
246 {
247 if (FullTransactionIdEquals(value, snap->xip[i]))
248 return false;
249 }
250 return true;
251 }
252}
253
254/*
255 * helper functions to use StringInfo for pg_snapshot creation.
256 */
257
258static StringInfo
260{
261 pg_snapshot snap;
263
264 snap.xmin = xmin;
265 snap.xmax = xmax;
266 snap.nxip = 0;
267
270 return buf;
271}
272
273static void
275{
276 pg_snapshot *snap = (pg_snapshot *) buf->data;
277
278 /* do this before possible realloc */
279 snap->nxip++;
280
281 appendBinaryStringInfo(buf, &fxid, sizeof(fxid));
282}
283
284static pg_snapshot *
286{
287 pg_snapshot *snap = (pg_snapshot *) buf->data;
288
289 SET_VARSIZE(snap, buf->len);
290
291 /* buf is not needed anymore */
292 buf->data = NULL;
293 pfree(buf);
294
295 return snap;
296}
297
298/*
299 * parse snapshot from cstring
300 */
301static pg_snapshot *
302parse_snapshot(const char *str, Node *escontext)
303{
308 const char *str_start = str;
309 char *endp;
311
312 xmin = FullTransactionIdFromU64(strtou64(str, &endp, 10));
313 if (*endp != ':')
314 goto bad_format;
315 str = endp + 1;
316
317 xmax = FullTransactionIdFromU64(strtou64(str, &endp, 10));
318 if (*endp != ':')
319 goto bad_format;
320 str = endp + 1;
321
322 /* it should look sane */
323 if (!FullTransactionIdIsValid(xmin) ||
325 FullTransactionIdPrecedes(xmax, xmin))
326 goto bad_format;
327
328 /* allocate buffer */
329 buf = buf_init(xmin, xmax);
330
331 /* loop over values */
332 while (*str != '\0')
333 {
334 /* read next value */
335 val = FullTransactionIdFromU64(strtou64(str, &endp, 10));
336 str = endp;
337
338 /* require the input to be in order */
339 if (FullTransactionIdPrecedes(val, xmin) ||
342 goto bad_format;
343
344 /* skip duplicates */
345 if (!FullTransactionIdEquals(val, last_val))
347 last_val = val;
348
349 if (*str == ',')
350 str++;
351 else if (*str != '\0')
352 goto bad_format;
353 }
354
355 return buf_finalize(buf);
356
357bad_format:
358 ereturn(escontext, NULL,
359 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
360 errmsg("invalid input syntax for type %s: \"%s\"",
361 "pg_snapshot", str_start)));
362}
363
364/*
365 * pg_current_xact_id() returns xid8
366 *
367 * Return the current toplevel full transaction ID.
368 * If the current transaction does not have one, one is assigned.
369 */
370Datum
372{
373 /*
374 * Must prevent during recovery because if an xid is not assigned we try
375 * to assign one, which would fail. Programs already rely on this function
376 * to always return a valid current xid, so we should not change this to
377 * return NULL or similar invalid xid.
378 */
379 PreventCommandDuringRecovery("pg_current_xact_id()");
380
382}
383
384/*
385 * Same as pg_current_xact_id() but doesn't assign a new xid if there
386 * isn't one yet.
387 */
388Datum
390{
392
393 if (!FullTransactionIdIsValid(topfxid))
395
397}
398
399/*
400 * pg_current_snapshot() returns pg_snapshot
401 *
402 * Return current snapshot
403 *
404 * Note that only top-transaction XIDs are included in the snapshot.
405 */
406Datum
408{
409 pg_snapshot *snap;
410 uint32 nxip,
411 i;
414
416 if (cur == NULL)
417 elog(ERROR, "no active snapshot set");
418
419 /* allocate */
420 nxip = cur->xcnt;
421 snap = palloc(PG_SNAPSHOT_SIZE(nxip));
422
423 /* fill */
424 snap->xmin = widen_snapshot_xid(cur->xmin, next_fxid);
425 snap->xmax = widen_snapshot_xid(cur->xmax, next_fxid);
426 snap->nxip = nxip;
427 for (i = 0; i < nxip; i++)
428 snap->xip[i] = widen_snapshot_xid(cur->xip[i], next_fxid);
429
430 /*
431 * We want them guaranteed to be in ascending order. This also removes
432 * any duplicate xids. Normally, an XID can only be assigned to one
433 * backend, but when preparing a transaction for two-phase commit, there
434 * is a transient state when both the original backend and the dummy
435 * PGPROC entry reserved for the prepared transaction hold the same XID.
436 */
437 sort_snapshot(snap);
438
439 /* set size after sorting, because it may have removed duplicate xips */
440 SET_VARSIZE(snap, PG_SNAPSHOT_SIZE(snap->nxip));
441
442 PG_RETURN_POINTER(snap);
443}
444
445/*
446 * pg_snapshot_in(cstring) returns pg_snapshot
447 *
448 * input function for type pg_snapshot
449 */
450Datum
452{
453 char *str = PG_GETARG_CSTRING(0);
454 pg_snapshot *snap;
455
456 snap = parse_snapshot(str, fcinfo->context);
457
458 PG_RETURN_POINTER(snap);
459}
460
461/*
462 * pg_snapshot_out(pg_snapshot) returns cstring
463 *
464 * output function for type pg_snapshot
465 */
466Datum
468{
471 uint32 i;
472
474
479
480 for (i = 0; i < snap->nxip; i++)
481 {
482 if (i > 0)
486 }
487
489}
490
491/*
492 * pg_snapshot_recv(internal) returns pg_snapshot
493 *
494 * binary input function for type pg_snapshot
495 *
496 * format: int4 nxip, int8 xmin, int8 xmax, int8 xip
497 */
498Datum
500{
502 pg_snapshot *snap;
504 int nxip;
505 int i;
508
509 /* load and validate nxip */
510 nxip = pq_getmsgint(buf, 4);
511 if (nxip < 0 || nxip > PG_SNAPSHOT_MAX_NXIP)
512 goto bad_format;
513
516 if (!FullTransactionIdIsValid(xmin) ||
518 FullTransactionIdPrecedes(xmax, xmin))
519 goto bad_format;
520
521 snap = palloc(PG_SNAPSHOT_SIZE(nxip));
522 snap->xmin = xmin;
523 snap->xmax = xmax;
524
525 for (i = 0; i < nxip; i++)
526 {
529
530 if (FullTransactionIdPrecedes(cur, last) ||
533 goto bad_format;
534
535 /* skip duplicate xips */
536 if (FullTransactionIdEquals(cur, last))
537 {
538 i--;
539 nxip--;
540 continue;
541 }
542
543 snap->xip[i] = cur;
544 last = cur;
545 }
546 snap->nxip = nxip;
547 SET_VARSIZE(snap, PG_SNAPSHOT_SIZE(nxip));
548 PG_RETURN_POINTER(snap);
549
550bad_format:
552 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
553 errmsg("invalid external pg_snapshot data")));
554 PG_RETURN_POINTER(NULL); /* keep compiler quiet */
555}
556
557/*
558 * pg_snapshot_send(pg_snapshot) returns bytea
559 *
560 * binary output function for type pg_snapshot
561 *
562 * format: int4 nxip, u64 xmin, u64 xmax, u64 xip...
563 */
564Datum
566{
569 uint32 i;
570
572 pq_sendint32(&buf, snap->nxip);
575 for (i = 0; i < snap->nxip; i++)
578}
579
580/*
581 * pg_visible_in_snapshot(xid8, pg_snapshot) returns bool
582 *
583 * is txid visible in snapshot ?
584 */
585Datum
587{
590
592}
593
594/*
595 * pg_snapshot_xmin(pg_snapshot) returns xid8
596 *
597 * return snapshot's xmin
598 */
599Datum
601{
603
605}
606
607/*
608 * pg_snapshot_xmax(pg_snapshot) returns xid8
609 *
610 * return snapshot's xmax
611 */
612Datum
614{
616
618}
619
620/*
621 * pg_snapshot_xip(pg_snapshot) returns setof xid8
622 *
623 * return in-progress xid8s in snapshot.
624 */
625Datum
627{
628 FuncCallContext *fctx;
629 pg_snapshot *snap;
631
632 /* on first call initialize fctx and get copy of snapshot */
633 if (SRF_IS_FIRSTCALL())
634 {
636
637 fctx = SRF_FIRSTCALL_INIT();
638
639 /* make a copy of user snapshot */
641 memcpy(snap, arg, VARSIZE(arg));
642
643 fctx->user_fctx = snap;
644 }
645
646 /* return values one-by-one */
647 fctx = SRF_PERCALL_SETUP();
648 snap = fctx->user_fctx;
649 if (fctx->call_cntr < snap->nxip)
650 {
651 value = snap->xip[fctx->call_cntr];
653 }
654 else
655 {
656 SRF_RETURN_DONE(fctx);
657 }
658}
659
660/*
661 * Report the status of a recent transaction ID, or null for wrapped,
662 * truncated away or otherwise too old XIDs.
663 *
664 * The passed epoch-qualified xid is treated as a normal xid, not a
665 * multixact id.
666 *
667 * If it points to a committed subxact the result is the subxact status even
668 * though the parent xact may still be in progress or may have aborted.
669 */
670Datum
672{
673 const char *status;
675 TransactionId xid;
676
677 /*
678 * We must protect against concurrent truncation of clog entries to avoid
679 * an I/O error on SLRU lookup.
680 */
681 LWLockAcquire(XactTruncationLock, LW_SHARED);
682 if (TransactionIdInRecentPast(fxid, &xid))
683 {
685
686 /*
687 * Like when doing visibility checks on a row, check whether the
688 * transaction is still in progress before looking into the CLOG.
689 * Otherwise we would incorrectly return "committed" for a transaction
690 * that is committing and has already updated the CLOG, but hasn't
691 * removed its XID from the proc array yet. (See comment on that race
692 * condition at the top of heapam_visibility.c)
693 */
695 status = "in progress";
696 else if (TransactionIdDidCommit(xid))
697 status = "committed";
698 else
699 {
700 /* it must have aborted or crashed */
701 status = "aborted";
702 }
703 }
704 else
705 {
706 status = NULL;
707 }
708 LWLockRelease(XactTruncationLock);
709
710 if (status == NULL)
712 else
714}
#define Assert(condition)
Definition: c.h:815
int64_t int64
Definition: c.h:485
#define FLEXIBLE_ARRAY_MEMBER
Definition: c.h:420
#define UINT64_FORMAT
Definition: c.h:507
int32_t int32
Definition: c.h:484
uint64_t uint64
Definition: c.h:489
uint32_t uint32
Definition: c.h:488
uint32 TransactionId
Definition: c.h:609
struct cursor * cur
Definition: ecpg.c:29
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ereturn(context, dummy_value,...)
Definition: elog.h:277
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
#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
const char * str
static struct @162 value
long val
Definition: informix.c:689
int b
Definition: isn.c:69
return false
Definition: isn.c:130
int a
Definition: isn.c:68
int i
Definition: isn.c:72
bool LWLockHeldByMe(LWLock *lock)
Definition: lwlock.c:1893
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ LW_SHARED
Definition: lwlock.h:115
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
void * arg
static char * buf
Definition: pg_test_fsync.c:72
#define qsort(a, b, c, d)
Definition: port.h:474
uintptr_t Datum
Definition: postgres.h:69
#define MAX_BACKENDS
Definition: postmaster.h:138
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
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:728
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
StringInfoData * StringInfo
Definition: stringinfo.h:54
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:129
TransactionId oldestClogXid
Definition: transam.h:253
FullTransactionId xip[FLEXIBLE_ARRAY_MEMBER]
Definition: xid8funcs.c:67
int32 __varsz
Definition: xid8funcs.c:61
FullTransactionId xmax
Definition: xid8funcs.c:65
uint32 nxip
Definition: xid8funcs.c:63
FullTransactionId xmin
Definition: xid8funcs.c:64
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:126
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:299
#define FullTransactionIdEquals(a, b)
Definition: transam.h:50
#define EpochFromFullTransactionId(x)
Definition: transam.h:47
#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
static FullTransactionId FullTransactionIdFromEpochAndXid(uint32 epoch, TransactionId xid)
Definition: transam.h:71
#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:441
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305
#define VARSIZE(PTR)
Definition: varatt.h:279
text * cstring_to_text(const char *s)
Definition: varlena.c:184
FullTransactionId ReadNextFullTransactionId(void)
Definition: varsup.c:288
TransamVariablesData * TransamVariables
Definition: varsup.c:34
static const unsigned __int64 epoch
FullTransactionId GetTopFullTransactionId(void)
Definition: xact.c:482
FullTransactionId GetTopFullTransactionIdIfAny(void)
Definition: xact.c:498
#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:97
Datum pg_snapshot_send(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:565
static pg_snapshot * buf_finalize(StringInfo buf)
Definition: xid8funcs.c:285
Datum pg_current_xact_id_if_assigned(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:389
static StringInfo buf_init(FullTransactionId xmin, FullTransactionId xmax)
Definition: xid8funcs.c:259
static bool is_visible_fxid(FullTransactionId value, const pg_snapshot *snap)
Definition: xid8funcs.c:224
static int cmp_fxid(const void *aa, const void *bb)
Definition: xid8funcs.c:190
#define USE_BSEARCH_IF_NXIP_GREATER
Definition: xid8funcs.c:48
Datum pg_snapshot_out(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:467
#define PG_SNAPSHOT_SIZE(nxip)
Definition: xid8funcs.c:70
#define PG_SNAPSHOT_MAX_NXIP
Definition: xid8funcs.c:72
Datum pg_current_xact_id(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:371
static pg_snapshot * parse_snapshot(const char *str, Node *escontext)
Definition: xid8funcs.c:302
Datum pg_snapshot_recv(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:499
Datum pg_snapshot_in(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:451
Datum pg_xact_status(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:671
Datum pg_current_snapshot(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:407
static void buf_add_txid(StringInfo buf, FullTransactionId fxid)
Definition: xid8funcs.c:274
Datum pg_snapshot_xmin(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:600
Datum pg_snapshot_xip(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:626
static void sort_snapshot(pg_snapshot *snap)
Definition: xid8funcs.c:210
Datum pg_visible_in_snapshot(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:586
StaticAssertDecl(MAX_BACKENDS *2<=PG_SNAPSHOT_MAX_NXIP, "possible overflow in pg_current_snapshot()")
static FullTransactionId widen_snapshot_xid(TransactionId xid, FullTransactionId next_fxid)
Definition: xid8funcs.c:164
Datum pg_snapshot_xmax(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:613