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