1/*-------------------------------------------------------------------------
2 *
3 * xid.c
4 * POSTGRES transaction identifier and command identifier datatypes.
5 *
6 * Portions Copyright (c) 1996-2019, 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
32Datum
33xidin(PG_FUNCTION_ARGS)
34{
35 char *str = PG_GETARG_CSTRING(0);
36
37 PG_RETURN_TRANSACTIONID((TransactionId) strtoul(str, NULL, 0));
38}
39
40Datum
41xidout(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 */
53Datum
54xidrecv(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 */
64Datum
65xidsend(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 */
78Datum
79xideq(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 */
90Datum
91xidneq(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 */
102Datum
103xid_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 */
118Datum
119mxid_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 */
137int
138xidComparator(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 */
157Datum
158cidin(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 */
168Datum
169cidout(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 */
181Datum
182cidrecv(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 */
192Datum
193cidsend(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
203Datum
204cideq(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