aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/pg_lsn.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2014-02-19 08:35:23 -0500
committerRobert Haas <rhaas@postgresql.org>2014-02-19 08:35:23 -0500
commit7d03a83f4d0736ba869fa6f93973f7623a27038a (patch)
treed1d7f36c742fcea38edbbf7eb623cca2a52c1378 /src/backend/utils/adt/pg_lsn.c
parenta222f7fda6a04ab8ec655cd5a9de5ff70ff916c3 (diff)
downloadpostgresql-7d03a83f4d0736ba869fa6f93973f7623a27038a.tar.gz
postgresql-7d03a83f4d0736ba869fa6f93973f7623a27038a.zip
Add a pg_lsn data type, to represent an LSN.
Robert Haas and Michael Paquier
Diffstat (limited to 'src/backend/utils/adt/pg_lsn.c')
-rw-r--r--src/backend/utils/adt/pg_lsn.c180
1 files changed, 180 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 00000000000..39e22931362
--- /dev/null
+++ b/src/backend/utils/adt/pg_lsn.c
@@ -0,0 +1,180 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_lsn.c
+ * Internal PostgreSQL LSN operations
+ *
+ * Portions Copyright (c) 1996-2011, 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/pg_lsn.h"
+
+#define MAXPG_LSNLEN 17
+#define MAXPG_LSNCOMPONENT 8
+
+/*----------------------------------------------------------
+ * Formatting and conversion routines.
+ *---------------------------------------------------------*/
+
+Datum
+pg_lsn_in(PG_FUNCTION_ARGS)
+{
+ char *str = PG_GETARG_CSTRING(0);
+ int len1, len2;
+ uint32 id, off;
+ XLogRecPtr result;
+
+ /* Sanity check input format. */
+ len1 = strspn(str, "0123456789abcdefABCDEF");
+ if (len1 < 1 || len1 > MAXPG_LSNCOMPONENT || str[len1] != '/')
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid input syntax for transaction log location: \"%s\"", str)));
+ len2 = strspn(str + len1 + 1, "0123456789abcdefABCDEF");
+ if (len2 < 1 || len2 > MAXPG_LSNCOMPONENT || str[len1 + 1 + len2] != '\0')
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid input syntax for transaction log location: \"%s\"", str)));
+
+ /* Decode result. */
+ id = (uint32) strtoul(str, NULL, 16);
+ off = (uint32) strtoul(str + len1 + 1, NULL, 16);
+ result = (XLogRecPtr) ((uint64) id << 32) | off;
+
+ PG_RETURN_PG_LSN(result);
+}
+
+Datum
+pg_lsn_out(PG_FUNCTION_ARGS)
+{
+ XLogRecPtr lsn = (XLogRecPtr) PG_GETARG_PG_LSN(0);
+ char buf[MAXPG_LSNLEN + 1];
+ char *result;
+ uint32 id, off;
+
+ /* Decode ID and offset */
+ id = (uint32) (lsn >> 32);
+ off = (uint32) lsn;
+
+ snprintf(buf, sizeof buf, "%X/%X", id, off);
+ 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_PG_LSN(result);
+}
+
+Datum
+pg_lsn_send(PG_FUNCTION_ARGS)
+{
+ XLogRecPtr lsn = (XLogRecPtr) PG_GETARG_PG_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 = (XLogRecPtr) PG_GETARG_PG_LSN(0);
+ XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_PG_LSN(1);
+
+ PG_RETURN_BOOL(lsn1 == lsn2);
+}
+
+Datum
+pg_lsn_ne(PG_FUNCTION_ARGS)
+{
+ XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_PG_LSN(0);
+ XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_PG_LSN(1);
+
+ PG_RETURN_BOOL(lsn1 != lsn2);
+}
+
+Datum
+pg_lsn_lt(PG_FUNCTION_ARGS)
+{
+ XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_PG_LSN(0);
+ XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_PG_LSN(1);
+
+ PG_RETURN_BOOL(lsn1 < lsn2);
+}
+
+Datum
+pg_lsn_gt(PG_FUNCTION_ARGS)
+{
+ XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_PG_LSN(0);
+ XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_PG_LSN(1);
+
+ PG_RETURN_BOOL(lsn1 > lsn2);
+}
+
+Datum
+pg_lsn_le(PG_FUNCTION_ARGS)
+{
+ XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_PG_LSN(0);
+ XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_PG_LSN(1);
+
+ PG_RETURN_BOOL(lsn1 <= lsn2);
+}
+
+Datum
+pg_lsn_ge(PG_FUNCTION_ARGS)
+{
+ XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_PG_LSN(0);
+ XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_PG_LSN(1);
+
+ PG_RETURN_BOOL(lsn1 >= lsn2);
+}
+
+
+/*----------------------------------------------------------
+ * Arithmetic operators on PostgreSQL LSNs.
+ *---------------------------------------------------------*/
+
+Datum
+pg_lsn_mi(PG_FUNCTION_ARGS)
+{
+ XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_PG_LSN(0);
+ XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_PG_LSN(1);
+ char buf[256];
+ Datum result;
+
+ /* Negative results are not allowed. */
+ if (lsn1 < lsn2)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("transaction log location out of range")));
+
+ /* Convert to numeric. */
+ snprintf(buf, sizeof buf, UINT64_FORMAT, lsn1 - lsn2);
+ result = DirectFunctionCall3(numeric_in,
+ CStringGetDatum(buf),
+ ObjectIdGetDatum(0),
+ Int32GetDatum(-1));
+
+ return result;
+}