1 /*-------------------------------------------------------------------------
2 *
3 * xid.c
4 * POSTGRES transaction identifier and command identifier datatypes.
5 *
6 * Portions Copyright (c) 1996-2020, 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_TRANSACTIONID(n) DatumGetTransactionId(PG_GETARG_DATUM(n))
27 #define PG_RETURN_TRANSACTIONID(x) return TransactionIdGetDatum(x)
28
29 #define PG_GETARG_COMMANDID(n) DatumGetCommandId(PG_GETARG_DATUM(n))
30 #define PG_RETURN_COMMANDID(x) return CommandIdGetDatum(x)
31
32
33 Datum
xidin(PG_FUNCTION_ARGS)34 xidin(PG_FUNCTION_ARGS)
35 {
36 char *str = PG_GETARG_CSTRING(0);
37
38 PG_RETURN_TRANSACTIONID((TransactionId) strtoul(str, NULL, 0));
39 }
40
41 Datum
xidout(PG_FUNCTION_ARGS)42 xidout(PG_FUNCTION_ARGS)
43 {
44 TransactionId transactionId = PG_GETARG_TRANSACTIONID(0);
45 char *result = (char *) palloc(16);
46
47 snprintf(result, 16, "%lu", (unsigned long) transactionId);
48 PG_RETURN_CSTRING(result);
49 }
50
51 /*
52 * xidrecv - converts external binary format to xid
53 */
54 Datum
xidrecv(PG_FUNCTION_ARGS)55 xidrecv(PG_FUNCTION_ARGS)
56 {
57 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
58
59 PG_RETURN_TRANSACTIONID((TransactionId) pq_getmsgint(buf, sizeof(TransactionId)));
60 }
61
62 /*
63 * xidsend - converts xid to binary format
64 */
65 Datum
xidsend(PG_FUNCTION_ARGS)66 xidsend(PG_FUNCTION_ARGS)
67 {
68 TransactionId arg1 = PG_GETARG_TRANSACTIONID(0);
69 StringInfoData buf;
70
71 pq_begintypsend(&buf);
72 pq_sendint32(&buf, arg1);
73 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
74 }
75
76 /*
77 * xideq - are two xids equal?
78 */
79 Datum
xideq(PG_FUNCTION_ARGS)80 xideq(PG_FUNCTION_ARGS)
81 {
82 TransactionId xid1 = PG_GETARG_TRANSACTIONID(0);
83 TransactionId xid2 = PG_GETARG_TRANSACTIONID(1);
84
85 PG_RETURN_BOOL(TransactionIdEquals(xid1, xid2));
86 }
87
88 /*
89 * xidneq - are two xids different?
90 */
91 Datum
xidneq(PG_FUNCTION_ARGS)92 xidneq(PG_FUNCTION_ARGS)
93 {
94 TransactionId xid1 = PG_GETARG_TRANSACTIONID(0);
95 TransactionId xid2 = PG_GETARG_TRANSACTIONID(1);
96
97 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
xid_age(PG_FUNCTION_ARGS)104 xid_age(PG_FUNCTION_ARGS)
105 {
106 TransactionId xid = PG_GETARG_TRANSACTIONID(0);
107 TransactionId now = GetStableLatestTransactionId();
108
109 /* Permanent XIDs are always infinitely old */
110 if (!TransactionIdIsNormal(xid))
111 PG_RETURN_INT32(INT_MAX);
112
113 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
mxid_age(PG_FUNCTION_ARGS)120 mxid_age(PG_FUNCTION_ARGS)
121 {
122 TransactionId xid = PG_GETARG_TRANSACTIONID(0);
123 MultiXactId now = ReadNextMultiXactId();
124
125 if (!MultiXactIdIsValid(xid))
126 PG_RETURN_INT32(INT_MAX);
127
128 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
xidComparator(const void * arg1,const void * arg2)139 xidComparator(const void *arg1, const void *arg2)
140 {
141 TransactionId xid1 = *(const TransactionId *) arg1;
142 TransactionId xid2 = *(const TransactionId *) arg2;
143
144 if (xid1 > xid2)
145 return 1;
146 if (xid1 < xid2)
147 return -1;
148 return 0;
149 }
150
151 Datum
xid8toxid(PG_FUNCTION_ARGS)152 xid8toxid(PG_FUNCTION_ARGS)
153 {
154 FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
155
156 PG_RETURN_TRANSACTIONID(XidFromFullTransactionId(fxid));
157 }
158
159 Datum
xid8in(PG_FUNCTION_ARGS)160 xid8in(PG_FUNCTION_ARGS)
161 {
162 char *str = PG_GETARG_CSTRING(0);
163
164 PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(pg_strtouint64(str, NULL, 0)));
165 }
166
167 Datum
xid8out(PG_FUNCTION_ARGS)168 xid8out(PG_FUNCTION_ARGS)
169 {
170 FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
171 char *result = (char *) palloc(21);
172
173 snprintf(result, 21, UINT64_FORMAT, U64FromFullTransactionId(fxid));
174 PG_RETURN_CSTRING(result);
175 }
176
177 Datum
xid8recv(PG_FUNCTION_ARGS)178 xid8recv(PG_FUNCTION_ARGS)
179 {
180 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
181 uint64 value;
182
183 value = (uint64) pq_getmsgint64(buf);
184 PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(value));
185 }
186
187 Datum
xid8send(PG_FUNCTION_ARGS)188 xid8send(PG_FUNCTION_ARGS)
189 {
190 FullTransactionId arg1 = PG_GETARG_FULLTRANSACTIONID(0);
191 StringInfoData buf;
192
193 pq_begintypsend(&buf);
194 pq_sendint64(&buf, (uint64) U64FromFullTransactionId(arg1));
195 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
196 }
197
198 Datum
xid8eq(PG_FUNCTION_ARGS)199 xid8eq(PG_FUNCTION_ARGS)
200 {
201 FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
202 FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
203
204 PG_RETURN_BOOL(FullTransactionIdEquals(fxid1, fxid2));
205 }
206
207 Datum
xid8ne(PG_FUNCTION_ARGS)208 xid8ne(PG_FUNCTION_ARGS)
209 {
210 FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
211 FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
212
213 PG_RETURN_BOOL(!FullTransactionIdEquals(fxid1, fxid2));
214 }
215
216 Datum
xid8lt(PG_FUNCTION_ARGS)217 xid8lt(PG_FUNCTION_ARGS)
218 {
219 FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
220 FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
221
222 PG_RETURN_BOOL(FullTransactionIdPrecedes(fxid1, fxid2));
223 }
224
225 Datum
xid8gt(PG_FUNCTION_ARGS)226 xid8gt(PG_FUNCTION_ARGS)
227 {
228 FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
229 FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
230
231 PG_RETURN_BOOL(FullTransactionIdFollows(fxid1, fxid2));
232 }
233
234 Datum
xid8le(PG_FUNCTION_ARGS)235 xid8le(PG_FUNCTION_ARGS)
236 {
237 FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
238 FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
239
240 PG_RETURN_BOOL(FullTransactionIdPrecedesOrEquals(fxid1, fxid2));
241 }
242
243 Datum
xid8ge(PG_FUNCTION_ARGS)244 xid8ge(PG_FUNCTION_ARGS)
245 {
246 FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
247 FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
248
249 PG_RETURN_BOOL(FullTransactionIdFollowsOrEquals(fxid1, fxid2));
250 }
251
252 Datum
xid8cmp(PG_FUNCTION_ARGS)253 xid8cmp(PG_FUNCTION_ARGS)
254 {
255 FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
256 FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
257
258 if (FullTransactionIdFollows(fxid1, fxid2))
259 PG_RETURN_INT32(1);
260 else if (FullTransactionIdEquals(fxid1, fxid2))
261 PG_RETURN_INT32(0);
262 else
263 PG_RETURN_INT32(-1);
264 }
265
266 /*****************************************************************************
267 * COMMAND IDENTIFIER ROUTINES *
268 *****************************************************************************/
269
270 /*
271 * cidin - converts CommandId to internal representation.
272 */
273 Datum
cidin(PG_FUNCTION_ARGS)274 cidin(PG_FUNCTION_ARGS)
275 {
276 char *str = PG_GETARG_CSTRING(0);
277
278 PG_RETURN_COMMANDID((CommandId) strtoul(str, NULL, 0));
279 }
280
281 /*
282 * cidout - converts a cid to external representation.
283 */
284 Datum
cidout(PG_FUNCTION_ARGS)285 cidout(PG_FUNCTION_ARGS)
286 {
287 CommandId c = PG_GETARG_COMMANDID(0);
288 char *result = (char *) palloc(16);
289
290 snprintf(result, 16, "%lu", (unsigned long) c);
291 PG_RETURN_CSTRING(result);
292 }
293
294 /*
295 * cidrecv - converts external binary format to cid
296 */
297 Datum
cidrecv(PG_FUNCTION_ARGS)298 cidrecv(PG_FUNCTION_ARGS)
299 {
300 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
301
302 PG_RETURN_COMMANDID((CommandId) pq_getmsgint(buf, sizeof(CommandId)));
303 }
304
305 /*
306 * cidsend - converts cid to binary format
307 */
308 Datum
cidsend(PG_FUNCTION_ARGS)309 cidsend(PG_FUNCTION_ARGS)
310 {
311 CommandId arg1 = PG_GETARG_COMMANDID(0);
312 StringInfoData buf;
313
314 pq_begintypsend(&buf);
315 pq_sendint32(&buf, arg1);
316 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
317 }
318
319 Datum
cideq(PG_FUNCTION_ARGS)320 cideq(PG_FUNCTION_ARGS)
321 {
322 CommandId arg1 = PG_GETARG_COMMANDID(0);
323 CommandId arg2 = PG_GETARG_COMMANDID(1);
324
325 PG_RETURN_BOOL(arg1 == arg2);
326 }
327