Age Owner Branch data TLA 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
7643 tgl@sss.pgh.pa.us 32 :CBC 2381 : xidin(PG_FUNCTION_ARGS)
33 : : {
34 : 2381 : char *str = PG_GETARG_CSTRING(0);
35 : : TransactionId result;
36 : :
474 37 : 2381 : result = uint32in_subr(str, NULL, "xid", fcinfo->context);
38 : 2375 : PG_RETURN_TRANSACTIONID(result);
39 : : }
40 : :
41 : : Datum
7643 42 : 99553 : xidout(PG_FUNCTION_ARGS)
43 : : {
44 : 99553 : TransactionId transactionId = PG_GETARG_TRANSACTIONID(0);
2735 45 : 99553 : char *result = (char *) palloc(16);
46 : :
47 : 99553 : snprintf(result, 16, "%lu", (unsigned long) transactionId);
48 : 99553 : PG_RETURN_CSTRING(result);
49 : : }
50 : :
51 : : /*
52 : : * xidrecv - converts external binary format to xid
53 : : */
54 : : Datum
7643 tgl@sss.pgh.pa.us 55 :UBC 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);
2377 andres@anarazel.de 72 : 0 : pq_sendint32(&buf, arg1);
7643 tgl@sss.pgh.pa.us 73 : 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
74 : : }
75 : :
76 : : /*
77 : : * xideq - are two xids equal?
78 : : */
79 : : Datum
7643 tgl@sss.pgh.pa.us 80 :CBC 188204 : xideq(PG_FUNCTION_ARGS)
81 : : {
82 : 188204 : TransactionId xid1 = PG_GETARG_TRANSACTIONID(0);
83 : 188204 : TransactionId xid2 = PG_GETARG_TRANSACTIONID(1);
84 : :
85 : 188204 : PG_RETURN_BOOL(TransactionIdEquals(xid1, xid2));
86 : : }
87 : :
88 : : /*
89 : : * xidneq - are two xids different?
90 : : */
91 : : Datum
3081 92 : 441 : xidneq(PG_FUNCTION_ARGS)
93 : : {
94 : 441 : TransactionId xid1 = PG_GETARG_TRANSACTIONID(0);
95 : 441 : TransactionId xid2 = PG_GETARG_TRANSACTIONID(1);
96 : :
97 : 441 : 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
7643 104 : 129 : xid_age(PG_FUNCTION_ARGS)
105 : : {
106 : 129 : TransactionId xid = PG_GETARG_TRANSACTIONID(0);
4356 simon@2ndQuadrant.co 107 : 129 : TransactionId now = GetStableLatestTransactionId();
108 : :
109 : : /* Permanent XIDs are always infinitely old */
7643 tgl@sss.pgh.pa.us 110 [ - + ]: 129 : if (!TransactionIdIsNormal(xid))
7643 tgl@sss.pgh.pa.us 111 :UBC 0 : PG_RETURN_INT32(INT_MAX);
112 : :
7643 tgl@sss.pgh.pa.us 113 :CBC 129 : 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
3504 bruce@momjian.us 120 : 1 : mxid_age(PG_FUNCTION_ARGS)
121 : : {
122 : 1 : TransactionId xid = PG_GETARG_TRANSACTIONID(0);
123 : 1 : MultiXactId now = ReadNextMultiXactId();
124 : :
125 [ - + ]: 1 : if (!MultiXactIdIsValid(xid))
3504 bruce@momjian.us 126 :UBC 0 : PG_RETURN_INT32(INT_MAX);
127 : :
3504 bruce@momjian.us 128 :CBC 1 : 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
5230 simon@2ndQuadrant.co 139 : 38397 : xidComparator(const void *arg1, const void *arg2)
140 : : {
141 : 38397 : TransactionId xid1 = *(const TransactionId *) arg1;
142 : 38397 : TransactionId xid2 = *(const TransactionId *) arg2;
143 : :
58 nathan@postgresql.or 144 :GNC 38397 : 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
808 tomas.vondra@postgre 156 :UBC 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 [ # # ]: 0 : Assert(TransactionIdIsNormal(xid1));
162 [ # # ]: 0 : 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
1468 tmunro@postgresql.or 174 :CBC 1031 : xid8toxid(PG_FUNCTION_ARGS)
175 : : {
176 : 1031 : FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
177 : :
178 : 1031 : PG_RETURN_TRANSACTIONID(XidFromFullTransactionId(fxid));
179 : : }
180 : :
181 : : Datum
182 : 434 : xid8in(PG_FUNCTION_ARGS)
183 : : {
184 : 434 : char *str = PG_GETARG_CSTRING(0);
185 : : uint64 result;
186 : :
474 tgl@sss.pgh.pa.us 187 : 434 : result = uint64in_subr(str, NULL, "xid8", fcinfo->context);
188 : 428 : PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(result));
189 : : }
190 : :
191 : : Datum
1468 tmunro@postgresql.or 192 : 491 : xid8out(PG_FUNCTION_ARGS)
193 : : {
194 : 491 : FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
195 : 491 : char *result = (char *) palloc(21);
196 : :
197 : 491 : snprintf(result, 21, UINT64_FORMAT, U64FromFullTransactionId(fxid));
198 : 491 : PG_RETURN_CSTRING(result);
199 : : }
200 : :
201 : : Datum
1468 tmunro@postgresql.or 202 :UBC 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
1468 tmunro@postgresql.or 223 :CBC 9 : xid8eq(PG_FUNCTION_ARGS)
224 : : {
225 : 9 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
226 : 9 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
227 : :
228 : 9 : PG_RETURN_BOOL(FullTransactionIdEquals(fxid1, fxid2));
229 : : }
230 : :
231 : : Datum
232 : 4 : xid8ne(PG_FUNCTION_ARGS)
233 : : {
234 : 4 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
235 : 4 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
236 : :
237 : 4 : PG_RETURN_BOOL(!FullTransactionIdEquals(fxid1, fxid2));
238 : : }
239 : :
240 : : Datum
241 : 9 : xid8lt(PG_FUNCTION_ARGS)
242 : : {
243 : 9 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
244 : 9 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
245 : :
246 : 9 : PG_RETURN_BOOL(FullTransactionIdPrecedes(fxid1, fxid2));
247 : : }
248 : :
249 : : Datum
250 : 9 : xid8gt(PG_FUNCTION_ARGS)
251 : : {
252 : 9 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
253 : 9 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
254 : :
255 : 9 : PG_RETURN_BOOL(FullTransactionIdFollows(fxid1, fxid2));
256 : : }
257 : :
258 : : Datum
259 : 9 : xid8le(PG_FUNCTION_ARGS)
260 : : {
261 : 9 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
262 : 9 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
263 : :
264 : 9 : PG_RETURN_BOOL(FullTransactionIdPrecedesOrEquals(fxid1, fxid2));
265 : : }
266 : :
267 : : Datum
268 : 12 : xid8ge(PG_FUNCTION_ARGS)
269 : : {
270 : 12 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
271 : 12 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
272 : :
273 : 12 : PG_RETURN_BOOL(FullTransactionIdFollowsOrEquals(fxid1, fxid2));
274 : : }
275 : :
276 : : Datum
277 : 21 : xid8cmp(PG_FUNCTION_ARGS)
278 : : {
279 : 21 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
280 : 21 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
281 : :
282 [ + + ]: 21 : if (FullTransactionIdFollows(fxid1, fxid2))
283 : 3 : PG_RETURN_INT32(1);
284 [ + + ]: 18 : else if (FullTransactionIdEquals(fxid1, fxid2))
285 : 6 : PG_RETURN_INT32(0);
286 : : else
287 : 12 : PG_RETURN_INT32(-1);
288 : : }
289 : :
290 : : Datum
794 fujii@postgresql.org 291 : 12 : xid8_larger(PG_FUNCTION_ARGS)
292 : : {
293 : 12 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
294 : 12 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
295 : :
296 [ - + ]: 12 : if (FullTransactionIdFollows(fxid1, fxid2))
794 fujii@postgresql.org 297 :UBC 0 : PG_RETURN_FULLTRANSACTIONID(fxid1);
298 : : else
794 fujii@postgresql.org 299 :CBC 12 : PG_RETURN_FULLTRANSACTIONID(fxid2);
300 : : }
301 : :
302 : : Datum
303 : 12 : xid8_smaller(PG_FUNCTION_ARGS)
304 : : {
305 : 12 : FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
306 : 12 : FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
307 : :
308 [ + - ]: 12 : if (FullTransactionIdPrecedes(fxid1, fxid2))
309 : 12 : PG_RETURN_FULLTRANSACTIONID(fxid1);
310 : : else
794 fujii@postgresql.org 311 :UBC 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
7643 tgl@sss.pgh.pa.us 322 :CBC 3 : cidin(PG_FUNCTION_ARGS)
323 : : {
2735 324 : 3 : char *str = PG_GETARG_CSTRING(0);
325 : : CommandId result;
326 : :
474 327 : 3 : result = uint32in_subr(str, NULL, "cid", fcinfo->context);
328 : 3 : PG_RETURN_COMMANDID(result);
329 : : }
330 : :
331 : : /*
332 : : * cidout - converts a cid to external representation.
333 : : */
334 : : Datum
7643 335 : 97 : cidout(PG_FUNCTION_ARGS)
336 : : {
337 : 97 : CommandId c = PG_GETARG_COMMANDID(0);
338 : 97 : char *result = (char *) palloc(16);
339 : :
2735 340 : 97 : snprintf(result, 16, "%lu", (unsigned long) c);
7643 341 : 97 : PG_RETURN_CSTRING(result);
342 : : }
343 : :
344 : : /*
345 : : * cidrecv - converts external binary format to cid
346 : : */
347 : : Datum
7643 tgl@sss.pgh.pa.us 348 :UBC 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 : : {
7559 bruce@momjian.us 361 : 0 : CommandId arg1 = PG_GETARG_COMMANDID(0);
362 : : StringInfoData buf;
363 : :
7643 tgl@sss.pgh.pa.us 364 : 0 : pq_begintypsend(&buf);
2377 andres@anarazel.de 365 : 0 : pq_sendint32(&buf, arg1);
7643 tgl@sss.pgh.pa.us 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 : : }
|