PostgreSQL Source Code  git master
pg_lsn.c
Go to the documentation of this file.
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 
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
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  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 
76  PG_RETURN_LSN(result);
77 }
78 
79 Datum
81 {
82  XLogRecPtr lsn = PG_GETARG_LSN(0);
83  char buf[MAXPG_LSNLEN + 1];
84  char *result;
85 
86  snprintf(buf, sizeof buf, "%X/%X", LSN_FORMAT_ARGS(lsn));
87  result = pstrdup(buf);
88  PG_RETURN_CSTRING(result);
89 }
90 
91 Datum
93 {
95  XLogRecPtr result;
96 
97  result = pq_getmsgint64(buf);
98  PG_RETURN_LSN(result);
99 }
100 
101 Datum
103 {
104  XLogRecPtr lsn = PG_GETARG_LSN(0);
106 
108  pq_sendint64(&buf, lsn);
110 }
111 
112 
113 /*----------------------------------------------------------
114  * Operators for PostgreSQL LSNs
115  *---------------------------------------------------------*/
116 
117 Datum
119 {
120  XLogRecPtr lsn1 = PG_GETARG_LSN(0);
121  XLogRecPtr lsn2 = PG_GETARG_LSN(1);
122 
123  PG_RETURN_BOOL(lsn1 == lsn2);
124 }
125 
126 Datum
128 {
129  XLogRecPtr lsn1 = PG_GETARG_LSN(0);
130  XLogRecPtr lsn2 = PG_GETARG_LSN(1);
131 
132  PG_RETURN_BOOL(lsn1 != lsn2);
133 }
134 
135 Datum
137 {
138  XLogRecPtr lsn1 = PG_GETARG_LSN(0);
139  XLogRecPtr lsn2 = PG_GETARG_LSN(1);
140 
141  PG_RETURN_BOOL(lsn1 < lsn2);
142 }
143 
144 Datum
146 {
147  XLogRecPtr lsn1 = PG_GETARG_LSN(0);
148  XLogRecPtr lsn2 = PG_GETARG_LSN(1);
149 
150  PG_RETURN_BOOL(lsn1 > lsn2);
151 }
152 
153 Datum
155 {
156  XLogRecPtr lsn1 = PG_GETARG_LSN(0);
157  XLogRecPtr lsn2 = PG_GETARG_LSN(1);
158 
159  PG_RETURN_BOOL(lsn1 <= lsn2);
160 }
161 
162 Datum
164 {
165  XLogRecPtr lsn1 = PG_GETARG_LSN(0);
166  XLogRecPtr lsn2 = PG_GETARG_LSN(1);
167 
168  PG_RETURN_BOOL(lsn1 >= lsn2);
169 }
170 
171 Datum
173 {
174  XLogRecPtr lsn1 = PG_GETARG_LSN(0);
175  XLogRecPtr lsn2 = PG_GETARG_LSN(1);
176 
177  PG_RETURN_LSN((lsn1 > lsn2) ? lsn1 : lsn2);
178 }
179 
180 Datum
182 {
183  XLogRecPtr lsn1 = PG_GETARG_LSN(0);
184  XLogRecPtr lsn2 = PG_GETARG_LSN(1);
185 
186  PG_RETURN_LSN((lsn1 < lsn2) ? lsn1 : lsn2);
187 }
188 
189 /* btree index opclass support */
190 Datum
192 {
195 
196  if (a > b)
197  PG_RETURN_INT32(1);
198  else if (a == b)
199  PG_RETURN_INT32(0);
200  else
201  PG_RETURN_INT32(-1);
202 }
203 
204 /* hash index opclass support */
205 Datum
207 {
208  /* We can use hashint8 directly */
209  return hashint8(fcinfo);
210 }
211 
212 Datum
214 {
215  return hashint8extended(fcinfo);
216 }
217 
218 
219 /*----------------------------------------------------------
220  * Arithmetic operators on PostgreSQL LSNs.
221  *---------------------------------------------------------*/
222 
223 Datum
225 {
226  XLogRecPtr lsn1 = PG_GETARG_LSN(0);
227  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. */
232  if (lsn1 < lsn2)
233  snprintf(buf, sizeof buf, "-" UINT64_FORMAT, lsn2 - lsn1);
234  else
235  snprintf(buf, sizeof buf, UINT64_FORMAT, lsn1 - lsn2);
236 
237  /* Convert to numeric. */
240  ObjectIdGetDatum(0),
241  Int32GetDatum(-1));
242 
243  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
252 {
253  XLogRecPtr lsn = PG_GETARG_LSN(0);
254  Numeric nbytes = PG_GETARG_NUMERIC(1);
255  Datum num;
256  Datum res;
257  char buf[32];
258 
259  if (numeric_is_nan(nbytes))
260  ereport(ERROR,
261  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
262  errmsg("cannot add NaN to pg_lsn")));
263 
264  /* Convert to numeric */
265  snprintf(buf, sizeof(buf), UINT64_FORMAT, lsn);
268  ObjectIdGetDatum(0),
269  Int32GetDatum(-1));
270 
271  /* Add two numerics */
273  num,
274  NumericGetDatum(nbytes));
275 
276  /* Convert to pg_lsn */
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
286 {
287  XLogRecPtr lsn = PG_GETARG_LSN(0);
288  Numeric nbytes = PG_GETARG_NUMERIC(1);
289  Datum num;
290  Datum res;
291  char buf[32];
292 
293  if (numeric_is_nan(nbytes))
294  ereport(ERROR,
295  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
296  errmsg("cannot subtract NaN from pg_lsn")));
297 
298  /* Convert to numeric */
299  snprintf(buf, sizeof(buf), UINT64_FORMAT, lsn);
302  ObjectIdGetDatum(0),
303  Int32GetDatum(-1));
304 
305  /* Subtract two numerics */
307  num,
308  NumericGetDatum(nbytes));
309 
310  /* Convert to pg_lsn */
312 }
Datum numeric_sub(PG_FUNCTION_ARGS)
Definition: numeric.c:2923
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:626
bool numeric_is_nan(Numeric num)
Definition: numeric.c:840
Datum numeric_add(PG_FUNCTION_ARGS)
Definition: numeric.c:2846
Datum numeric_pg_lsn(PG_FUNCTION_ARGS)
Definition: numeric.c:4698
unsigned int uint32
Definition: c.h:493
#define UINT64_FORMAT
Definition: c.h:536
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ereturn(context, dummy_value,...)
Definition: elog.h:276
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:644
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:646
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
Datum hashint8extended(PG_FUNCTION_ARGS)
Definition: hashfunc.c:103
Datum hashint8(PG_FUNCTION_ARGS)
Definition: hashfunc.c:83
int b
Definition: isn.c:70
int a
Definition: isn.c:69
Assert(fmt[strlen(fmt) - 1] !='\n')
char * pstrdup(const char *in)
Definition: mcxt.c:1683
#define PG_GETARG_NUMERIC(n)
Definition: numeric.h:77
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:72
Datum pg_lsn_ne(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:127
Datum pg_lsn_eq(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:118
Datum pg_lsn_cmp(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:191
#define MAXPG_LSNLEN
Definition: pg_lsn.c:21
Datum pg_lsn_out(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:80
Datum pg_lsn_smaller(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:181
Datum pg_lsn_send(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:102
XLogRecPtr pg_lsn_in_internal(const char *str, bool *have_error)
Definition: pg_lsn.c:29
#define MAXPG_LSNCOMPONENT
Definition: pg_lsn.c:22
Datum pg_lsn_le(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:154
Datum pg_lsn_in(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:63
Datum pg_lsn_pli(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:251
Datum pg_lsn_mii(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:285
Datum pg_lsn_hash(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:206
Datum pg_lsn_ge(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:163
Datum pg_lsn_hash_extended(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:213
Datum pg_lsn_gt(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:145
Datum pg_lsn_larger(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:172
Datum pg_lsn_recv(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:92
Datum pg_lsn_mi(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:224
Datum pg_lsn_lt(PG_FUNCTION_ARGS)
Definition: pg_lsn.c:136
#define PG_GETARG_LSN(n)
Definition: pg_lsn.h:33
#define PG_RETURN_LSN(x)
Definition: pg_lsn.h:34
static char * buf
Definition: pg_test_fsync.c:73
#define snprintf
Definition: port.h:238
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:326
int64 pq_getmsgint64(StringInfo msg)
Definition: pqformat.c:453
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:346
static void pq_sendint64(StringInfo buf, uint64 i)
Definition: pqformat.h:152
StringInfoData * StringInfo
Definition: stringinfo.h:54
#define LSN_FORMAT_ARGS(lsn)
Definition: xlogdefs.h:43
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28