diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:46:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:46:48 +0000 |
commit | 311bcfc6b3acdd6fd152798c7f287ddf74fa2a98 (patch) | |
tree | 0ec307299b1dada3701e42f4ca6eda57d708261e /src/backend/utils/adt/pg_lsn.c | |
parent | Initial commit. (diff) | |
download | postgresql-15-upstream.tar.xz postgresql-15-upstream.zip |
Adding upstream version 15.4.upstream/15.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/backend/utils/adt/pg_lsn.c')
-rw-r--r-- | src/backend/utils/adt/pg_lsn.c | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/src/backend/utils/adt/pg_lsn.c b/src/backend/utils/adt/pg_lsn.c new file mode 100644 index 0000000..4540878 --- /dev/null +++ b/src/backend/utils/adt/pg_lsn.c @@ -0,0 +1,313 @@ +/*------------------------------------------------------------------------- + * + * pg_lsn.c + * Operations for the pg_lsn datatype. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/utils/adt/pg_lsn.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "funcapi.h" +#include "libpq/pqformat.h" +#include "utils/builtins.h" +#include "utils/numeric.h" +#include "utils/pg_lsn.h" + +#define MAXPG_LSNLEN 17 +#define MAXPG_LSNCOMPONENT 8 + +/*---------------------------------------------------------- + * Formatting and conversion routines. + *---------------------------------------------------------*/ + +XLogRecPtr +pg_lsn_in_internal(const char *str, bool *have_error) +{ + int len1, + len2; + uint32 id, + off; + XLogRecPtr result; + + Assert(have_error != NULL); + *have_error = false; + + /* Sanity check input format. */ + len1 = strspn(str, "0123456789abcdefABCDEF"); + if (len1 < 1 || len1 > MAXPG_LSNCOMPONENT || str[len1] != '/') + { + *have_error = true; + return InvalidXLogRecPtr; + } + len2 = strspn(str + len1 + 1, "0123456789abcdefABCDEF"); + if (len2 < 1 || len2 > MAXPG_LSNCOMPONENT || str[len1 + 1 + len2] != '\0') + { + *have_error = true; + return InvalidXLogRecPtr; + } + + /* Decode result. */ + id = (uint32) strtoul(str, NULL, 16); + off = (uint32) strtoul(str + len1 + 1, NULL, 16); + result = ((uint64) id << 32) | off; + + return result; +} + +Datum +pg_lsn_in(PG_FUNCTION_ARGS) +{ + char *str = PG_GETARG_CSTRING(0); + XLogRecPtr result; + bool have_error = false; + + result = pg_lsn_in_internal(str, &have_error); + if (have_error) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "pg_lsn", str))); + + PG_RETURN_LSN(result); +} + +Datum +pg_lsn_out(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn = PG_GETARG_LSN(0); + char buf[MAXPG_LSNLEN + 1]; + char *result; + + snprintf(buf, sizeof buf, "%X/%X", LSN_FORMAT_ARGS(lsn)); + result = pstrdup(buf); + PG_RETURN_CSTRING(result); +} + +Datum +pg_lsn_recv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + XLogRecPtr result; + + result = pq_getmsgint64(buf); + PG_RETURN_LSN(result); +} + +Datum +pg_lsn_send(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn = PG_GETARG_LSN(0); + StringInfoData buf; + + pq_begintypsend(&buf); + pq_sendint64(&buf, lsn); + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} + + +/*---------------------------------------------------------- + * Operators for PostgreSQL LSNs + *---------------------------------------------------------*/ + +Datum +pg_lsn_eq(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn1 = PG_GETARG_LSN(0); + XLogRecPtr lsn2 = PG_GETARG_LSN(1); + + PG_RETURN_BOOL(lsn1 == lsn2); +} + +Datum +pg_lsn_ne(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn1 = PG_GETARG_LSN(0); + XLogRecPtr lsn2 = PG_GETARG_LSN(1); + + PG_RETURN_BOOL(lsn1 != lsn2); +} + +Datum +pg_lsn_lt(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn1 = PG_GETARG_LSN(0); + XLogRecPtr lsn2 = PG_GETARG_LSN(1); + + PG_RETURN_BOOL(lsn1 < lsn2); +} + +Datum +pg_lsn_gt(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn1 = PG_GETARG_LSN(0); + XLogRecPtr lsn2 = PG_GETARG_LSN(1); + + PG_RETURN_BOOL(lsn1 > lsn2); +} + +Datum +pg_lsn_le(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn1 = PG_GETARG_LSN(0); + XLogRecPtr lsn2 = PG_GETARG_LSN(1); + + PG_RETURN_BOOL(lsn1 <= lsn2); +} + +Datum +pg_lsn_ge(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn1 = PG_GETARG_LSN(0); + XLogRecPtr lsn2 = PG_GETARG_LSN(1); + + PG_RETURN_BOOL(lsn1 >= lsn2); +} + +Datum +pg_lsn_larger(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn1 = PG_GETARG_LSN(0); + XLogRecPtr lsn2 = PG_GETARG_LSN(1); + + PG_RETURN_LSN((lsn1 > lsn2) ? lsn1 : lsn2); +} + +Datum +pg_lsn_smaller(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn1 = PG_GETARG_LSN(0); + XLogRecPtr lsn2 = PG_GETARG_LSN(1); + + PG_RETURN_LSN((lsn1 < lsn2) ? lsn1 : lsn2); +} + +/* btree index opclass support */ +Datum +pg_lsn_cmp(PG_FUNCTION_ARGS) +{ + XLogRecPtr a = PG_GETARG_LSN(0); + XLogRecPtr b = PG_GETARG_LSN(1); + + if (a > b) + PG_RETURN_INT32(1); + else if (a == b) + PG_RETURN_INT32(0); + else + PG_RETURN_INT32(-1); +} + +/* hash index opclass support */ +Datum +pg_lsn_hash(PG_FUNCTION_ARGS) +{ + /* We can use hashint8 directly */ + return hashint8(fcinfo); +} + +Datum +pg_lsn_hash_extended(PG_FUNCTION_ARGS) +{ + return hashint8extended(fcinfo); +} + + +/*---------------------------------------------------------- + * Arithmetic operators on PostgreSQL LSNs. + *---------------------------------------------------------*/ + +Datum +pg_lsn_mi(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn1 = PG_GETARG_LSN(0); + XLogRecPtr lsn2 = PG_GETARG_LSN(1); + char buf[256]; + Datum result; + + /* Output could be as large as plus or minus 2^63 - 1. */ + if (lsn1 < lsn2) + snprintf(buf, sizeof buf, "-" UINT64_FORMAT, lsn2 - lsn1); + else + snprintf(buf, sizeof buf, UINT64_FORMAT, lsn1 - lsn2); + + /* Convert to numeric. */ + result = DirectFunctionCall3(numeric_in, + CStringGetDatum(buf), + ObjectIdGetDatum(0), + Int32GetDatum(-1)); + + return result; +} + +/* + * Add the number of bytes to pg_lsn, giving a new pg_lsn. + * Must handle both positive and negative numbers of bytes. + */ +Datum +pg_lsn_pli(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn = PG_GETARG_LSN(0); + Numeric nbytes = PG_GETARG_NUMERIC(1); + Datum num; + Datum res; + char buf[32]; + + if (numeric_is_nan(nbytes)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot add NaN to pg_lsn"))); + + /* Convert to numeric */ + snprintf(buf, sizeof(buf), UINT64_FORMAT, lsn); + num = DirectFunctionCall3(numeric_in, + CStringGetDatum(buf), + ObjectIdGetDatum(0), + Int32GetDatum(-1)); + + /* Add two numerics */ + res = DirectFunctionCall2(numeric_add, + NumericGetDatum(num), + NumericGetDatum(nbytes)); + + /* Convert to pg_lsn */ + return DirectFunctionCall1(numeric_pg_lsn, res); +} + +/* + * Subtract the number of bytes from pg_lsn, giving a new pg_lsn. + * Must handle both positive and negative numbers of bytes. + */ +Datum +pg_lsn_mii(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn = PG_GETARG_LSN(0); + Numeric nbytes = PG_GETARG_NUMERIC(1); + Datum num; + Datum res; + char buf[32]; + + if (numeric_is_nan(nbytes)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot subtract NaN from pg_lsn"))); + + /* Convert to numeric */ + snprintf(buf, sizeof(buf), UINT64_FORMAT, lsn); + num = DirectFunctionCall3(numeric_in, + CStringGetDatum(buf), + ObjectIdGetDatum(0), + Int32GetDatum(-1)); + + /* Subtract two numerics */ + res = DirectFunctionCall2(numeric_sub, + NumericGetDatum(num), + NumericGetDatum(nbytes)); + + /* Convert to pg_lsn */ + return DirectFunctionCall1(numeric_pg_lsn, res); +} |