Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * xid.c
4 : * POSTGRES transaction identifier and command identifier datatypes.
5 : *
6 : * Portions Copyright (c) 1996-2024, 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 4880 : xidin(PG_FUNCTION_ARGS)
34 : {
35 4880 : char *str = PG_GETARG_CSTRING(0);
36 : TransactionId result;
37 :
38 4880 : result = uint32in_subr(str, NULL, "xid", fcinfo->context);
39 4868 : PG_RETURN_TRANSACTIONID(result);
40 : }
41 :
42 : Datum
43 222606 : xidout(PG_FUNCTION_ARGS)
44 : {
45 222606 : TransactionId transactionId = PG_GETARG_TRANSACTIONID(0);
46 222606 : char *result = (char *) palloc(16);
47 :
48 222606 : snprintf(result, 16, "%lu", (unsigned long) transactionId);
49 222606 : PG_RETURN_CSTRING(result);
50 : }
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 : }
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);
73 0 : pq_sendint32(&buf, arg1);
74 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
75 : }
76 :
77 : /*
78 : * xideq - are two xids equal?
79 : */
80 : Datum
81 319870 : xideq(PG_FUNCTION_ARGS)
82 : {
83 319870 : TransactionId xid1 = PG_GETARG_TRANSACTIONID(0);
84 319870 : TransactionId xid2 = PG_GETARG_TRANSACTIONID(1);
85 :
86 319870 : PG_RETURN_BOOL(TransactionIdEquals(xid1, xid2));
87 : }
88 :
89 : /*
90 : * xidneq - are two xids different?
91 : */
92 : Datum
93 870 : xidneq(PG_FUNCTION_ARGS)
94 : {
95 870 : TransactionId xid1 = PG_GETARG_TRANSACTIONID(0);
96 870 : TransactionId xid2 = PG_GETARG_TRANSACTIONID(1);
97 :
98 870 : PG_RETURN_BOOL(!TransactionIdEquals(xid1, xid2));
99 : }
100 :
101 : Datum
102 192 : hashxid(PG_FUNCTION_ARGS)
103 : {
104 192 : 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 332 : xid_age(PG_FUNCTION_ARGS)
118 : {
119 332 : TransactionId xid = PG_GETARG_TRANSACTIONID(0);
120 332 : TransactionId now = GetStableLatestTransactionId();
121 :
122 : /* Permanent XIDs are always infinitely old */
123 332 : if (!TransactionIdIsNormal(xid))
124 0 : PG_RETURN_INT32(INT_MAX);
125 :
126 332 : 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
133 2 : mxid_age(PG_FUNCTION_ARGS)
134 : {
135 2 : TransactionId xid = PG_GETARG_TRANSACTIONID(0);
136 2 : MultiXactId now = ReadNextMultiXactId();
137 :
138 2 : if (!MultiXactIdIsValid(xid))
139 0 : PG_RETURN_INT32(INT_MAX);
140 :
141 2 : 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
152 73764 : xidComparator(const void *arg1, const void *arg2)
153 : {
154 73764 : TransactionId xid1 = *(const TransactionId *) arg1;
155 73764 : TransactionId xid2 = *(const TransactionId *) arg2;
156 :
157 73764 : 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
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 : Assert(TransactionIdIsNormal(xid1));
175 : 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
187 1580 : xid8toxid(PG_FUNCTION_ARGS)
188 : {
189 1580 : FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
190 :
191 1580 : PG_RETURN_TRANSACTIONID(XidFromFullTransactionId(fxid));
192 : }
193 :
194 : Datum
195 868 : xid8in(PG_FUNCTION_ARGS)
196 : {
197 868 : char *str = PG_GETARG_CSTRING(0);
198 : uint64 result;
199 :
200 868 : result = uint64in_subr(str, NULL, "xid8", fcinfo->context);
201 856 : PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(result));
202 : }
203 :
204 : Datum
205 982 : xid8out(PG_FUNCTION_ARGS)
206 : {
207 982 : FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
208 982 : char *result = (char *) palloc(21);
209 :
210 982 : snprintf(result, 21, UINT64_FORMAT, U64FromFullTransactionId(fxid));
211 982 : PG_RETURN_CSTRING(result);
212 : }
213 :
214 : Datum
215 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
236 18 : xid8eq(PG_FUNCTION_ARGS)
237 : {
238 18 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
239 18 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
240 :
241 18 : PG_RETURN_BOOL(FullTransactionIdEquals(fxid1, fxid2));
242 : }
243 :
244 : Datum
245 8 : xid8ne(PG_FUNCTION_ARGS)
246 : {
247 8 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
248 8 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
249 :
250 8 : PG_RETURN_BOOL(!FullTransactionIdEquals(fxid1, fxid2));
251 : }
252 :
253 : Datum
254 18 : xid8lt(PG_FUNCTION_ARGS)
255 : {
256 18 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
257 18 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
258 :
259 18 : PG_RETURN_BOOL(FullTransactionIdPrecedes(fxid1, fxid2));
260 : }
261 :
262 : Datum
263 18 : xid8gt(PG_FUNCTION_ARGS)
264 : {
265 18 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
266 18 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
267 :
268 18 : PG_RETURN_BOOL(FullTransactionIdFollows(fxid1, fxid2));
269 : }
270 :
271 : Datum
272 18 : xid8le(PG_FUNCTION_ARGS)
273 : {
274 18 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
275 18 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
276 :
277 18 : PG_RETURN_BOOL(FullTransactionIdPrecedesOrEquals(fxid1, fxid2));
278 : }
279 :
280 : Datum
281 24 : xid8ge(PG_FUNCTION_ARGS)
282 : {
283 24 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
284 24 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
285 :
286 24 : PG_RETURN_BOOL(FullTransactionIdFollowsOrEquals(fxid1, fxid2));
287 : }
288 :
289 : Datum
290 42 : xid8cmp(PG_FUNCTION_ARGS)
291 : {
292 42 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
293 42 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
294 :
295 42 : if (FullTransactionIdFollows(fxid1, fxid2))
296 6 : PG_RETURN_INT32(1);
297 36 : else if (FullTransactionIdEquals(fxid1, fxid2))
298 12 : PG_RETURN_INT32(0);
299 : else
300 24 : PG_RETURN_INT32(-1);
301 : }
302 :
303 : Datum
304 30 : hashxid8(PG_FUNCTION_ARGS)
305 : {
306 30 : return hashint8(fcinfo);
307 : }
308 :
309 : Datum
310 0 : hashxid8extended(PG_FUNCTION_ARGS)
311 : {
312 0 : return hashint8extended(fcinfo);
313 : }
314 :
315 : Datum
316 24 : xid8_larger(PG_FUNCTION_ARGS)
317 : {
318 24 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
319 24 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
320 :
321 24 : if (FullTransactionIdFollows(fxid1, fxid2))
322 0 : PG_RETURN_FULLTRANSACTIONID(fxid1);
323 : else
324 24 : PG_RETURN_FULLTRANSACTIONID(fxid2);
325 : }
326 :
327 : Datum
328 24 : xid8_smaller(PG_FUNCTION_ARGS)
329 : {
330 24 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
331 24 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
332 :
333 24 : if (FullTransactionIdPrecedes(fxid1, fxid2))
334 24 : PG_RETURN_FULLTRANSACTIONID(fxid1);
335 : else
336 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
347 6 : cidin(PG_FUNCTION_ARGS)
348 : {
349 6 : char *str = PG_GETARG_CSTRING(0);
350 : CommandId result;
351 :
352 6 : result = uint32in_subr(str, NULL, "cid", fcinfo->context);
353 6 : PG_RETURN_COMMANDID(result);
354 : }
355 :
356 : /*
357 : * cidout - converts a cid to external representation.
358 : */
359 : Datum
360 194 : cidout(PG_FUNCTION_ARGS)
361 : {
362 194 : CommandId c = PG_GETARG_COMMANDID(0);
363 194 : char *result = (char *) palloc(16);
364 :
365 194 : snprintf(result, 16, "%lu", (unsigned long) c);
366 194 : PG_RETURN_CSTRING(result);
367 : }
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 : }
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 : StringInfoData buf;
388 :
389 0 : pq_begintypsend(&buf);
390 0 : pq_sendint32(&buf, arg1);
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
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 : }
|