1 /*-------------------------------------------------------------------------
2  *
3  * xid.c
4  *	  POSTGRES transaction identifier and command identifier datatypes.
5  *
6  * Portions Copyright (c) 1996-2018, 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 
25 #define PG_GETARG_TRANSACTIONID(n)	DatumGetTransactionId(PG_GETARG_DATUM(n))
26 #define PG_RETURN_TRANSACTIONID(x)	return TransactionIdGetDatum(x)
27 
28 #define PG_GETARG_COMMANDID(n)		DatumGetCommandId(PG_GETARG_DATUM(n))
29 #define PG_RETURN_COMMANDID(x)		return CommandIdGetDatum(x)
30 
31 
32 Datum
xidin(PG_FUNCTION_ARGS)33 xidin(PG_FUNCTION_ARGS)
34 {
35 	char	   *str = PG_GETARG_CSTRING(0);
36 
37 	PG_RETURN_TRANSACTIONID((TransactionId) strtoul(str, NULL, 0));
38 }
39 
40 Datum
xidout(PG_FUNCTION_ARGS)41 xidout(PG_FUNCTION_ARGS)
42 {
43 	TransactionId transactionId = PG_GETARG_TRANSACTIONID(0);
44 	char	   *result = (char *) palloc(16);
45 
46 	snprintf(result, 16, "%lu", (unsigned long) transactionId);
47 	PG_RETURN_CSTRING(result);
48 }
49 
50 /*
51  *		xidrecv			- converts external binary format to xid
52  */
53 Datum
xidrecv(PG_FUNCTION_ARGS)54 xidrecv(PG_FUNCTION_ARGS)
55 {
56 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
57 
58 	PG_RETURN_TRANSACTIONID((TransactionId) pq_getmsgint(buf, sizeof(TransactionId)));
59 }
60 
61 /*
62  *		xidsend			- converts xid to binary format
63  */
64 Datum
xidsend(PG_FUNCTION_ARGS)65 xidsend(PG_FUNCTION_ARGS)
66 {
67 	TransactionId arg1 = PG_GETARG_TRANSACTIONID(0);
68 	StringInfoData buf;
69 
70 	pq_begintypsend(&buf);
71 	pq_sendint32(&buf, arg1);
72 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
73 }
74 
75 /*
76  *		xideq			- are two xids equal?
77  */
78 Datum
xideq(PG_FUNCTION_ARGS)79 xideq(PG_FUNCTION_ARGS)
80 {
81 	TransactionId xid1 = PG_GETARG_TRANSACTIONID(0);
82 	TransactionId xid2 = PG_GETARG_TRANSACTIONID(1);
83 
84 	PG_RETURN_BOOL(TransactionIdEquals(xid1, xid2));
85 }
86 
87 /*
88  *		xidneq			- are two xids different?
89  */
90 Datum
xidneq(PG_FUNCTION_ARGS)91 xidneq(PG_FUNCTION_ARGS)
92 {
93 	TransactionId xid1 = PG_GETARG_TRANSACTIONID(0);
94 	TransactionId xid2 = PG_GETARG_TRANSACTIONID(1);
95 
96 	PG_RETURN_BOOL(!TransactionIdEquals(xid1, xid2));
97 }
98 
99 /*
100  *		xid_age			- compute age of an XID (relative to latest stable xid)
101  */
102 Datum
xid_age(PG_FUNCTION_ARGS)103 xid_age(PG_FUNCTION_ARGS)
104 {
105 	TransactionId xid = PG_GETARG_TRANSACTIONID(0);
106 	TransactionId now = GetStableLatestTransactionId();
107 
108 	/* Permanent XIDs are always infinitely old */
109 	if (!TransactionIdIsNormal(xid))
110 		PG_RETURN_INT32(INT_MAX);
111 
112 	PG_RETURN_INT32((int32) (now - xid));
113 }
114 
115 /*
116  *		mxid_age			- compute age of a multi XID (relative to latest stable mxid)
117  */
118 Datum
mxid_age(PG_FUNCTION_ARGS)119 mxid_age(PG_FUNCTION_ARGS)
120 {
121 	TransactionId xid = PG_GETARG_TRANSACTIONID(0);
122 	MultiXactId now = ReadNextMultiXactId();
123 
124 	if (!MultiXactIdIsValid(xid))
125 		PG_RETURN_INT32(INT_MAX);
126 
127 	PG_RETURN_INT32((int32) (now - xid));
128 }
129 
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
xidComparator(const void * arg1,const void * arg2)138 xidComparator(const void *arg1, const void *arg2)
139 {
140 	TransactionId xid1 = *(const TransactionId *) arg1;
141 	TransactionId xid2 = *(const TransactionId *) arg2;
142 
143 	if (xid1 > xid2)
144 		return 1;
145 	if (xid1 < xid2)
146 		return -1;
147 	return 0;
148 }
149 
150 /*****************************************************************************
151  *	 COMMAND IDENTIFIER ROUTINES											 *
152  *****************************************************************************/
153 
154 /*
155  *		cidin	- converts CommandId to internal representation.
156  */
157 Datum
cidin(PG_FUNCTION_ARGS)158 cidin(PG_FUNCTION_ARGS)
159 {
160 	char	   *str = PG_GETARG_CSTRING(0);
161 
162 	PG_RETURN_COMMANDID((CommandId) strtoul(str, NULL, 0));
163 }
164 
165 /*
166  *		cidout	- converts a cid to external representation.
167  */
168 Datum
cidout(PG_FUNCTION_ARGS)169 cidout(PG_FUNCTION_ARGS)
170 {
171 	CommandId	c = PG_GETARG_COMMANDID(0);
172 	char	   *result = (char *) palloc(16);
173 
174 	snprintf(result, 16, "%lu", (unsigned long) c);
175 	PG_RETURN_CSTRING(result);
176 }
177 
178 /*
179  *		cidrecv			- converts external binary format to cid
180  */
181 Datum
cidrecv(PG_FUNCTION_ARGS)182 cidrecv(PG_FUNCTION_ARGS)
183 {
184 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
185 
186 	PG_RETURN_COMMANDID((CommandId) pq_getmsgint(buf, sizeof(CommandId)));
187 }
188 
189 /*
190  *		cidsend			- converts cid to binary format
191  */
192 Datum
cidsend(PG_FUNCTION_ARGS)193 cidsend(PG_FUNCTION_ARGS)
194 {
195 	CommandId	arg1 = PG_GETARG_COMMANDID(0);
196 	StringInfoData buf;
197 
198 	pq_begintypsend(&buf);
199 	pq_sendint32(&buf, arg1);
200 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
201 }
202 
203 Datum
cideq(PG_FUNCTION_ARGS)204 cideq(PG_FUNCTION_ARGS)
205 {
206 	CommandId	arg1 = PG_GETARG_COMMANDID(0);
207 	CommandId	arg2 = PG_GETARG_COMMANDID(1);
208 
209 	PG_RETURN_BOOL(arg1 == arg2);
210 }
211