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