Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * xid.c
4 : : * POSTGRES transaction identifier and command identifier datatypes.
5 : : *
6 : : * Portions Copyright (c) 1996-2026, 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
33 : 56 : xidin(PG_FUNCTION_ARGS)
34 : : {
35 : 56 : char *str = PG_GETARG_CSTRING(0);
36 : 56 : TransactionId result;
37 : :
38 : 56 : result = uint32in_subr(str, NULL, "xid", fcinfo->context);
39 : 112 : PG_RETURN_TRANSACTIONID(result);
40 : 56 : }
41 : :
42 : : Datum
43 : 26 : xidout(PG_FUNCTION_ARGS)
44 : : {
45 : 26 : TransactionId transactionId = PG_GETARG_TRANSACTIONID(0);
46 : 26 : char *result = (char *) palloc(16);
47 : :
48 : 26 : snprintf(result, 16, "%u", transactionId);
49 : 52 : PG_RETURN_CSTRING(result);
50 : 26 : }
51 : :
52 : : /*
53 : : * xidrecv - converts external binary format to xid
54 : : */
55 : : Datum
56 : 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 : 0 : }
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 : 0 : StringInfoData buf;
71 : :
72 : 0 : pq_begintypsend(&buf);
73 : 0 : pq_sendint32(&buf, arg1);
74 : 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
75 : 0 : }
76 : :
77 : : /*
78 : : * xideq - are two xids equal?
79 : : */
80 : : Datum
81 : 1113 : xideq(PG_FUNCTION_ARGS)
82 : : {
83 : 1113 : TransactionId xid1 = PG_GETARG_TRANSACTIONID(0);
84 : 1113 : TransactionId xid2 = PG_GETARG_TRANSACTIONID(1);
85 : :
86 : 2226 : PG_RETURN_BOOL(TransactionIdEquals(xid1, xid2));
87 : 1113 : }
88 : :
89 : : /*
90 : : * xidneq - are two xids different?
91 : : */
92 : : Datum
93 : 2 : xidneq(PG_FUNCTION_ARGS)
94 : : {
95 : 2 : TransactionId xid1 = PG_GETARG_TRANSACTIONID(0);
96 : 2 : TransactionId xid2 = PG_GETARG_TRANSACTIONID(1);
97 : :
98 : 4 : PG_RETURN_BOOL(!TransactionIdEquals(xid1, xid2));
99 : 2 : }
100 : :
101 : : Datum
102 : 32 : hashxid(PG_FUNCTION_ARGS)
103 : : {
104 : 32 : return hash_uint32(PG_GETARG_TRANSACTIONID(0));
105 : : }
106 : :
107 : : Datum
108 : 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
117 : 0 : xid_age(PG_FUNCTION_ARGS)
118 : : {
119 : 0 : TransactionId xid = PG_GETARG_TRANSACTIONID(0);
120 : 0 : TransactionId now = GetStableLatestTransactionId();
121 : :
122 : : /* Permanent XIDs are always infinitely old */
123 [ # # ]: 0 : if (!TransactionIdIsNormal(xid))
124 : 0 : PG_RETURN_INT32(INT_MAX);
125 : :
126 : 0 : PG_RETURN_INT32((int32) (now - xid));
127 : 0 : }
128 : :
129 : : /*
130 : : * mxid_age - compute age of a multi XID (relative to latest stable mxid)
131 : : */
132 : : Datum
133 : 0 : mxid_age(PG_FUNCTION_ARGS)
134 : : {
135 : 0 : TransactionId xid = PG_GETARG_TRANSACTIONID(0);
136 : 0 : MultiXactId now = ReadNextMultiXactId();
137 : :
138 [ # # ]: 0 : if (!MultiXactIdIsValid(xid))
139 : 0 : PG_RETURN_INT32(INT_MAX);
140 : :
141 : 0 : PG_RETURN_INT32((int32) (now - xid));
142 : 0 : }
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
152 : 742 : xidComparator(const void *arg1, const void *arg2)
153 : : {
154 : 742 : TransactionId xid1 = *(const TransactionId *) arg1;
155 : 742 : TransactionId xid2 = *(const TransactionId *) arg2;
156 : :
157 : 1484 : return pg_cmp_u32(xid1, xid2);
158 : 742 : }
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
169 : 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 : 0 : }
185 : :
186 : : Datum
187 : 263 : xid8toxid(PG_FUNCTION_ARGS)
188 : : {
189 : 263 : FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
190 : :
191 : 526 : PG_RETURN_TRANSACTIONID(XidFromFullTransactionId(fxid));
192 : 263 : }
193 : :
194 : : Datum
195 : 143 : xid8in(PG_FUNCTION_ARGS)
196 : : {
197 : 143 : char *str = PG_GETARG_CSTRING(0);
198 : 143 : uint64 result;
199 : :
200 : 143 : result = uint64in_subr(str, NULL, "xid8", fcinfo->context);
201 : 286 : PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(result));
202 : 143 : }
203 : :
204 : : Datum
205 : 121 : xid8out(PG_FUNCTION_ARGS)
206 : : {
207 : 121 : FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
208 : 121 : char *result = (char *) palloc(21);
209 : :
210 : 121 : snprintf(result, 21, UINT64_FORMAT, U64FromFullTransactionId(fxid));
211 : 242 : PG_RETURN_CSTRING(result);
212 : 121 : }
213 : :
214 : : Datum
215 : 0 : xid8recv(PG_FUNCTION_ARGS)
216 : : {
217 : 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
218 : 0 : uint64 value;
219 : :
220 : 0 : value = (uint64) pq_getmsgint64(buf);
221 : 0 : PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(value));
222 : 0 : }
223 : :
224 : : Datum
225 : 0 : xid8send(PG_FUNCTION_ARGS)
226 : : {
227 : 0 : FullTransactionId arg1 = PG_GETARG_FULLTRANSACTIONID(0);
228 : 0 : 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 : 0 : }
234 : :
235 : : Datum
236 : 2 : xid8eq(PG_FUNCTION_ARGS)
237 : : {
238 : 2 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
239 : 2 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
240 : :
241 : 4 : PG_RETURN_BOOL(FullTransactionIdEquals(fxid1, fxid2));
242 : 2 : }
243 : :
244 : : Datum
245 : 1 : xid8ne(PG_FUNCTION_ARGS)
246 : : {
247 : 1 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
248 : 1 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
249 : :
250 : 2 : PG_RETURN_BOOL(!FullTransactionIdEquals(fxid1, fxid2));
251 : 1 : }
252 : :
253 : : Datum
254 : 3 : xid8lt(PG_FUNCTION_ARGS)
255 : : {
256 : 3 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
257 : 3 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
258 : :
259 : 6 : PG_RETURN_BOOL(FullTransactionIdPrecedes(fxid1, fxid2));
260 : 3 : }
261 : :
262 : : Datum
263 : 3 : xid8gt(PG_FUNCTION_ARGS)
264 : : {
265 : 3 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
266 : 3 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
267 : :
268 : 6 : PG_RETURN_BOOL(FullTransactionIdFollows(fxid1, fxid2));
269 : 3 : }
270 : :
271 : : Datum
272 : 3 : xid8le(PG_FUNCTION_ARGS)
273 : : {
274 : 3 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
275 : 3 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
276 : :
277 : 6 : PG_RETURN_BOOL(FullTransactionIdPrecedesOrEquals(fxid1, fxid2));
278 : 3 : }
279 : :
280 : : Datum
281 : 4 : xid8ge(PG_FUNCTION_ARGS)
282 : : {
283 : 4 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
284 : 4 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
285 : :
286 : 8 : PG_RETURN_BOOL(FullTransactionIdFollowsOrEquals(fxid1, fxid2));
287 : 4 : }
288 : :
289 : : Datum
290 : 7 : xid8cmp(PG_FUNCTION_ARGS)
291 : : {
292 : 7 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
293 : 7 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
294 : :
295 [ + + ]: 7 : if (FullTransactionIdFollows(fxid1, fxid2))
296 : 1 : PG_RETURN_INT32(1);
297 [ + + ]: 6 : else if (FullTransactionIdEquals(fxid1, fxid2))
298 : 2 : PG_RETURN_INT32(0);
299 : : else
300 : 4 : PG_RETURN_INT32(-1);
301 : 7 : }
302 : :
303 : : Datum
304 : 5 : hashxid8(PG_FUNCTION_ARGS)
305 : : {
306 : 5 : return hashint8(fcinfo);
307 : : }
308 : :
309 : : Datum
310 : 0 : hashxid8extended(PG_FUNCTION_ARGS)
311 : : {
312 : 0 : return hashint8extended(fcinfo);
313 : : }
314 : :
315 : : Datum
316 : 4 : xid8_larger(PG_FUNCTION_ARGS)
317 : : {
318 : 4 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
319 : 4 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
320 : :
321 [ - + ]: 4 : if (FullTransactionIdFollows(fxid1, fxid2))
322 : 0 : PG_RETURN_FULLTRANSACTIONID(fxid1);
323 : : else
324 : 4 : PG_RETURN_FULLTRANSACTIONID(fxid2);
325 : 4 : }
326 : :
327 : : Datum
328 : 4 : xid8_smaller(PG_FUNCTION_ARGS)
329 : : {
330 : 4 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
331 : 4 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
332 : :
333 [ + - ]: 4 : if (FullTransactionIdPrecedes(fxid1, fxid2))
334 : 4 : PG_RETURN_FULLTRANSACTIONID(fxid1);
335 : : else
336 : 0 : PG_RETURN_FULLTRANSACTIONID(fxid2);
337 : 4 : }
338 : :
339 : : /*****************************************************************************
340 : : * COMMAND IDENTIFIER ROUTINES *
341 : : *****************************************************************************/
342 : :
343 : : /*
344 : : * cidin - converts CommandId to internal representation.
345 : : */
346 : : Datum
347 : 1 : cidin(PG_FUNCTION_ARGS)
348 : : {
349 : 1 : char *str = PG_GETARG_CSTRING(0);
350 : 1 : CommandId result;
351 : :
352 : 1 : result = uint32in_subr(str, NULL, "cid", fcinfo->context);
353 : 2 : PG_RETURN_COMMANDID(result);
354 : 1 : }
355 : :
356 : : /*
357 : : * cidout - converts a cid to external representation.
358 : : */
359 : : Datum
360 : 31 : cidout(PG_FUNCTION_ARGS)
361 : : {
362 : 31 : CommandId c = PG_GETARG_COMMANDID(0);
363 : 31 : char *result = (char *) palloc(16);
364 : :
365 : 31 : snprintf(result, 16, "%u", c);
366 : 62 : PG_RETURN_CSTRING(result);
367 : 31 : }
368 : :
369 : : /*
370 : : * cidrecv - converts external binary format to cid
371 : : */
372 : : Datum
373 : 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 : 0 : }
379 : :
380 : : /*
381 : : * cidsend - converts cid to binary format
382 : : */
383 : : Datum
384 : 0 : cidsend(PG_FUNCTION_ARGS)
385 : : {
386 : 0 : CommandId arg1 = PG_GETARG_COMMANDID(0);
387 : 0 : StringInfoData buf;
388 : :
389 : 0 : pq_begintypsend(&buf);
390 : 0 : pq_sendint32(&buf, arg1);
391 : 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
392 : 0 : }
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 : 0 : }
402 : :
403 : : Datum
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 : : }
|