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