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