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