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-2026, 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 "common/pg_parse_lsn.h"
17 : : #include "libpq/pqformat.h"
18 : : #include "utils/fmgrprotos.h"
19 : : #include "utils/numeric.h"
20 : : #include "utils/pg_lsn.h"
21 : :
22 : : #define MAXPG_LSNLEN 17
23 : :
24 : : /*----------------------------------------------------------
25 : : * Formatting and conversion routines.
26 : : *---------------------------------------------------------*/
27 : :
28 : : /*
29 : : * Internal version of pg_lsn_in() with support for soft error reporting.
30 : : */
31 : : XLogRecPtr
356 michael@paquier.xyz 32 :CBC 5338 : pg_lsn_in_safe(const char *str, Node *escontext)
33 : : {
34 : : XLogRecPtr result;
35 : :
15 fujii@postgresql.org 36 [ + + ]:GNC 5338 : if (pg_parse_lsn(str, &result))
37 : 5309 : return result;
38 : :
356 michael@paquier.xyz 39 [ + + ]:CBC 29 : ereturn(escontext, InvalidXLogRecPtr,
40 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
41 : : errmsg("invalid input syntax for type %s: \"%s\"",
42 : : "pg_lsn", str)));
43 : : }
44 : :
45 : : Datum
2615 peter@eisentraut.org 46 : 5330 : pg_lsn_in(PG_FUNCTION_ARGS)
47 : : {
48 : 5330 : char *str = PG_GETARG_CSTRING(0);
49 : : XLogRecPtr result;
50 : :
356 michael@paquier.xyz 51 : 5330 : result = pg_lsn_in_safe(str, fcinfo->context);
52 : :
2615 peter@eisentraut.org 53 : 5309 : PG_RETURN_LSN(result);
54 : : }
55 : :
56 : : Datum
4572 rhaas@postgresql.org 57 : 3881 : pg_lsn_out(PG_FUNCTION_ARGS)
58 : : {
59 : 3881 : XLogRecPtr lsn = PG_GETARG_LSN(0);
60 : : char buf[MAXPG_LSNLEN + 1];
61 : : char *result;
62 : :
416 alvherre@kurilemu.de 63 : 3881 : snprintf(buf, sizeof buf, "%X/%08X", LSN_FORMAT_ARGS(lsn));
4572 rhaas@postgresql.org 64 : 3881 : result = pstrdup(buf);
65 : 3881 : PG_RETURN_CSTRING(result);
66 : : }
67 : :
68 : : Datum
4572 rhaas@postgresql.org 69 :UBC 0 : pg_lsn_recv(PG_FUNCTION_ARGS)
70 : : {
71 : 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
72 : : XLogRecPtr result;
73 : :
74 : 0 : result = pq_getmsgint64(buf);
75 : 0 : PG_RETURN_LSN(result);
76 : : }
77 : :
78 : : Datum
79 : 0 : pg_lsn_send(PG_FUNCTION_ARGS)
80 : : {
4496 bruce@momjian.us 81 : 0 : XLogRecPtr lsn = PG_GETARG_LSN(0);
82 : : StringInfoData buf;
83 : :
4572 rhaas@postgresql.org 84 : 0 : pq_begintypsend(&buf);
85 : 0 : pq_sendint64(&buf, lsn);
86 : 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
87 : : }
88 : :
89 : :
90 : : /*----------------------------------------------------------
91 : : * Operators for PostgreSQL LSNs
92 : : *---------------------------------------------------------*/
93 : :
94 : : Datum
4572 rhaas@postgresql.org 95 :CBC 30080 : pg_lsn_eq(PG_FUNCTION_ARGS)
96 : : {
4496 bruce@momjian.us 97 : 30080 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
98 : 30080 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
99 : :
4572 rhaas@postgresql.org 100 : 30080 : PG_RETURN_BOOL(lsn1 == lsn2);
101 : : }
102 : :
103 : : Datum
104 : 8 : pg_lsn_ne(PG_FUNCTION_ARGS)
105 : : {
4496 bruce@momjian.us 106 : 8 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
107 : 8 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
108 : :
4572 rhaas@postgresql.org 109 : 8 : PG_RETURN_BOOL(lsn1 != lsn2);
110 : : }
111 : :
112 : : Datum
113 : 89965 : pg_lsn_lt(PG_FUNCTION_ARGS)
114 : : {
4496 bruce@momjian.us 115 : 89965 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
116 : 89965 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
117 : :
4572 rhaas@postgresql.org 118 : 89965 : PG_RETURN_BOOL(lsn1 < lsn2);
119 : : }
120 : :
121 : : Datum
122 : 2996 : pg_lsn_gt(PG_FUNCTION_ARGS)
123 : : {
4496 bruce@momjian.us 124 : 2996 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
125 : 2996 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
126 : :
4572 rhaas@postgresql.org 127 : 2996 : PG_RETURN_BOOL(lsn1 > lsn2);
128 : : }
129 : :
130 : : Datum
131 : 3109 : pg_lsn_le(PG_FUNCTION_ARGS)
132 : : {
4496 bruce@momjian.us 133 : 3109 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
134 : 3109 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
135 : :
4572 rhaas@postgresql.org 136 : 3109 : PG_RETURN_BOOL(lsn1 <= lsn2);
137 : : }
138 : :
139 : : Datum
140 : 2256 : pg_lsn_ge(PG_FUNCTION_ARGS)
141 : : {
4496 bruce@momjian.us 142 : 2256 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
143 : 2256 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
144 : :
4572 rhaas@postgresql.org 145 : 2256 : PG_RETURN_BOOL(lsn1 >= lsn2);
146 : : }
147 : :
148 : : Datum
2610 michael@paquier.xyz 149 : 17 : pg_lsn_larger(PG_FUNCTION_ARGS)
150 : : {
151 : 17 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
152 : 17 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
153 : :
154 : 17 : PG_RETURN_LSN((lsn1 > lsn2) ? lsn1 : lsn2);
155 : : }
156 : :
157 : : Datum
158 : 4 : pg_lsn_smaller(PG_FUNCTION_ARGS)
159 : : {
160 : 4 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
161 : 4 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
162 : :
163 : 4 : PG_RETURN_LSN((lsn1 < lsn2) ? lsn1 : lsn2);
164 : : }
165 : :
166 : : /* btree index opclass support */
167 : : Datum
4467 tgl@sss.pgh.pa.us 168 : 8224 : pg_lsn_cmp(PG_FUNCTION_ARGS)
169 : : {
170 : 8224 : XLogRecPtr a = PG_GETARG_LSN(0);
171 : 8224 : XLogRecPtr b = PG_GETARG_LSN(1);
172 : :
173 [ + + ]: 8224 : if (a > b)
174 : 4169 : PG_RETURN_INT32(1);
175 [ + + ]: 4055 : else if (a == b)
176 : 65 : PG_RETURN_INT32(0);
177 : : else
178 : 3990 : PG_RETURN_INT32(-1);
179 : : }
180 : :
181 : : /* hash index opclass support */
182 : : Datum
183 : 3540 : pg_lsn_hash(PG_FUNCTION_ARGS)
184 : : {
185 : : /* We can use hashint8 directly */
186 : 3540 : return hashint8(fcinfo);
187 : : }
188 : :
189 : : Datum
3283 rhaas@postgresql.org 190 : 40 : pg_lsn_hash_extended(PG_FUNCTION_ARGS)
191 : : {
192 : 40 : return hashint8extended(fcinfo);
193 : : }
194 : :
195 : :
196 : : /*----------------------------------------------------------
197 : : * Arithmetic operators on PostgreSQL LSNs.
198 : : *---------------------------------------------------------*/
199 : :
200 : : Datum
4572 201 : 1679 : pg_lsn_mi(PG_FUNCTION_ARGS)
202 : : {
4496 bruce@momjian.us 203 : 1679 : XLogRecPtr lsn1 = PG_GETARG_LSN(0);
204 : 1679 : XLogRecPtr lsn2 = PG_GETARG_LSN(1);
205 : : char buf[256];
206 : : Datum result;
207 : :
208 : : /* Output could be as large as plus or minus 2^63 - 1. */
4572 rhaas@postgresql.org 209 [ + + ]: 1679 : if (lsn1 < lsn2)
210 : 23 : snprintf(buf, sizeof buf, "-" UINT64_FORMAT, lsn2 - lsn1);
211 : : else
212 : 1656 : snprintf(buf, sizeof buf, UINT64_FORMAT, lsn1 - lsn2);
213 : :
214 : : /* Convert to numeric. */
215 : 1679 : result = DirectFunctionCall3(numeric_in,
216 : : CStringGetDatum(buf),
217 : : ObjectIdGetDatum(0),
218 : : Int32GetDatum(-1));
219 : :
220 : 1679 : return result;
221 : : }
222 : :
223 : : /*
224 : : * Add the number of bytes to pg_lsn, giving a new pg_lsn.
225 : : * Must handle both positive and negative numbers of bytes.
226 : : */
227 : : Datum
2249 fujii@postgresql.org 228 : 55 : pg_lsn_pli(PG_FUNCTION_ARGS)
229 : : {
230 : 55 : XLogRecPtr lsn = PG_GETARG_LSN(0);
231 : 55 : Numeric nbytes = PG_GETARG_NUMERIC(1);
232 : : Datum num;
233 : : Datum res;
234 : : char buf[32];
235 : :
236 [ + + ]: 55 : if (numeric_is_nan(nbytes))
237 [ + - ]: 4 : ereport(ERROR,
238 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
239 : : errmsg("cannot add NaN to pg_lsn")));
240 : :
241 : : /* Convert to numeric */
242 : 51 : snprintf(buf, sizeof(buf), UINT64_FORMAT, lsn);
243 : 51 : num = DirectFunctionCall3(numeric_in,
244 : : CStringGetDatum(buf),
245 : : ObjectIdGetDatum(0),
246 : : Int32GetDatum(-1));
247 : :
248 : : /* Add two numerics */
249 : 51 : res = DirectFunctionCall2(numeric_add,
250 : : num,
251 : : NumericGetDatum(nbytes));
252 : :
253 : : /* Convert to pg_lsn */
254 : 51 : return DirectFunctionCall1(numeric_pg_lsn, res);
255 : : }
256 : :
257 : : /*
258 : : * Subtract the number of bytes from pg_lsn, giving a new pg_lsn.
259 : : * Must handle both positive and negative numbers of bytes.
260 : : */
261 : : Datum
262 : 30 : pg_lsn_mii(PG_FUNCTION_ARGS)
263 : : {
264 : 30 : XLogRecPtr lsn = PG_GETARG_LSN(0);
265 : 30 : Numeric nbytes = PG_GETARG_NUMERIC(1);
266 : : Datum num;
267 : : Datum res;
268 : : char buf[32];
269 : :
270 [ + + ]: 30 : if (numeric_is_nan(nbytes))
271 [ + - ]: 4 : ereport(ERROR,
272 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
273 : : errmsg("cannot subtract NaN from pg_lsn")));
274 : :
275 : : /* Convert to numeric */
276 : 26 : snprintf(buf, sizeof(buf), UINT64_FORMAT, lsn);
277 : 26 : num = DirectFunctionCall3(numeric_in,
278 : : CStringGetDatum(buf),
279 : : ObjectIdGetDatum(0),
280 : : Int32GetDatum(-1));
281 : :
282 : : /* Subtract two numerics */
283 : 26 : res = DirectFunctionCall2(numeric_sub,
284 : : num,
285 : : NumericGetDatum(nbytes));
286 : :
287 : : /* Convert to pg_lsn */
288 : 26 : return DirectFunctionCall1(numeric_pg_lsn, res);
289 : : }
|