Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * pg_lsn.c
4 : : * Operations for the pg_lsn datatype.
5 : : *
6 : : * Portions Copyright (c) 1996-2024, 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 "libpq/pqformat.h"
17 : : #include "utils/fmgrprotos.h"
18 : : #include "utils/numeric.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
1750 peter@eisentraut.org 29 :CBC 3896 : 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 : :
1714 michael@paquier.xyz 37 [ - + ]: 3896 : Assert(have_error != NULL);
38 : 3896 : *have_error = false;
39 : :
40 : : /* Sanity check input format. */
3707 rhaas@postgresql.org 41 : 3896 : len1 = strspn(str, "0123456789abcdefABCDEF");
42 [ + + + - : 3896 : if (len1 < 1 || len1 > MAXPG_LSNCOMPONENT || str[len1] != '/')
+ + ]
43 : : {
1750 peter@eisentraut.org 44 : 18 : *have_error = true;
45 : 18 : return InvalidXLogRecPtr;
46 : : }
3707 rhaas@postgresql.org 47 : 3878 : len2 = strspn(str + len1 + 1, "0123456789abcdefABCDEF");
48 [ + + + - : 3878 : if (len2 < 1 || len2 > MAXPG_LSNCOMPONENT || str[len1 + 1 + len2] != '\0')
- + ]
49 : : {
1750 peter@eisentraut.org 50 : 3 : *have_error = true;
51 : 3 : return InvalidXLogRecPtr;
52 : : }
53 : :
54 : : /* Decode result. */
3707 rhaas@postgresql.org 55 : 3875 : id = (uint32) strtoul(str, NULL, 16);
56 : 3875 : off = (uint32) strtoul(str + len1 + 1, NULL, 16);
57 : 3875 : result = ((uint64) id << 32) | off;
58 : :
1750 peter@eisentraut.org 59 : 3875 : return result;
60 : : }
61 : :
62 : : Datum
63 : 3890 : pg_lsn_in(PG_FUNCTION_ARGS)
64 : : {
65 : 3890 : char *str = PG_GETARG_CSTRING(0);
66 : : XLogRecPtr result;
1749 tgl@sss.pgh.pa.us 67 : 3890 : bool have_error = false;
68 : :
1750 peter@eisentraut.org 69 : 3890 : result = pg_lsn_in_internal(str, &have_error);
70 [ + + ]: 3890 : if (have_error)
487 tgl@sss.pgh.pa.us 71 [ + + ]: 21 : ereturn(fcinfo->context, (Datum) 0,
72 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
73 : : errmsg("invalid input syntax for type %s: \"%s\"",
74 : : "pg_lsn", str)));
75 : :
1750 peter@eisentraut.org 76 : 3869 : PG_RETURN_LSN(result);
77 : : }
78 : :
79 : : Datum
3707 rhaas@postgresql.org 80 : 2608 : pg_lsn_out(PG_FUNCTION_ARGS)
81 : : {
82 : 2608 : XLogRecPtr lsn = PG_GETARG_LSN(0);
83 : : char buf[MAXPG_LSNLEN + 1];
84 : : char *result;
85 : :
1146 peter@eisentraut.org 86 : 2608 : snprintf(buf, sizeof buf, "%X/%X", LSN_FORMAT_ARGS(lsn));
3707 rhaas@postgresql.org 87 : 2608 : result = pstrdup(buf);
88 : 2608 : PG_RETURN_CSTRING(result);
89 : : }
90 : :
91 : : Datum
3707 rhaas@postgresql.org 92 :UBC 0 : pg_lsn_recv(PG_FUNCTION_ARGS)
93 : : {
94 : 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
95 : : XLogRecPtr result;
96 : :
97 : 0 : result = pq_getmsgint64(buf);
98 : 0 : PG_RETURN_LSN(result);
99 : : }
100 : :
101 : : Datum
102 : 0 : pg_lsn_send(PG_FUNCTION_ARGS)
103 : : {
3631 bruce@momjian.us 104 : 0 : XLogRecPtr lsn = PG_GETARG_LSN(0);
105 : : StringInfoData buf;
106 : :
3707 rhaas@postgresql.org 107 : 0 : pq_begintypsend(&buf);
108 : 0 : pq_sendint64(&buf, lsn);
109 : 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
110 : : }
111 : :
112 : :
113 : : /*----------------------------------------------------------
114 : : * Operators for PostgreSQL LSNs
115 : : *---------------------------------------------------------*/
116 : :
117 : : Datum
3707 rhaas@postgresql.org 118 :CBC 22565 : pg_lsn_eq(PG_FUNCTION_ARGS)
119 : : {
3631 bruce@momjian.us 120 : 22565 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
121 : 22565 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
122 : :
3707 rhaas@postgresql.org 123 : 22565 : PG_RETURN_BOOL(lsn1 == lsn2);
124 : : }
125 : :
126 : : Datum
127 : 6 : pg_lsn_ne(PG_FUNCTION_ARGS)
128 : : {
3631 bruce@momjian.us 129 : 6 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
130 : 6 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
131 : :
3707 rhaas@postgresql.org 132 : 6 : PG_RETURN_BOOL(lsn1 != lsn2);
133 : : }
134 : :
135 : : Datum
136 : 67471 : pg_lsn_lt(PG_FUNCTION_ARGS)
137 : : {
3631 bruce@momjian.us 138 : 67471 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
139 : 67471 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
140 : :
3707 rhaas@postgresql.org 141 : 67471 : PG_RETURN_BOOL(lsn1 < lsn2);
142 : : }
143 : :
144 : : Datum
145 : 2249 : pg_lsn_gt(PG_FUNCTION_ARGS)
146 : : {
3631 bruce@momjian.us 147 : 2249 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
148 : 2249 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
149 : :
3707 rhaas@postgresql.org 150 : 2249 : PG_RETURN_BOOL(lsn1 > lsn2);
151 : : }
152 : :
153 : : Datum
154 : 2566 : pg_lsn_le(PG_FUNCTION_ARGS)
155 : : {
3631 bruce@momjian.us 156 : 2566 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
157 : 2566 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
158 : :
3707 rhaas@postgresql.org 159 : 2566 : PG_RETURN_BOOL(lsn1 <= lsn2);
160 : : }
161 : :
162 : : Datum
163 : 1696 : pg_lsn_ge(PG_FUNCTION_ARGS)
164 : : {
3631 bruce@momjian.us 165 : 1696 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
166 : 1696 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
167 : :
3707 rhaas@postgresql.org 168 : 1696 : PG_RETURN_BOOL(lsn1 >= lsn2);
169 : : }
170 : :
171 : : Datum
1745 michael@paquier.xyz 172 : 9 : pg_lsn_larger(PG_FUNCTION_ARGS)
173 : : {
174 : 9 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
175 : 9 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
176 : :
177 : 9 : PG_RETURN_LSN((lsn1 > lsn2) ? lsn1 : lsn2);
178 : : }
179 : :
180 : : Datum
181 : 3 : pg_lsn_smaller(PG_FUNCTION_ARGS)
182 : : {
183 : 3 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
184 : 3 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
185 : :
186 : 3 : PG_RETURN_LSN((lsn1 < lsn2) ? lsn1 : lsn2);
187 : : }
188 : :
189 : : /* btree index opclass support */
190 : : Datum
3602 tgl@sss.pgh.pa.us 191 : 6162 : pg_lsn_cmp(PG_FUNCTION_ARGS)
192 : : {
193 : 6162 : XLogRecPtr a = PG_GETARG_LSN(0);
194 : 6162 : XLogRecPtr b = PG_GETARG_LSN(1);
195 : :
196 [ + + ]: 6162 : if (a > b)
197 : 3131 : PG_RETURN_INT32(1);
198 [ + + ]: 3031 : else if (a == b)
199 : 43 : PG_RETURN_INT32(0);
200 : : else
201 : 2988 : PG_RETURN_INT32(-1);
202 : : }
203 : :
204 : : /* hash index opclass support */
205 : : Datum
206 : 2661 : pg_lsn_hash(PG_FUNCTION_ARGS)
207 : : {
208 : : /* We can use hashint8 directly */
209 : 2661 : return hashint8(fcinfo);
210 : : }
211 : :
212 : : Datum
2418 rhaas@postgresql.org 213 : 30 : pg_lsn_hash_extended(PG_FUNCTION_ARGS)
214 : : {
215 : 30 : return hashint8extended(fcinfo);
216 : : }
217 : :
218 : :
219 : : /*----------------------------------------------------------
220 : : * Arithmetic operators on PostgreSQL LSNs.
221 : : *---------------------------------------------------------*/
222 : :
223 : : Datum
3707 224 : 1969 : pg_lsn_mi(PG_FUNCTION_ARGS)
225 : : {
3631 bruce@momjian.us 226 : 1969 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
227 : 1969 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
228 : : char buf[256];
229 : : Datum result;
230 : :
231 : : /* Output could be as large as plus or minus 2^63 - 1. */
3707 rhaas@postgresql.org 232 [ + + ]: 1969 : if (lsn1 < lsn2)
233 : 26 : snprintf(buf, sizeof buf, "-" UINT64_FORMAT, lsn2 - lsn1);
234 : : else
235 : 1943 : snprintf(buf, sizeof buf, UINT64_FORMAT, lsn1 - lsn2);
236 : :
237 : : /* Convert to numeric. */
238 : 1969 : result = DirectFunctionCall3(numeric_in,
239 : : CStringGetDatum(buf),
240 : : ObjectIdGetDatum(0),
241 : : Int32GetDatum(-1));
242 : :
243 : 1969 : return result;
244 : : }
245 : :
246 : : /*
247 : : * Add the number of bytes to pg_lsn, giving a new pg_lsn.
248 : : * Must handle both positive and negative numbers of bytes.
249 : : */
250 : : Datum
1384 fujii@postgresql.org 251 : 30 : pg_lsn_pli(PG_FUNCTION_ARGS)
252 : : {
253 : 30 : XLogRecPtr lsn = PG_GETARG_LSN(0);
254 : 30 : Numeric nbytes = PG_GETARG_NUMERIC(1);
255 : : Datum num;
256 : : Datum res;
257 : : char buf[32];
258 : :
259 [ + + ]: 30 : if (numeric_is_nan(nbytes))
260 [ + - ]: 3 : ereport(ERROR,
261 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
262 : : errmsg("cannot add NaN to pg_lsn")));
263 : :
264 : : /* Convert to numeric */
265 : 27 : snprintf(buf, sizeof(buf), UINT64_FORMAT, lsn);
266 : 27 : num = DirectFunctionCall3(numeric_in,
267 : : CStringGetDatum(buf),
268 : : ObjectIdGetDatum(0),
269 : : Int32GetDatum(-1));
270 : :
271 : : /* Add two numerics */
272 : 27 : res = DirectFunctionCall2(numeric_add,
273 : : num,
274 : : NumericGetDatum(nbytes));
275 : :
276 : : /* Convert to pg_lsn */
277 : 27 : return DirectFunctionCall1(numeric_pg_lsn, res);
278 : : }
279 : :
280 : : /*
281 : : * Subtract the number of bytes from pg_lsn, giving a new pg_lsn.
282 : : * Must handle both positive and negative numbers of bytes.
283 : : */
284 : : Datum
285 : 18 : pg_lsn_mii(PG_FUNCTION_ARGS)
286 : : {
287 : 18 : XLogRecPtr lsn = PG_GETARG_LSN(0);
288 : 18 : Numeric nbytes = PG_GETARG_NUMERIC(1);
289 : : Datum num;
290 : : Datum res;
291 : : char buf[32];
292 : :
293 [ + + ]: 18 : if (numeric_is_nan(nbytes))
294 [ + - ]: 3 : ereport(ERROR,
295 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
296 : : errmsg("cannot subtract NaN from pg_lsn")));
297 : :
298 : : /* Convert to numeric */
299 : 15 : snprintf(buf, sizeof(buf), UINT64_FORMAT, lsn);
300 : 15 : num = DirectFunctionCall3(numeric_in,
301 : : CStringGetDatum(buf),
302 : : ObjectIdGetDatum(0),
303 : : Int32GetDatum(-1));
304 : :
305 : : /* Subtract two numerics */
306 : 15 : res = DirectFunctionCall2(numeric_sub,
307 : : num,
308 : : NumericGetDatum(nbytes));
309 : :
310 : : /* Convert to pg_lsn */
311 : 15 : return DirectFunctionCall1(numeric_pg_lsn, res);
312 : : }
|