Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * xid.c
4 : * POSTGRES transaction identifier and command identifier datatypes.
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/utils/adt/xid.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
17 : #include <limits.h>
18 :
19 : #include "access/multixact.h"
20 : #include "access/transam.h"
21 : #include "access/xact.h"
22 : #include "libpq/pqformat.h"
23 : #include "utils/builtins.h"
24 : #include "utils/xid8.h"
25 :
26 : #define PG_GETARG_COMMANDID(n) DatumGetCommandId(PG_GETARG_DATUM(n))
27 : #define PG_RETURN_COMMANDID(x) return CommandIdGetDatum(x)
28 :
29 :
30 : Datum
7272 tgl 31 CBC 4844 : xidin(PG_FUNCTION_ARGS)
32 : {
33 4844 : char *str = PG_GETARG_CSTRING(0);
34 : TransactionId result;
35 :
103 tgl 36 GNC 4844 : result = uint32in_subr(str, NULL, "xid", fcinfo->context);
37 4838 : PG_RETURN_TRANSACTIONID(result);
7272 tgl 38 ECB : }
39 :
40 : Datum
7272 tgl 41 GIC 77402 : xidout(PG_FUNCTION_ARGS)
42 : {
7272 tgl 43 CBC 77402 : TransactionId transactionId = PG_GETARG_TRANSACTIONID(0);
2364 tgl 44 GIC 77402 : char *result = (char *) palloc(16);
7272 tgl 45 ECB :
2364 tgl 46 CBC 77402 : snprintf(result, 16, "%lu", (unsigned long) transactionId);
2364 tgl 47 GIC 77402 : PG_RETURN_CSTRING(result);
7272 tgl 48 ECB : }
49 :
50 : /*
51 : * xidrecv - converts external binary format to xid
52 : */
53 : Datum
7272 tgl 54 UIC 0 : xidrecv(PG_FUNCTION_ARGS)
55 : {
7272 tgl 56 UBC 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
57 :
58 0 : PG_RETURN_TRANSACTIONID((TransactionId) pq_getmsgint(buf, sizeof(TransactionId)));
59 : }
7272 tgl 60 EUB :
61 : /*
62 : * xidsend - converts xid to binary format
63 : */
64 : Datum
7272 tgl 65 UIC 0 : xidsend(PG_FUNCTION_ARGS)
66 : {
7272 tgl 67 UBC 0 : TransactionId arg1 = PG_GETARG_TRANSACTIONID(0);
68 : StringInfoData buf;
7272 tgl 69 EUB :
7272 tgl 70 UIC 0 : pq_begintypsend(&buf);
2006 andres 71 0 : pq_sendint32(&buf, arg1);
7272 tgl 72 UBC 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
7272 tgl 73 EUB : }
74 :
75 : /*
76 : * xideq - are two xids equal?
77 : */
78 : Datum
7272 tgl 79 GIC 371283 : xideq(PG_FUNCTION_ARGS)
80 : {
7272 tgl 81 CBC 371283 : TransactionId xid1 = PG_GETARG_TRANSACTIONID(0);
7272 tgl 82 GIC 371283 : TransactionId xid2 = PG_GETARG_TRANSACTIONID(1);
7272 tgl 83 ECB :
7272 tgl 84 CBC 371283 : PG_RETURN_BOOL(TransactionIdEquals(xid1, xid2));
85 : }
7272 tgl 86 ECB :
87 : /*
88 : * xidneq - are two xids different?
89 : */
90 : Datum
2710 tgl 91 GIC 432 : xidneq(PG_FUNCTION_ARGS)
92 : {
2710 tgl 93 CBC 432 : TransactionId xid1 = PG_GETARG_TRANSACTIONID(0);
2710 tgl 94 GIC 432 : TransactionId xid2 = PG_GETARG_TRANSACTIONID(1);
2710 tgl 95 ECB :
2710 tgl 96 CBC 432 : PG_RETURN_BOOL(!TransactionIdEquals(xid1, xid2));
97 : }
2710 tgl 98 ECB :
99 : /*
100 : * xid_age - compute age of an XID (relative to latest stable xid)
101 : */
102 : Datum
7272 tgl 103 GIC 113 : xid_age(PG_FUNCTION_ARGS)
104 : {
7272 tgl 105 CBC 113 : TransactionId xid = PG_GETARG_TRANSACTIONID(0);
3985 simon 106 GIC 113 : TransactionId now = GetStableLatestTransactionId();
7272 tgl 107 ECB :
108 : /* Permanent XIDs are always infinitely old */
7272 tgl 109 GIC 113 : if (!TransactionIdIsNormal(xid))
7272 tgl 110 UIC 0 : PG_RETURN_INT32(INT_MAX);
7272 tgl 111 ECB :
7272 tgl 112 GBC 113 : PG_RETURN_INT32((int32) (now - xid));
113 : }
7272 tgl 114 ECB :
115 : /*
116 : * mxid_age - compute age of a multi XID (relative to latest stable mxid)
117 : */
118 : Datum
3133 bruce 119 GIC 1 : mxid_age(PG_FUNCTION_ARGS)
120 : {
3133 bruce 121 CBC 1 : TransactionId xid = PG_GETARG_TRANSACTIONID(0);
3133 bruce 122 GIC 1 : MultiXactId now = ReadNextMultiXactId();
3133 bruce 123 ECB :
3133 bruce 124 CBC 1 : if (!MultiXactIdIsValid(xid))
3133 bruce 125 UIC 0 : PG_RETURN_INT32(INT_MAX);
3133 bruce 126 ECB :
3133 bruce 127 GBC 1 : PG_RETURN_INT32((int32) (now - xid));
128 : }
3133 bruce 129 ECB :
130 : /*
131 : * xidComparator
132 : * qsort comparison function for XIDs
133 : *
134 : * We can't use wraparound comparison for XIDs because that does not respect
135 : * the triangle inequality! Any old sort order will do.
136 : */
137 : int
4859 simon 138 GIC 36048 : xidComparator(const void *arg1, const void *arg2)
139 : {
4859 simon 140 CBC 36048 : TransactionId xid1 = *(const TransactionId *) arg1;
4859 simon 141 GIC 36048 : TransactionId xid2 = *(const TransactionId *) arg2;
4859 simon 142 ECB :
4859 simon 143 CBC 36048 : if (xid1 > xid2)
4859 simon 144 GIC 6439 : return 1;
4859 simon 145 CBC 29609 : if (xid1 < xid2)
146 24910 : return -1;
147 4699 : return 0;
4859 simon 148 ECB : }
7272 tgl 149 :
150 : /*
151 : * xidLogicalComparator
152 : * qsort comparison function for XIDs
153 : *
154 : * This is used to compare only XIDs from the same epoch (e.g. for backends
155 : * running at the same time). So there must be only normal XIDs, so there's
156 : * no issue with triangle inequality.
157 : */
158 : int
437 tomas.vondra 159 UIC 0 : xidLogicalComparator(const void *arg1, const void *arg2)
160 : {
437 tomas.vondra 161 UBC 0 : TransactionId xid1 = *(const TransactionId *) arg1;
437 tomas.vondra 162 UIC 0 : TransactionId xid2 = *(const TransactionId *) arg2;
437 tomas.vondra 163 EUB :
437 tomas.vondra 164 UBC 0 : Assert(TransactionIdIsNormal(xid1));
437 tomas.vondra 165 UIC 0 : Assert(TransactionIdIsNormal(xid2));
437 tomas.vondra 166 EUB :
437 tomas.vondra 167 UBC 0 : if (TransactionIdPrecedes(xid1, xid2))
437 tomas.vondra 168 UIC 0 : return -1;
437 tomas.vondra 169 EUB :
437 tomas.vondra 170 UBC 0 : if (TransactionIdPrecedes(xid2, xid1))
437 tomas.vondra 171 UIC 0 : return 1;
437 tomas.vondra 172 EUB :
437 tomas.vondra 173 UBC 0 : return 0;
174 : }
437 tomas.vondra 175 EUB :
176 : Datum
1097 tmunro 177 GIC 802 : xid8toxid(PG_FUNCTION_ARGS)
178 : {
1097 tmunro 179 CBC 802 : FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
180 :
181 802 : PG_RETURN_TRANSACTIONID(XidFromFullTransactionId(fxid));
182 : }
1097 tmunro 183 ECB :
184 : Datum
1097 tmunro 185 GIC 433 : xid8in(PG_FUNCTION_ARGS)
186 : {
1097 tmunro 187 CBC 433 : char *str = PG_GETARG_CSTRING(0);
188 : uint64 result;
189 :
103 tgl 190 GNC 433 : result = uint64in_subr(str, NULL, "xid8", fcinfo->context);
191 427 : PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(result));
192 : }
193 :
1097 tmunro 194 ECB : Datum
1097 tmunro 195 CBC 369 : xid8out(PG_FUNCTION_ARGS)
196 : {
1097 tmunro 197 GIC 369 : FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
198 369 : char *result = (char *) palloc(21);
1097 tmunro 199 ECB :
1097 tmunro 200 GIC 369 : snprintf(result, 21, UINT64_FORMAT, U64FromFullTransactionId(fxid));
1097 tmunro 201 CBC 369 : PG_RETURN_CSTRING(result);
1097 tmunro 202 ECB : }
203 :
204 : Datum
1097 tmunro 205 LBC 0 : xid8recv(PG_FUNCTION_ARGS)
206 : {
1097 tmunro 207 UIC 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
208 : uint64 value;
1097 tmunro 209 EUB :
1097 tmunro 210 UIC 0 : value = (uint64) pq_getmsgint64(buf);
1097 tmunro 211 UBC 0 : PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(value));
212 : }
213 :
1097 tmunro 214 EUB : Datum
1097 tmunro 215 UBC 0 : xid8send(PG_FUNCTION_ARGS)
216 : {
1097 tmunro 217 UIC 0 : FullTransactionId arg1 = PG_GETARG_FULLTRANSACTIONID(0);
218 : StringInfoData buf;
1097 tmunro 219 EUB :
1097 tmunro 220 UIC 0 : pq_begintypsend(&buf);
1097 tmunro 221 UBC 0 : pq_sendint64(&buf, (uint64) U64FromFullTransactionId(arg1));
1097 tmunro 222 UIC 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
223 : }
1097 tmunro 224 EUB :
225 : Datum
1097 tmunro 226 GBC 9 : xid8eq(PG_FUNCTION_ARGS)
227 : {
1097 tmunro 228 GIC 9 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
229 9 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
1097 tmunro 230 ECB :
1097 tmunro 231 GIC 9 : PG_RETURN_BOOL(FullTransactionIdEquals(fxid1, fxid2));
1097 tmunro 232 ECB : }
233 :
234 : Datum
1097 tmunro 235 CBC 4 : xid8ne(PG_FUNCTION_ARGS)
236 : {
1097 tmunro 237 GIC 4 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
238 4 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
1097 tmunro 239 ECB :
1097 tmunro 240 GIC 4 : PG_RETURN_BOOL(!FullTransactionIdEquals(fxid1, fxid2));
1097 tmunro 241 ECB : }
242 :
243 : Datum
1097 tmunro 244 CBC 9 : xid8lt(PG_FUNCTION_ARGS)
245 : {
1097 tmunro 246 GIC 9 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
247 9 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
1097 tmunro 248 ECB :
1097 tmunro 249 GIC 9 : PG_RETURN_BOOL(FullTransactionIdPrecedes(fxid1, fxid2));
1097 tmunro 250 ECB : }
251 :
252 : Datum
1097 tmunro 253 CBC 9 : xid8gt(PG_FUNCTION_ARGS)
254 : {
1097 tmunro 255 GIC 9 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
256 9 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
1097 tmunro 257 ECB :
1097 tmunro 258 GIC 9 : PG_RETURN_BOOL(FullTransactionIdFollows(fxid1, fxid2));
1097 tmunro 259 ECB : }
260 :
261 : Datum
1097 tmunro 262 CBC 9 : xid8le(PG_FUNCTION_ARGS)
263 : {
1097 tmunro 264 GIC 9 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
265 9 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
1097 tmunro 266 ECB :
1097 tmunro 267 GIC 9 : PG_RETURN_BOOL(FullTransactionIdPrecedesOrEquals(fxid1, fxid2));
1097 tmunro 268 ECB : }
269 :
270 : Datum
1097 tmunro 271 CBC 12 : xid8ge(PG_FUNCTION_ARGS)
272 : {
1097 tmunro 273 GIC 12 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
274 12 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
1097 tmunro 275 ECB :
1097 tmunro 276 GIC 12 : PG_RETURN_BOOL(FullTransactionIdFollowsOrEquals(fxid1, fxid2));
1097 tmunro 277 ECB : }
278 :
279 : Datum
1097 tmunro 280 CBC 21 : xid8cmp(PG_FUNCTION_ARGS)
281 : {
1097 tmunro 282 GIC 21 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
283 21 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
1097 tmunro 284 ECB :
1097 tmunro 285 GIC 21 : if (FullTransactionIdFollows(fxid1, fxid2))
1097 tmunro 286 CBC 3 : PG_RETURN_INT32(1);
287 18 : else if (FullTransactionIdEquals(fxid1, fxid2))
1097 tmunro 288 GIC 6 : PG_RETURN_INT32(0);
1097 tmunro 289 ECB : else
1097 tmunro 290 CBC 12 : PG_RETURN_INT32(-1);
1097 tmunro 291 ECB : }
292 :
293 : Datum
423 fujii 294 CBC 12 : xid8_larger(PG_FUNCTION_ARGS)
295 : {
423 fujii 296 GIC 12 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
297 12 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
423 fujii 298 ECB :
423 fujii 299 GIC 12 : if (FullTransactionIdFollows(fxid1, fxid2))
423 fujii 300 LBC 0 : PG_RETURN_FULLTRANSACTIONID(fxid1);
423 fujii 301 ECB : else
423 fujii 302 GIC 12 : PG_RETURN_FULLTRANSACTIONID(fxid2);
423 fujii 303 ECB : }
423 fujii 304 EUB :
305 : Datum
423 fujii 306 CBC 12 : xid8_smaller(PG_FUNCTION_ARGS)
307 : {
423 fujii 308 GIC 12 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
309 12 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
423 fujii 310 ECB :
423 fujii 311 GIC 12 : if (FullTransactionIdPrecedes(fxid1, fxid2))
423 fujii 312 CBC 12 : PG_RETURN_FULLTRANSACTIONID(fxid1);
423 fujii 313 ECB : else
423 fujii 314 UIC 0 : PG_RETURN_FULLTRANSACTIONID(fxid2);
423 fujii 315 ECB : }
316 :
317 : /*****************************************************************************
7272 tgl 318 EUB : * COMMAND IDENTIFIER ROUTINES *
319 : *****************************************************************************/
320 :
321 : /*
322 : * cidin - converts CommandId to internal representation.
323 : */
324 : Datum
7272 tgl 325 GIC 3 : cidin(PG_FUNCTION_ARGS)
326 : {
2364 327 3 : char *str = PG_GETARG_CSTRING(0);
328 : CommandId result;
329 :
103 tgl 330 GNC 3 : result = uint32in_subr(str, NULL, "cid", fcinfo->context);
331 3 : PG_RETURN_COMMANDID(result);
332 : }
7272 tgl 333 ECB :
334 : /*
335 : * cidout - converts a cid to external representation.
336 : */
337 : Datum
7272 tgl 338 GIC 97 : cidout(PG_FUNCTION_ARGS)
339 : {
340 97 : CommandId c = PG_GETARG_COMMANDID(0);
341 97 : char *result = (char *) palloc(16);
342 :
2364 343 97 : snprintf(result, 16, "%lu", (unsigned long) c);
7272 tgl 344 CBC 97 : PG_RETURN_CSTRING(result);
345 : }
7272 tgl 346 ECB :
347 : /*
348 : * cidrecv - converts external binary format to cid
349 : */
350 : Datum
7272 tgl 351 UIC 0 : cidrecv(PG_FUNCTION_ARGS)
352 : {
353 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
354 :
355 0 : PG_RETURN_COMMANDID((CommandId) pq_getmsgint(buf, sizeof(CommandId)));
356 : }
7272 tgl 357 EUB :
358 : /*
359 : * cidsend - converts cid to binary format
360 : */
361 : Datum
7272 tgl 362 UIC 0 : cidsend(PG_FUNCTION_ARGS)
363 : {
7188 bruce 364 0 : CommandId arg1 = PG_GETARG_COMMANDID(0);
365 : StringInfoData buf;
366 :
7272 tgl 367 0 : pq_begintypsend(&buf);
2006 andres 368 UBC 0 : pq_sendint32(&buf, arg1);
7272 tgl 369 UIC 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
7272 tgl 370 EUB : }
371 :
372 : Datum
7272 tgl 373 UBC 0 : cideq(PG_FUNCTION_ARGS)
7272 tgl 374 EUB : {
7272 tgl 375 UBC 0 : CommandId arg1 = PG_GETARG_COMMANDID(0);
7272 tgl 376 UIC 0 : CommandId arg2 = PG_GETARG_COMMANDID(1);
377 :
378 0 : PG_RETURN_BOOL(arg1 == arg2);
7272 tgl 379 EUB : }
|