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 | |
28 | XLogRecPtr |
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 | /* 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 | |
59 | Datum |
60 | pg_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 | |
76 | Datum |
77 | pg_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 | |
94 | Datum |
95 | pg_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 | |
104 | Datum |
105 | pg_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 | |
120 | Datum |
121 | pg_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 | |
129 | Datum |
130 | pg_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 | |
138 | Datum |
139 | pg_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 | |
147 | Datum |
148 | pg_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 | |
156 | Datum |
157 | pg_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 | |
165 | Datum |
166 | pg_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 */ |
175 | Datum |
176 | pg_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 */ |
190 | Datum |
191 | pg_lsn_hash(PG_FUNCTION_ARGS) |
192 | { |
193 | /* We can use hashint8 directly */ |
194 | return hashint8(fcinfo); |
195 | } |
196 | |
197 | Datum |
198 | pg_lsn_hash_extended(PG_FUNCTION_ARGS) |
199 | { |
200 | return hashint8extended(fcinfo); |
201 | } |
202 | |
203 | |
204 | /*---------------------------------------------------------- |
205 | * Arithmetic operators on PostgreSQL LSNs. |
206 | *---------------------------------------------------------*/ |
207 | |
208 | Datum |
209 | pg_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 | |