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