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