diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 5f968b0..e79aeef 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -18,7 +18,7 @@ endif
 OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \
 	cash.o char.o date.o datetime.o datum.o domains.o \
 	enum.o float.o format_type.o \
-	geo_ops.o geo_selfuncs.o int.o int8.o like.o lockfuncs.o \
+	geo_ops.o geo_selfuncs.o int.o int8.o like.o lockfuncs.o lsn.o \
 	misc.o nabstime.o name.o numeric.o numutils.o \
 	oid.o oracle_compat.o pseudotypes.o rangetypes.o rangetypes_gist.o \
 	rowtypes.o regexp.o regproc.o ruleutils.o selfuncs.o \
diff --git a/src/backend/utils/adt/lsn.c b/src/backend/utils/adt/lsn.c
new file mode 100644
index 0000000..839ff37
--- /dev/null
+++ b/src/backend/utils/adt/lsn.c
@@ -0,0 +1,189 @@
+/*-------------------------------------------------------------------------
+ *
+ * lsn.c
+ *	  Internal 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/lsn.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "funcapi.h"
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
+#include "utils/lsn.h"
+
+#define MAXINT4LEN		12
+#define MAXINT8LEN		25
+#define MAXLSNLEN		17
+#define MAXLSNCOMPONENT	8
+
+/*----------------------------------------------------------
+ * Formatting and conversion routines.
+ *---------------------------------------------------------*/
+
+Datum
+lsn_in(PG_FUNCTION_ARGS)
+{
+	char	   *str = PG_GETARG_CSTRING(0);
+	int			len1,
+				len2;
+	XLogRecPtr *result;
+
+	/* Sanity check input format. */
+	len1 = strspn(str, "0123456789abcdefABCDEF");
+	if (len1 < 1 || len1 > MAXLSNCOMPONENT || str[len1] != '/')
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				 errmsg("invalid input syntax for lsn: \"%s\"", str)));
+	len2 = strspn(str + len1 + 1, "0123456789abcdefABCDEF");
+	if (len2 < 1 || len2 > MAXLSNCOMPONENT || str[len1 + 1 + len2] != '\0')
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				 errmsg("invalid input syntax for lsn: \"%s\"", str)));
+
+	/* Decode result. */
+	result = palloc(sizeof(XLogRecPtr));
+	result->xlogid = (uint32) strtoul(str, NULL, 16);
+	result->xrecoff = (uint32) strtoul(str + len1 + 1, NULL, 16);
+
+	PG_RETURN_POINTER(result);
+}
+
+Datum
+lsn_out(PG_FUNCTION_ARGS)
+{
+	XLogRecPtr *lsn = (XLogRecPtr *) PG_GETARG_POINTER(0);
+	char		buf[MAXLSNLEN + 1];
+	char	   *result;
+
+	sprintf(buf, "%X/%X", lsn->xlogid, lsn->xrecoff);
+	result = pstrdup(buf);
+	PG_RETURN_CSTRING(result);
+}
+
+Datum
+lsn_recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	XLogRecPtr *result;
+
+	result = palloc(sizeof(XLogRecPtr));
+	result->xlogid = pq_getmsgint(buf, 4);
+	result->xrecoff = pq_getmsgint(buf, 4);
+
+	PG_RETURN_POINTER(result);
+}
+
+Datum
+lsn_send(PG_FUNCTION_ARGS)
+{
+	XLogRecPtr *lsn = (XLogRecPtr *) PG_GETARG_POINTER(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendint(&buf, lsn->xlogid, 4);
+	pq_sendint(&buf, lsn->xrecoff, 4);
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+
+/*----------------------------------------------------------
+ *	Relational operators for LSNs
+ *---------------------------------------------------------*/
+
+Datum
+lsn_eq(PG_FUNCTION_ARGS)
+{
+	XLogRecPtr *lsn1 = (XLogRecPtr *) PG_GETARG_POINTER(0);
+	XLogRecPtr *lsn2 = (XLogRecPtr *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(XLByteEQ(*lsn1, *lsn2));
+}
+
+Datum
+lsn_ne(PG_FUNCTION_ARGS)
+{
+	XLogRecPtr *lsn1 = (XLogRecPtr *) PG_GETARG_POINTER(0);
+	XLogRecPtr *lsn2 = (XLogRecPtr *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(!XLByteEQ(*lsn1, *lsn2));
+}
+
+Datum
+lsn_lt(PG_FUNCTION_ARGS)
+{
+	XLogRecPtr *lsn1 = (XLogRecPtr *) PG_GETARG_POINTER(0);
+	XLogRecPtr *lsn2 = (XLogRecPtr *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(XLByteLT(*lsn1, *lsn2));
+}
+
+Datum
+lsn_gt(PG_FUNCTION_ARGS)
+{
+	XLogRecPtr *lsn1 = (XLogRecPtr *) PG_GETARG_POINTER(0);
+	XLogRecPtr *lsn2 = (XLogRecPtr *) PG_GETARG_POINTER(1);
+
+	/* note order of arguments */
+	PG_RETURN_BOOL(XLByteLT(*lsn2, *lsn1));
+}
+
+Datum
+lsn_le(PG_FUNCTION_ARGS)
+{
+	XLogRecPtr *lsn1 = (XLogRecPtr *) PG_GETARG_POINTER(0);
+	XLogRecPtr *lsn2 = (XLogRecPtr *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(XLByteLE(*lsn1, *lsn2));
+}
+
+Datum
+lsn_ge(PG_FUNCTION_ARGS)
+{
+	XLogRecPtr *lsn1 = (XLogRecPtr *) PG_GETARG_POINTER(0);
+	XLogRecPtr *lsn2 = (XLogRecPtr *) PG_GETARG_POINTER(1);
+
+	/* note order of arguments */
+	PG_RETURN_BOOL(XLByteLE(*lsn2, *lsn1));
+}
+
+
+/*----------------------------------------------------------
+ *	Arithmetic operators on LSNs.
+ *---------------------------------------------------------*/
+
+Datum
+lsn_mi(PG_FUNCTION_ARGS)
+{
+	XLogRecPtr *lsn1 = (XLogRecPtr *) PG_GETARG_POINTER(0);
+	XLogRecPtr *lsn2 = (XLogRecPtr *) PG_GETARG_POINTER(1);
+	uint64		v1;
+	uint64		v2;
+	char		buf[256];
+	Datum		result;
+
+	/* Flatten values to 64-bit unsigned integers. */
+	v1 = (((uint64) lsn1->xlogid) << 32) | ((uint64) lsn1->xrecoff);
+	v2 = (((uint64) lsn2->xlogid) << 32) | ((uint64) lsn2->xrecoff);
+
+	/* Negative results are not allowed. */
+	if (v1 < v2)
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("LSN out of range")));
+
+	/* Convert to numeric. */
+	sprintf(buf, UINT64_FORMAT, v1 - v2);
+	result = DirectFunctionCall3(numeric_in,
+								 CStringGetDatum(buf),
+								 ObjectIdGetDatum(0),
+								 Int32GetDatum(-1));
+
+	return result;
+}
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index eac5cb9..07b8f63 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1578,6 +1578,22 @@ DESCR("less than or equal");
 DATA(insert OID = 2977 (  ">="	   PGNSP PGUID b f f 2950 2950 16 2976 2974 uuid_ge scalargtsel scalargtjoinsel ));
 DESCR("greater than or equal");
 
+/* lsn operators */
+DATA(insert OID = 3788 (  "="	   PGNSP PGUID b f f 3813 3813 16 3788 3789 lsn_eq eqsel eqjoinsel ));
+DESCR("equal");
+DATA(insert OID = 3789 (  "<>"	   PGNSP PGUID b f f 3813 3813 16 3789 3788 lsn_ne neqsel neqjoinsel ));
+DESCR("not equal");
+DATA(insert OID = 3790 (  "<"	   PGNSP PGUID b f f 3813 3813 16 3791 3793 lsn_lt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+DATA(insert OID = 3791 (  ">"	   PGNSP PGUID b f f 3813 3813 16 3790 3792 lsn_gt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+DATA(insert OID = 3792 (  "<="	   PGNSP PGUID b f f 3813 3813 16 3793 3791 lsn_le scalarltsel scalarltjoinsel ));
+DESCR("less than or equal");
+DATA(insert OID = 3793 (  ">="	   PGNSP PGUID b f f 3813 3813 16 3792 3790 lsn_ge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
+DATA(insert OID = 3795 (  "-"	   PGNSP PGUID b f f 3813 3813 1700    0	0 lsn_mi - - ));
+DESCR("minus");
+
 /* enum operators */
 DATA(insert OID = 3516 (  "="	   PGNSP PGUID b t t 3500 3500 16 3516 3517 enum_eq eqsel eqjoinsel ));
 DESCR("equal");
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 28e53b7..0ddc956 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3983,6 +3983,23 @@ DESCR("I/O");
 DATA(insert OID = 2963 (  uuid_hash		   PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 23 "2950" _null_ _null_ _null_ _null_ uuid_hash _null_ _null_ _null_ ));
 DESCR("hash");
 
+/* lsn */
+DATA(insert OID = 3778 (  lsn_in		   PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 3813 "2275" _null_ _null_ _null_ _null_ lsn_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3779 (  lsn_out		   PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 2275 "3813" _null_ _null_ _null_ _null_ lsn_out _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3780 (  lsn_lt		   PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "3813 3813" _null_ _null_ _null_ _null_ lsn_lt _null_ _null_ _null_ ));
+DATA(insert OID = 3781 (  lsn_le		   PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "3813 3813" _null_ _null_ _null_ _null_ lsn_le _null_ _null_ _null_ ));
+DATA(insert OID = 3782 (  lsn_eq		   PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "3813 3813" _null_ _null_ _null_ _null_ lsn_eq _null_ _null_ _null_ ));
+DATA(insert OID = 3783 (  lsn_ge		   PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "3813 3813" _null_ _null_ _null_ _null_ lsn_ge _null_ _null_ _null_ ));
+DATA(insert OID = 3784 (  lsn_gt		   PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "3813 3813" _null_ _null_ _null_ _null_ lsn_gt _null_ _null_ _null_ ));
+DATA(insert OID = 3785 (  lsn_ne		   PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "3813 3813" _null_ _null_ _null_ _null_ lsn_ne _null_ _null_ _null_ ));
+DATA(insert OID = 3794 (  lsn_mi		   PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 1700 "3813 3813" _null_ _null_ _null_ _null_ lsn_mi _null_ _null_ _null_ ));
+DATA(insert OID = 3786 (  lsn_recv		   PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 3813 "2281" _null_ _null_ _null_ _null_ lsn_recv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3787 (  lsn_send		   PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 17 "3813" _null_ _null_ _null_ _null_ lsn_send _null_ _null_ _null_ ));
+DESCR("I/O");
+
 /* enum related procs */
 DATA(insert OID = 3504 (  anyenum_in	PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 3500 "2275" _null_ _null_ _null_ _null_ anyenum_in _null_ _null_ _null_ ));
 DESCR("I/O");
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 406241a..aec9a24 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -565,6 +565,11 @@ DATA(insert OID = 2950 ( uuid			PGNSP PGUID 16 f b U f t \054 0 0 2951 uuid_in u
 DESCR("UUID datatype");
 DATA(insert OID = 2951 ( _uuid			PGNSP PGUID -1 f b A f t \054 0 2950 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
 
+/* lsn */
+DATA(insert OID = 3813 ( lsn			PGNSP PGUID 16 f b U f t \054 0 0 3814 lsn_in lsn_out lsn_recv lsn_send - - - i p f 0 -1 0 0 _null_ _null_ ));
+DESCR("LSN datatype");
+DATA(insert OID = 3814 ( _lsn			PGNSP PGUID -1 f b A f t \054 0 3813 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
+
 /* text search */
 DATA(insert OID = 3614 ( tsvector		PGNSP PGUID -1 f b U f t \054 0 0 3643 tsvectorin tsvectorout tsvectorrecv tsvectorsend - - ts_typanalyze i x f 0 -1 0 0 _null_ _null_ ));
 DESCR("text representation for text search");
diff --git a/src/include/utils/lsn.h b/src/include/utils/lsn.h
new file mode 100644
index 0000000..7e4be7b
--- /dev/null
+++ b/src/include/utils/lsn.h
@@ -0,0 +1,33 @@
+/*-------------------------------------------------------------------------
+ *
+ * lsn.h
+ *	  Declarations for operations on log sequence numbers (LSNs).
+ *
+ *
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/utils/lsn.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef LSN_H
+#define LSN_H
+
+#include "fmgr.h"
+
+extern Datum lsn_in(PG_FUNCTION_ARGS);
+extern Datum lsn_out(PG_FUNCTION_ARGS);
+extern Datum lsn_recv(PG_FUNCTION_ARGS);
+extern Datum lsn_send(PG_FUNCTION_ARGS);
+
+extern Datum lsn_eq(PG_FUNCTION_ARGS);
+extern Datum lsn_ne(PG_FUNCTION_ARGS);
+extern Datum lsn_lt(PG_FUNCTION_ARGS);
+extern Datum lsn_gt(PG_FUNCTION_ARGS);
+extern Datum lsn_le(PG_FUNCTION_ARGS);
+extern Datum lsn_ge(PG_FUNCTION_ARGS);
+
+extern Datum lsn_mi(PG_FUNCTION_ARGS);
+
+#endif   /* LSN_H */