1 /*-------------------------------------------------------------------------
2 *
3 * pg_lsn.c
4 * Operations for the pg_lsn datatype.
5 *
6 * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 * IDENTIFICATION
10 * src/backend/utils/adt/pg_lsn.c
11 *
12 *-------------------------------------------------------------------------
13 */
14 #include "postgres.h"
15
16 #include "funcapi.h"
17 #include "libpq/pqformat.h"
18 #include "utils/builtins.h"
19 #include "utils/pg_lsn.h"
20
21 #define MAXPG_LSNLEN 17
22 #define MAXPG_LSNCOMPONENT 8
23
24 /*----------------------------------------------------------
25 * Formatting and conversion routines.
26 *---------------------------------------------------------*/
27
28 XLogRecPtr
pg_lsn_in_internal(const char * str,bool * have_error)29 pg_lsn_in_internal(const char *str, bool *have_error)
30 {
31 int len1,
32 len2;
33 uint32 id,
34 off;
35 XLogRecPtr result;
36
37 Assert(have_error != NULL);
38 *have_error = false;
39
40 /* Sanity check input format. */
41 len1 = strspn(str, "0123456789abcdefABCDEF");
42 if (len1 < 1 || len1 > MAXPG_LSNCOMPONENT || str[len1] != '/')
43 {
44 *have_error = true;
45 return InvalidXLogRecPtr;
46 }
47 len2 = strspn(str + len1 + 1, "0123456789abcdefABCDEF");
48 if (len2 < 1 || len2 > MAXPG_LSNCOMPONENT || str[len1 + 1 + len2] != '\0')
49 {
50 *have_error = true;
51 return InvalidXLogRecPtr;
52 }
53
54 /* Decode result. */
55 id = (uint32) strtoul(str, NULL, 16);
56 off = (uint32) strtoul(str + len1 + 1, NULL, 16);
57 result = ((uint64) id << 32) | off;
58
59 return result;
60 }
61
62 Datum
pg_lsn_in(PG_FUNCTION_ARGS)63 pg_lsn_in(PG_FUNCTION_ARGS)
64 {
65 char *str = PG_GETARG_CSTRING(0);
66 XLogRecPtr result;
67 bool have_error = false;
68
69 result = pg_lsn_in_internal(str, &have_error);
70 if (have_error)
71 ereport(ERROR,
72 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
73 errmsg("invalid input syntax for type %s: \"%s\"",
74 "pg_lsn", str)));
75
76 PG_RETURN_LSN(result);
77 }
78
79 Datum
pg_lsn_out(PG_FUNCTION_ARGS)80 pg_lsn_out(PG_FUNCTION_ARGS)
81 {
82 XLogRecPtr lsn = PG_GETARG_LSN(0);
83 char buf[MAXPG_LSNLEN + 1];
84 char *result;
85 uint32 id,
86 off;
87
88 /* Decode ID and offset */
89 id = (uint32) (lsn >> 32);
90 off = (uint32) lsn;
91
92 snprintf(buf, sizeof buf, "%X/%X", id, off);
93 result = pstrdup(buf);
94 PG_RETURN_CSTRING(result);
95 }
96
97 Datum
pg_lsn_recv(PG_FUNCTION_ARGS)98 pg_lsn_recv(PG_FUNCTION_ARGS)
99 {
100 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
101 XLogRecPtr result;
102
103 result = pq_getmsgint64(buf);
104 PG_RETURN_LSN(result);
105 }
106
107 Datum
pg_lsn_send(PG_FUNCTION_ARGS)108 pg_lsn_send(PG_FUNCTION_ARGS)
109 {
110 XLogRecPtr lsn = PG_GETARG_LSN(0);
111 StringInfoData buf;
112
113 pq_begintypsend(&buf);
114 pq_sendint64(&buf, lsn);
115 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
116 }
117
118
119 /*----------------------------------------------------------
120 * Operators for PostgreSQL LSNs
121 *---------------------------------------------------------*/
122
123 Datum
pg_lsn_eq(PG_FUNCTION_ARGS)124 pg_lsn_eq(PG_FUNCTION_ARGS)
125 {
126 XLogRecPtr lsn1 = PG_GETARG_LSN(0);
127 XLogRecPtr lsn2 = PG_GETARG_LSN(1);
128
129 PG_RETURN_BOOL(lsn1 == lsn2);
130 }
131
132 Datum
pg_lsn_ne(PG_FUNCTION_ARGS)133 pg_lsn_ne(PG_FUNCTION_ARGS)
134 {
135 XLogRecPtr lsn1 = PG_GETARG_LSN(0);
136 XLogRecPtr lsn2 = PG_GETARG_LSN(1);
137
138 PG_RETURN_BOOL(lsn1 != lsn2);
139 }
140
141 Datum
pg_lsn_lt(PG_FUNCTION_ARGS)142 pg_lsn_lt(PG_FUNCTION_ARGS)
143 {
144 XLogRecPtr lsn1 = PG_GETARG_LSN(0);
145 XLogRecPtr lsn2 = PG_GETARG_LSN(1);
146
147 PG_RETURN_BOOL(lsn1 < lsn2);
148 }
149
150 Datum
pg_lsn_gt(PG_FUNCTION_ARGS)151 pg_lsn_gt(PG_FUNCTION_ARGS)
152 {
153 XLogRecPtr lsn1 = PG_GETARG_LSN(0);
154 XLogRecPtr lsn2 = PG_GETARG_LSN(1);
155
156 PG_RETURN_BOOL(lsn1 > lsn2);
157 }
158
159 Datum
pg_lsn_le(PG_FUNCTION_ARGS)160 pg_lsn_le(PG_FUNCTION_ARGS)
161 {
162 XLogRecPtr lsn1 = PG_GETARG_LSN(0);
163 XLogRecPtr lsn2 = PG_GETARG_LSN(1);
164
165 PG_RETURN_BOOL(lsn1 <= lsn2);
166 }
167
168 Datum
pg_lsn_ge(PG_FUNCTION_ARGS)169 pg_lsn_ge(PG_FUNCTION_ARGS)
170 {
171 XLogRecPtr lsn1 = PG_GETARG_LSN(0);
172 XLogRecPtr lsn2 = PG_GETARG_LSN(1);
173
174 PG_RETURN_BOOL(lsn1 >= lsn2);
175 }
176
177 Datum
pg_lsn_larger(PG_FUNCTION_ARGS)178 pg_lsn_larger(PG_FUNCTION_ARGS)
179 {
180 XLogRecPtr lsn1 = PG_GETARG_LSN(0);
181 XLogRecPtr lsn2 = PG_GETARG_LSN(1);
182
183 PG_RETURN_LSN((lsn1 > lsn2) ? lsn1 : lsn2);
184 }
185
186 Datum
pg_lsn_smaller(PG_FUNCTION_ARGS)187 pg_lsn_smaller(PG_FUNCTION_ARGS)
188 {
189 XLogRecPtr lsn1 = PG_GETARG_LSN(0);
190 XLogRecPtr lsn2 = PG_GETARG_LSN(1);
191
192 PG_RETURN_LSN((lsn1 < lsn2) ? lsn1 : lsn2);
193 }
194
195 /* btree index opclass support */
196 Datum
pg_lsn_cmp(PG_FUNCTION_ARGS)197 pg_lsn_cmp(PG_FUNCTION_ARGS)
198 {
199 XLogRecPtr a = PG_GETARG_LSN(0);
200 XLogRecPtr b = PG_GETARG_LSN(1);
201
202 if (a > b)
203 PG_RETURN_INT32(1);
204 else if (a == b)
205 PG_RETURN_INT32(0);
206 else
207 PG_RETURN_INT32(-1);
208 }
209
210 /* hash index opclass support */
211 Datum
pg_lsn_hash(PG_FUNCTION_ARGS)212 pg_lsn_hash(PG_FUNCTION_ARGS)
213 {
214 /* We can use hashint8 directly */
215 return hashint8(fcinfo);
216 }
217
218 Datum
pg_lsn_hash_extended(PG_FUNCTION_ARGS)219 pg_lsn_hash_extended(PG_FUNCTION_ARGS)
220 {
221 return hashint8extended(fcinfo);
222 }
223
224
225 /*----------------------------------------------------------
226 * Arithmetic operators on PostgreSQL LSNs.
227 *---------------------------------------------------------*/
228
229 Datum
pg_lsn_mi(PG_FUNCTION_ARGS)230 pg_lsn_mi(PG_FUNCTION_ARGS)
231 {
232 XLogRecPtr lsn1 = PG_GETARG_LSN(0);
233 XLogRecPtr lsn2 = PG_GETARG_LSN(1);
234 char buf[256];
235 Datum result;
236
237 /* Output could be as large as plus or minus 2^63 - 1. */
238 if (lsn1 < lsn2)
239 snprintf(buf, sizeof buf, "-" UINT64_FORMAT, lsn2 - lsn1);
240 else
241 snprintf(buf, sizeof buf, UINT64_FORMAT, lsn1 - lsn2);
242
243 /* Convert to numeric. */
244 result = DirectFunctionCall3(numeric_in,
245 CStringGetDatum(buf),
246 ObjectIdGetDatum(0),
247 Int32GetDatum(-1));
248
249 return result;
250 }
251