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