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