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