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