On Tue, Feb 4, 2014 at 10:10 AM, Tom Lane <t...@sss.pgh.pa.us> wrote:
> Michael Paquier <michael.paqu...@gmail.com> writes:
>> Please find attached a patch implementing lsn as a datatype, based on
>> the one Robert wrote a couple of years ago.
>
>> Patch contains regression tests as well as a bit of documentation.
>> Perhaps this is too late for 9.4, so if there are no objections I'll
>> simply add this patch to the next commit fest in June for 9.5.
>
> I may have lost count, but aren't a bunch of the affected functions new
> in 9.4?  If so, there's a good argument to be made that we should get
> this in now, rather than waiting and having an API change for those
> functions in 9.5.
Cool... I have created a second patch that updates all the system
functions to use the new lsn datatype introduced in the 1st patch
(pg_start|stop_backup, replication_slot stuff, xlog diff things, etc.)
and it is attached. This cleans up quite a bit of code in xlogfuncs.c
because we do not need anymore the LSN <-> cstring transformations!
I am also attaching a v2 of the first patch, I noticed that lsn_in
introduced in the first patch was using some error messages not
consistent with the ones of validate_xlog_location:xlogfuncs.c. Note
as well that validate_xlog_location is removed in the 2nd patch where
all the system functions are swicthed to the new datatype.
Regards,
-- 
Michael
*** a/doc/src/sgml/datatype.sgml
--- b/doc/src/sgml/datatype.sgml
***************
*** 155,160 ****
--- 155,166 ----
        </row>
  
        <row>
+        <entry><type>lsn</type></entry>
+        <entry></entry>
+        <entry>Log Sequence Number</entry>
+       </row>
+ 
+       <row>
         <entry><type>macaddr</type></entry>
         <entry></entry>
         <entry>MAC (Media Access Control) address</entry>
***************
*** 4502,4507 **** SELECT * FROM pg_attribute
--- 4508,4527 ----
     </para>
    </sect1>
  
+   <sect1 id="datatype-lsn">
+    <title><acronym>LSN</> Type</title>
+ 
+    <indexterm zone="datatype-lsn">
+     <primary>LSN</primary>
+    </indexterm>
+ 
+    <para>
+     The <type>lsn</type> data type can be used to store LSN (Log Sequence
+     Number) data which is a pointer to a location in the XLOG. This type is a
+     representation of XLogRecPtr.
+    </para>
+   </sect1>
+ 
    <sect1 id="datatype-pseudo">
     <title>Pseudo-Types</title>
  
*** a/src/backend/utils/adt/Makefile
--- b/src/backend/utils/adt/Makefile
***************
*** 20,26 **** OBJS = acl.o arrayfuncs.o array_selfuncs.o array_typanalyze.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 json.o jsonfuncs.o like.o \
! 	lockfuncs.o misc.o nabstime.o name.o numeric.o numutils.o \
  	oid.o oracle_compat.o orderedsetaggs.o \
  	pseudotypes.o rangetypes.o rangetypes_gist.o \
  	rowtypes.o regexp.o regproc.o ruleutils.o selfuncs.o \
--- 20,26 ----
  	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 json.o jsonfuncs.o like.o \
! 	lockfuncs.o lsn.o misc.o nabstime.o name.o numeric.o numutils.o \
  	oid.o oracle_compat.o orderedsetaggs.o \
  	pseudotypes.o rangetypes.o rangetypes_gist.o \
  	rowtypes.o regexp.o regproc.o ruleutils.o selfuncs.o \
*** /dev/null
--- b/src/backend/utils/adt/lsn.c
***************
*** 0 ****
--- 1,180 ----
+ /*-------------------------------------------------------------------------
+  *
+  * 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 MAXLSNLEN		17
+ #define MAXLSNCOMPONENT	8
+ 
+ /*----------------------------------------------------------
+  * Formatting and conversion routines.
+  *---------------------------------------------------------*/
+ 
+ Datum
+ 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 > MAXLSNCOMPONENT || 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 > MAXLSNCOMPONENT || 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_LSN(result);
+ }
+ 
+ Datum
+ lsn_out(PG_FUNCTION_ARGS)
+ {
+ 	XLogRecPtr	lsn = (XLogRecPtr) PG_GETARG_LSN(0);
+ 	char		buf[MAXLSNLEN + 1];
+ 	char	   *result;
+ 	uint32		id, off;
+ 
+ 	/* Decode ID and offset */
+ 	id = (uint32) (lsn >> 32);
+ 	off = (uint32) lsn;
+ 
+ 	sprintf(buf, "%X/%X", id, off);
+ 	result = pstrdup(buf);
+ 	PG_RETURN_CSTRING(result);
+ }
+ 
+ Datum
+ lsn_recv(PG_FUNCTION_ARGS)
+ {
+ 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+ 	XLogRecPtr	result;
+ 
+ 	result = pq_getmsgint64(buf);
+ 	PG_RETURN_LSN(result);
+ }
+ 
+ Datum
+ lsn_send(PG_FUNCTION_ARGS)
+ {
+ 	XLogRecPtr lsn = (XLogRecPtr) PG_GETARG_LSN(0);
+ 	StringInfoData buf;
+ 
+ 	pq_begintypsend(&buf);
+ 	pq_sendint64(&buf, lsn);
+ 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+ }
+ 
+ 
+ /*----------------------------------------------------------
+  *	Relational operators for LSNs
+  *---------------------------------------------------------*/
+ 
+ Datum
+ lsn_eq(PG_FUNCTION_ARGS)
+ {
+ 	XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_LSN(0);
+ 	XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_LSN(1);
+ 
+ 	PG_RETURN_BOOL(lsn1 == lsn2);
+ }
+ 
+ Datum
+ lsn_ne(PG_FUNCTION_ARGS)
+ {
+ 	XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_LSN(0);
+ 	XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_LSN(1);
+ 
+ 	PG_RETURN_BOOL(lsn1 != lsn2);
+ }
+ 
+ Datum
+ lsn_lt(PG_FUNCTION_ARGS)
+ {
+ 	XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_LSN(0);
+ 	XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_LSN(1);
+ 
+ 	PG_RETURN_BOOL(lsn1 < lsn2);
+ }
+ 
+ Datum
+ lsn_gt(PG_FUNCTION_ARGS)
+ {
+ 	XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_LSN(0);
+ 	XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_LSN(1);
+ 
+ 	PG_RETURN_BOOL(lsn1 > lsn2);
+ }
+ 
+ Datum
+ lsn_le(PG_FUNCTION_ARGS)
+ {
+ 	XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_LSN(0);
+ 	XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_LSN(1);
+ 
+ 	PG_RETURN_BOOL(lsn1 <= lsn2);
+ }
+ 
+ Datum
+ lsn_ge(PG_FUNCTION_ARGS)
+ {
+ 	XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_LSN(0);
+ 	XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_LSN(1);
+ 
+ 	PG_RETURN_BOOL(lsn1 >= lsn2);
+ }
+ 
+ 
+ /*----------------------------------------------------------
+  *	Arithmetic operators on LSNs.
+  *---------------------------------------------------------*/
+ 
+ Datum
+ lsn_mi(PG_FUNCTION_ARGS)
+ {
+ 	XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_LSN(0);
+ 	XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_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("LSN out of range")));
+ 
+ 	/* Convert to numeric. */
+ 	sprintf(buf, UINT64_FORMAT, lsn1 - lsn2);
+ 	result = DirectFunctionCall3(numeric_in,
+ 								 CStringGetDatum(buf),
+ 								 ObjectIdGetDatum(0),
+ 								 Int32GetDatum(-1));
+ 
+ 	return result;
+ }
*** a/src/include/catalog/pg_operator.h
--- b/src/include/catalog/pg_operator.h
***************
*** 1592,1597 **** DESCR("less than or equal");
--- 1592,1613 ----
  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 = 3222 (  "="	   PGNSP PGUID b f f 3220 3220 16 3222 3223 lsn_eq eqsel eqjoinsel ));
+ DESCR("equal");
+ DATA(insert OID = 3223 (  "<>"	   PGNSP PGUID b f f 3220 3220 16 3223 3222 lsn_ne neqsel neqjoinsel ));
+ DESCR("not equal");
+ DATA(insert OID = 3224 (  "<"	   PGNSP PGUID b f f 3220 3220 16 3225 3227 lsn_lt scalarltsel scalarltjoinsel ));
+ DESCR("less than");
+ DATA(insert OID = 3225 (  ">"	   PGNSP PGUID b f f 3220 3220 16 3224 3226 lsn_gt scalargtsel scalargtjoinsel ));
+ DESCR("greater than");
+ DATA(insert OID = 3226 (  "<="	   PGNSP PGUID b f f 3220 3220 16 3227 3225 lsn_le scalarltsel scalarltjoinsel ));
+ DESCR("less than or equal");
+ DATA(insert OID = 3227 (  ">="	   PGNSP PGUID b f f 3220 3220 16 3226 3224 lsn_ge scalargtsel scalargtjoinsel ));
+ DESCR("greater than or equal");
+ DATA(insert OID = 3228 (  "-"	   PGNSP PGUID b f f 3220 3220 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");
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 4212,4217 **** DESCR("I/O");
--- 4212,4234 ----
  DATA(insert OID = 2963 (  uuid_hash		   PGNSP PGUID 12 1 0 0 0 f 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 = 3229 (  lsn_in		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 3220 "2275" _null_ _null_ _null_ _null_ lsn_in _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 3230 (  lsn_out		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "3220" _null_ _null_ _null_ _null_ lsn_out _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 3231 (  lsn_lt		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3220 3220" _null_ _null_ _null_ _null_ lsn_lt _null_ _null_ _null_ ));
+ DATA(insert OID = 3232 (  lsn_le		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3220 3220" _null_ _null_ _null_ _null_ lsn_le _null_ _null_ _null_ ));
+ DATA(insert OID = 3233 (  lsn_eq		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3220 3220" _null_ _null_ _null_ _null_ lsn_eq _null_ _null_ _null_ ));
+ DATA(insert OID = 3234 (  lsn_ge		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3220 3220" _null_ _null_ _null_ _null_ lsn_ge _null_ _null_ _null_ ));
+ DATA(insert OID = 3235 (  lsn_gt		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3220 3220" _null_ _null_ _null_ _null_ lsn_gt _null_ _null_ _null_ ));
+ DATA(insert OID = 3236 (  lsn_ne		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3220 3220" _null_ _null_ _null_ _null_ lsn_ne _null_ _null_ _null_ ));
+ DATA(insert OID = 3237 (  lsn_mi		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1700 "3220 3220" _null_ _null_ _null_ _null_ lsn_mi _null_ _null_ _null_ ));
+ DATA(insert OID = 3238 (  lsn_recv		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 3220 "2281" _null_ _null_ _null_ _null_ lsn_recv _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 3239 (  lsn_send		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 17 "3220" _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 f t f i 1 0 3500 "2275" _null_ _null_ _null_ _null_ anyenum_in _null_ _null_ _null_ ));
  DESCR("I/O");
*** a/src/include/catalog/pg_type.h
--- b/src/include/catalog/pg_type.h
***************
*** 577,582 **** DESCR("UUID datatype");
--- 577,587 ----
  #define UUIDOID 2950
  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 - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
  
+ /* lsn */
+ DATA(insert OID = 3220 ( lsn			PGNSP PGUID 8 t b U t t \054 0 0 3221 lsn_in lsn_out lsn_recv lsn_send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+ DESCR("LSN datatype");
+ DATA(insert OID = 3221 ( _lsn			PGNSP PGUID -1 f b A f t \054 0 3220 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _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_ _null_ ));
  DESCR("text representation for text search");
*** a/src/include/fmgr.h
--- b/src/include/fmgr.h
***************
*** 230,235 **** extern struct varlena *pg_detoast_datum_packed(struct varlena * datum);
--- 230,236 ----
  #define PG_GETARG_CHAR(n)	 DatumGetChar(PG_GETARG_DATUM(n))
  #define PG_GETARG_BOOL(n)	 DatumGetBool(PG_GETARG_DATUM(n))
  #define PG_GETARG_OID(n)	 DatumGetObjectId(PG_GETARG_DATUM(n))
+ #define PG_GETARG_LSN(n)	 DatumGetLogSeqNum(PG_GETARG_DATUM(n))
  #define PG_GETARG_POINTER(n) DatumGetPointer(PG_GETARG_DATUM(n))
  #define PG_GETARG_CSTRING(n) DatumGetCString(PG_GETARG_DATUM(n))
  #define PG_GETARG_NAME(n)	 DatumGetName(PG_GETARG_DATUM(n))
***************
*** 302,307 **** extern struct varlena *pg_detoast_datum_packed(struct varlena * datum);
--- 303,309 ----
  #define PG_RETURN_CHAR(x)	 return CharGetDatum(x)
  #define PG_RETURN_BOOL(x)	 return BoolGetDatum(x)
  #define PG_RETURN_OID(x)	 return ObjectIdGetDatum(x)
+ #define PG_RETURN_LSN(x)	 return LogSeqNumGetDatum(x)
  #define PG_RETURN_POINTER(x) return PointerGetDatum(x)
  #define PG_RETURN_CSTRING(x) return CStringGetDatum(x)
  #define PG_RETURN_NAME(x)	 return NameGetDatum(x)
*** a/src/include/postgres.h
--- b/src/include/postgres.h
***************
*** 484,489 **** typedef Datum *DatumPtr;
--- 484,503 ----
  #define ObjectIdGetDatum(X) ((Datum) SET_4_BYTES(X))
  
  /*
+  * DatumGetLogSeqNum
+  *		Returns log sequence number of a datum.
+  */
+ 
+ #define DatumGetLogSeqNum(X) ((XLogRecPtr) GET_8_BYTES(X))
+ 
+ /*
+  * LogSeqNumGetDatum
+  *		Returns datum representation for a log sequence number.
+  */
+ 
+ #define LogSeqNumGetDatum(X) ((Datum) SET_8_BYTES(X))
+ 
+ /*
   * DatumGetTransactionId
   *		Returns transaction identifier value of a datum.
   */
*** /dev/null
--- b/src/include/utils/lsn.h
***************
*** 0 ****
--- 1,33 ----
+ /*-------------------------------------------------------------------------
+  *
+  * lsn.h
+  *		Declarations for operations on log sequence numbers (LSNs).
+  *
+  *
+  * Portions Copyright (c) 1996-2014, 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 */
*** /dev/null
--- b/src/test/regress/expected/lsn.out
***************
*** 0 ****
--- 1,62 ----
+ --
+ -- LSN
+ --
+ CREATE TABLE LSN_TBL (f1 lsn);
+ -- Largest and smallest input
+ INSERT INTO LSN_TBL VALUES ('0/0');
+ INSERT INTO LSN_TBL VALUES ('FFFFFFFF/FFFFFFFF');
+ -- Incorrect input
+ INSERT INTO LSN_TBL VALUES ('G/0');
+ ERROR:  invalid input syntax for lsn: "G/0"
+ LINE 1: INSERT INTO LSN_TBL VALUES ('G/0');
+                                     ^
+ INSERT INTO LSN_TBL VALUES ('-1/0');
+ ERROR:  invalid input syntax for lsn: "-1/0"
+ LINE 1: INSERT INTO LSN_TBL VALUES ('-1/0');
+                                     ^
+ INSERT INTO LSN_TBL VALUES (' 0/12345678');
+ ERROR:  invalid input syntax for lsn: " 0/12345678"
+ LINE 1: INSERT INTO LSN_TBL VALUES (' 0/12345678');
+                                     ^
+ INSERT INTO LSN_TBL VALUES ('ABCD/');
+ ERROR:  invalid input syntax for lsn: "ABCD/"
+ LINE 1: INSERT INTO LSN_TBL VALUES ('ABCD/');
+                                     ^
+ INSERT INTO LSN_TBL VALUES ('/ABCD');
+ ERROR:  invalid input syntax for lsn: "/ABCD"
+ LINE 1: INSERT INTO LSN_TBL VALUES ('/ABCD');
+                                     ^
+ DROP TABLE LSN_TBL;
+ -- Operators
+ SELECT lsn_eq('0/16AE7F8', '0/16AE7F8'); -- true
+  lsn_eq 
+ --------
+  t
+ (1 row)
+ 
+ SELECT lsn_ne('0/16AE7F8', '0/16AE7F7'); -- true
+  lsn_ne 
+ --------
+  t
+ (1 row)
+ 
+ SELECT lsn_lt('0/16AE7F7', '0/16AE7F8'); -- true
+  lsn_lt 
+ --------
+  t
+ (1 row)
+ 
+ SELECT lsn_gt('0/16AE7F8', '0/16AE7F7'); -- true
+  lsn_gt 
+ --------
+  t
+ (1 row)
+ 
+ SELECT lsn_mi('0/16AE7F7', '0/16AE7F8'); -- No negative results
+ ERROR:  LSN out of range
+ SELECT lsn_mi('0/16AE7F8', '0/16AE7F7'); -- correct
+  lsn_mi 
+ --------
+       1
+ (1 row)
+ 
*** a/src/test/regress/parallel_schedule
--- b/src/test/regress/parallel_schedule
***************
*** 13,19 **** test: tablespace
  # ----------
  # The first group of parallel tests
  # ----------
! test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric txid uuid enum money rangetypes
  
  # Depends on things setup during char, varchar and text
  test: strings
--- 13,19 ----
  # ----------
  # The first group of parallel tests
  # ----------
! test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric txid uuid enum money rangetypes lsn
  
  # Depends on things setup during char, varchar and text
  test: strings
*** a/src/test/regress/serial_schedule
--- b/src/test/regress/serial_schedule
***************
*** 19,24 **** test: uuid
--- 19,25 ----
  test: enum
  test: money
  test: rangetypes
+ test: lsn
  test: strings
  test: numerology
  test: point
*** /dev/null
--- b/src/test/regress/sql/lsn.sql
***************
*** 0 ****
--- 1,25 ----
+ --
+ -- LSN
+ --
+ 
+ CREATE TABLE LSN_TBL (f1 lsn);
+ 
+ -- Largest and smallest input
+ INSERT INTO LSN_TBL VALUES ('0/0');
+ INSERT INTO LSN_TBL VALUES ('FFFFFFFF/FFFFFFFF');
+ 
+ -- Incorrect input
+ INSERT INTO LSN_TBL VALUES ('G/0');
+ INSERT INTO LSN_TBL VALUES ('-1/0');
+ INSERT INTO LSN_TBL VALUES (' 0/12345678');
+ INSERT INTO LSN_TBL VALUES ('ABCD/');
+ INSERT INTO LSN_TBL VALUES ('/ABCD');
+ DROP TABLE LSN_TBL;
+ 
+ -- Operators
+ SELECT lsn_eq('0/16AE7F8', '0/16AE7F8'); -- true
+ SELECT lsn_ne('0/16AE7F8', '0/16AE7F7'); -- true
+ SELECT lsn_lt('0/16AE7F7', '0/16AE7F8'); -- true
+ SELECT lsn_gt('0/16AE7F8', '0/16AE7F7'); -- true
+ SELECT lsn_mi('0/16AE7F7', '0/16AE7F8'); -- No negative results
+ SELECT lsn_mi('0/16AE7F8', '0/16AE7F7'); -- correct
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 15884,15918 **** SELECT set_config('log_statement_stats', 'off', false);
         <entry>
          <literal><function>pg_create_restore_point(<parameter>name</> <type>text</>)</function></literal>
          </entry>
!        <entry><type>text</type></entry>
         <entry>Create a named point for performing restore (restricted to superusers)</entry>
        </row>
        <row>
         <entry>
          <literal><function>pg_current_xlog_insert_location()</function></literal>
          </entry>
!        <entry><type>text</type></entry>
         <entry>Get current transaction log insert location</entry>
        </row>
        <row>
         <entry>
          <literal><function>pg_current_xlog_location()</function></literal>
          </entry>
!        <entry><type>text</type></entry>
         <entry>Get current transaction log write location</entry>
        </row>
        <row>
         <entry>
          <literal><function>pg_start_backup(<parameter>label</> <type>text</> <optional>, <parameter>fast</> <type>boolean</> </optional>)</function></literal>
          </entry>
!        <entry><type>text</type></entry>
         <entry>Prepare for performing on-line backup (restricted to superusers or replication roles)</entry>
        </row>
        <row>
         <entry>
          <literal><function>pg_stop_backup()</function></literal>
          </entry>
!        <entry><type>text</type></entry>
         <entry>Finish performing on-line backup (restricted to superusers or replication roles)</entry>
        </row>
        <row>
--- 15884,15918 ----
         <entry>
          <literal><function>pg_create_restore_point(<parameter>name</> <type>text</>)</function></literal>
          </entry>
!        <entry><type>lsn</type></entry>
         <entry>Create a named point for performing restore (restricted to superusers)</entry>
        </row>
        <row>
         <entry>
          <literal><function>pg_current_xlog_insert_location()</function></literal>
          </entry>
!        <entry><type>lsn</type></entry>
         <entry>Get current transaction log insert location</entry>
        </row>
        <row>
         <entry>
          <literal><function>pg_current_xlog_location()</function></literal>
          </entry>
!        <entry><type>lsn</type></entry>
         <entry>Get current transaction log write location</entry>
        </row>
        <row>
         <entry>
          <literal><function>pg_start_backup(<parameter>label</> <type>text</> <optional>, <parameter>fast</> <type>boolean</> </optional>)</function></literal>
          </entry>
!        <entry><type>lsn</type></entry>
         <entry>Prepare for performing on-line backup (restricted to superusers or replication roles)</entry>
        </row>
        <row>
         <entry>
          <literal><function>pg_stop_backup()</function></literal>
          </entry>
!        <entry><type>lsn</type></entry>
         <entry>Finish performing on-line backup (restricted to superusers or replication roles)</entry>
        </row>
        <row>
***************
*** 15933,15958 **** SELECT set_config('log_statement_stats', 'off', false);
         <entry>
          <literal><function>pg_switch_xlog()</function></literal>
          </entry>
!        <entry><type>text</type></entry>
         <entry>Force switch to a new transaction log file (restricted to superusers)</entry>
        </row>
        <row>
         <entry>
!         <literal><function>pg_xlogfile_name(<parameter>location</> <type>text</>)</function></literal>
          </entry>
         <entry><type>text</type></entry>
         <entry>Convert transaction log location string to file name</entry>
        </row>
        <row>
         <entry>
!         <literal><function>pg_xlogfile_name_offset(<parameter>location</> <type>text</>)</function></literal>
          </entry>
         <entry><type>text</>, <type>integer</></entry>
         <entry>Convert transaction log location string to file name and decimal byte offset within file</entry>
        </row>
        <row>
         <entry>
!         <literal><function>pg_xlog_location_diff(<parameter>location</> <type>text</>, <parameter>location</> <type>text</>)</function></literal>
         </entry>
         <entry><type>numeric</></entry>
         <entry>Calculate the difference between two transaction log locations</entry>
--- 15933,15958 ----
         <entry>
          <literal><function>pg_switch_xlog()</function></literal>
          </entry>
!        <entry><type>lsn</type></entry>
         <entry>Force switch to a new transaction log file (restricted to superusers)</entry>
        </row>
        <row>
         <entry>
!         <literal><function>pg_xlogfile_name(<parameter>location</> <type>lsn</>)</function></literal>
          </entry>
         <entry><type>text</type></entry>
         <entry>Convert transaction log location string to file name</entry>
        </row>
        <row>
         <entry>
!         <literal><function>pg_xlogfile_name_offset(<parameter>location</> <type>lsn</>)</function></literal>
          </entry>
         <entry><type>text</>, <type>integer</></entry>
         <entry>Convert transaction log location string to file name and decimal byte offset within file</entry>
        </row>
        <row>
         <entry>
!         <literal><function>pg_xlog_location_diff(<parameter>location</> <type>lsn</>, <parameter>location</> <type>lsn</>)</function></literal>
         </entry>
         <entry><type>numeric</></entry>
         <entry>Calculate the difference between two transaction log locations</entry>
***************
*** 16107,16113 **** postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup());
         <entry>
          <literal><function>pg_last_xlog_receive_location()</function></literal>
          </entry>
!        <entry><type>text</type></entry>
         <entry>Get last transaction log location received and synced to disk by
          streaming replication. While streaming replication is in progress
          this will increase monotonically. If recovery has completed this will
--- 16107,16113 ----
         <entry>
          <literal><function>pg_last_xlog_receive_location()</function></literal>
          </entry>
!        <entry><type>lsn</type></entry>
         <entry>Get last transaction log location received and synced to disk by
          streaming replication. While streaming replication is in progress
          this will increase monotonically. If recovery has completed this will
***************
*** 16121,16127 **** postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup());
         <entry>
          <literal><function>pg_last_xlog_replay_location()</function></literal>
          </entry>
!        <entry><type>text</type></entry>
         <entry>Get last transaction log location replayed during recovery.
          If recovery is still in progress this will increase monotonically.
          If recovery has completed then this value will remain static at
--- 16121,16127 ----
         <entry>
          <literal><function>pg_last_xlog_replay_location()</function></literal>
          </entry>
!        <entry><type>lsn</type></entry>
         <entry>Get last transaction log location replayed during recovery.
          If recovery is still in progress this will increase monotonically.
          If recovery has completed then this value will remain static at
***************
*** 16335,16341 **** postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup());
          <literal><function>pg_create_physical_replication_slot(<parameter>slotname</parameter> <type>text</type>, <parameter>plugin</parameter> <type>text</type>)</function></literal>
         </entry>
         <entry>
!         (<parameter>slotname</parameter> <type>text</type>, <parameter>xlog_position</parameter> <type>text</type>)
         </entry>
         <entry>
          Creates a new physical replication slot named
--- 16335,16341 ----
          <literal><function>pg_create_physical_replication_slot(<parameter>slotname</parameter> <type>text</type>, <parameter>plugin</parameter> <type>text</type>)</function></literal>
         </entry>
         <entry>
!         (<parameter>slotname</parameter> <type>text</type>, <parameter>xlog_position</parameter> <type>lsn</type>)
         </entry>
         <entry>
          Creates a new physical replication slot named
*** a/src/backend/access/transam/xlogfuncs.c
--- b/src/backend/access/transam/xlogfuncs.c
***************
*** 33,40 ****
  #include "utils/timestamp.h"
  #include "storage/fd.h"
  
- static void validate_xlog_location(char *str);
- 
  
  /*
   * pg_start_backup: set up for taking an on-line backup dump
--- 33,38 ----
*** a/src/backend/catalog/system_views.sql
--- b/src/backend/catalog/system_views.sql
***************
*** 810,816 **** COMMENT ON FUNCTION ts_debug(text) IS
  
  CREATE OR REPLACE FUNCTION
    pg_start_backup(label text, fast boolean DEFAULT false)
!   RETURNS text STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup';
  
  CREATE OR REPLACE FUNCTION
    json_populate_record(base anyelement, from_json json, use_json_as_text boolean DEFAULT false)
--- 810,816 ----
  
  CREATE OR REPLACE FUNCTION
    pg_start_backup(label text, fast boolean DEFAULT false)
!   RETURNS lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup';
  
  CREATE OR REPLACE FUNCTION
    json_populate_record(base anyelement, from_json json, use_json_as_text boolean DEFAULT false)
*** a/src/backend/replication/slotfuncs.c
--- b/src/backend/replication/slotfuncs.c
***************
*** 141,148 **** pg_get_replication_slots(PG_FUNCTION_ARGS)
  		bool		active;
  		Oid			database;
  		const char *slot_name;
- 
- 		char		restart_lsn_s[MAXFNAMELEN];
  		int			i;
  
  		SpinLockAcquire(&slot->mutex);
--- 141,146 ----
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 2971,2998 **** DATA(insert OID = 2171 ( pg_cancel_backend		PGNSP PGUID 12 1 0 0 0 f f f f t f v
  DESCR("cancel a server process' current query");
  DATA(insert OID = 2096 ( pg_terminate_backend		PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 16 "23" _null_ _null_ _null_ _null_ pg_terminate_backend _null_ _null_ _null_ ));
  DESCR("terminate a server process");
! DATA(insert OID = 2172 ( pg_start_backup		PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 25 "25 16" _null_ _null_ _null_ _null_ pg_start_backup _null_ _null_ _null_ ));
  DESCR("prepare for taking an online backup");
! DATA(insert OID = 2173 ( pg_stop_backup			PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 25 "" _null_ _null_ _null_ _null_ pg_stop_backup _null_ _null_ _null_ ));
  DESCR("finish taking an online backup");
  DATA(insert OID = 3813 ( pg_is_in_backup		PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ pg_is_in_backup _null_ _null_ _null_ ));
  DESCR("true if server is in online backup");
  DATA(insert OID = 3814 ( pg_backup_start_time		PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 1184 "" _null_ _null_ _null_ _null_ pg_backup_start_time _null_ _null_ _null_ ));
  DESCR("start time of an online backup");
! DATA(insert OID = 2848 ( pg_switch_xlog			PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 25 "" _null_ _null_ _null_ _null_ pg_switch_xlog _null_ _null_ _null_ ));
  DESCR("switch to new xlog file");
! DATA(insert OID = 3098 ( pg_create_restore_point	PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 25 "25" _null_ _null_ _null_ _null_ pg_create_restore_point _null_ _null_ _null_ ));
  DESCR("create a named restore point");
! DATA(insert OID = 2849 ( pg_current_xlog_location	PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 25 "" _null_ _null_ _null_ _null_ pg_current_xlog_location _null_ _null_ _null_ ));
  DESCR("current xlog write location");
! DATA(insert OID = 2852 ( pg_current_xlog_insert_location	PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 25 "" _null_ _null_ _null_ _null_ pg_current_xlog_insert_location _null_ _null_ _null_ ));
  DESCR("current xlog insert location");
! DATA(insert OID = 2850 ( pg_xlogfile_name_offset	PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2249 "25" "{25,25,23}" "{i,o,o}" "{wal_location,file_name,file_offset}" _null_ pg_xlogfile_name_offset _null_ _null_ _null_ ));
  DESCR("xlog filename and byte offset, given an xlog location");
! DATA(insert OID = 2851 ( pg_xlogfile_name			PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "25" _null_ _null_ _null_ _null_ pg_xlogfile_name _null_ _null_ _null_ ));
  DESCR("xlog filename, given an xlog location");
  
! DATA(insert OID = 3165 ( pg_xlog_location_diff		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1700 "25 25" _null_ _null_ _null_ _null_ pg_xlog_location_diff _null_ _null_ _null_ ));
  DESCR("difference in bytes, given two xlog locations");
  
  DATA(insert OID = 3809 ( pg_export_snapshot		PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 25 "" _null_ _null_ _null_ _null_ pg_export_snapshot _null_ _null_ _null_ ));
--- 2971,2998 ----
  DESCR("cancel a server process' current query");
  DATA(insert OID = 2096 ( pg_terminate_backend		PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 16 "23" _null_ _null_ _null_ _null_ pg_terminate_backend _null_ _null_ _null_ ));
  DESCR("terminate a server process");
! DATA(insert OID = 2172 ( pg_start_backup		PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 3220 "25 16" _null_ _null_ _null_ _null_ pg_start_backup _null_ _null_ _null_ ));
  DESCR("prepare for taking an online backup");
! DATA(insert OID = 2173 ( pg_stop_backup			PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 3220 "" _null_ _null_ _null_ _null_ pg_stop_backup _null_ _null_ _null_ ));
  DESCR("finish taking an online backup");
  DATA(insert OID = 3813 ( pg_is_in_backup		PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ pg_is_in_backup _null_ _null_ _null_ ));
  DESCR("true if server is in online backup");
  DATA(insert OID = 3814 ( pg_backup_start_time		PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 1184 "" _null_ _null_ _null_ _null_ pg_backup_start_time _null_ _null_ _null_ ));
  DESCR("start time of an online backup");
! DATA(insert OID = 2848 ( pg_switch_xlog			PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 3220 "" _null_ _null_ _null_ _null_ pg_switch_xlog _null_ _null_ _null_ ));
  DESCR("switch to new xlog file");
! DATA(insert OID = 3098 ( pg_create_restore_point	PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 3220 "25" _null_ _null_ _null_ _null_ pg_create_restore_point _null_ _null_ _null_ ));
  DESCR("create a named restore point");
! DATA(insert OID = 2849 ( pg_current_xlog_location	PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 3220 "" _null_ _null_ _null_ _null_ pg_current_xlog_location _null_ _null_ _null_ ));
  DESCR("current xlog write location");
! DATA(insert OID = 2852 ( pg_current_xlog_insert_location	PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 3220 "" _null_ _null_ _null_ _null_ pg_current_xlog_insert_location _null_ _null_ _null_ ));
  DESCR("current xlog insert location");
! DATA(insert OID = 2850 ( pg_xlogfile_name_offset	PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2249 "3220" "{3220,25,23}" "{i,o,o}" "{wal_location,file_name,file_offset}" _null_ pg_xlogfile_name_offset _null_ _null_ _null_ ));
  DESCR("xlog filename and byte offset, given an xlog location");
! DATA(insert OID = 2851 ( pg_xlogfile_name			PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "3220" _null_ _null_ _null_ _null_ pg_xlogfile_name _null_ _null_ _null_ ));
  DESCR("xlog filename, given an xlog location");
  
! DATA(insert OID = 3165 ( pg_xlog_location_diff		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1700 "3220 3220" _null_ _null_ _null_ _null_ pg_xlog_location_diff _null_ _null_ _null_ ));
  DESCR("difference in bytes, given two xlog locations");
  
  DATA(insert OID = 3809 ( pg_export_snapshot		PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 25 "" _null_ _null_ _null_ _null_ pg_export_snapshot _null_ _null_ _null_ ));
***************
*** 3001,3009 **** DESCR("export a snapshot");
  DATA(insert OID = 3810 (  pg_is_in_recovery		PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ pg_is_in_recovery _null_ _null_ _null_ ));
  DESCR("true if server is in recovery");
  
! DATA(insert OID = 3820 ( pg_last_xlog_receive_location	PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 25 "" _null_ _null_ _null_ _null_ pg_last_xlog_receive_location _null_ _null_ _null_ ));
  DESCR("current xlog flush location");
! DATA(insert OID = 3821 ( pg_last_xlog_replay_location	PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 25 "" _null_ _null_ _null_ _null_ pg_last_xlog_replay_location _null_ _null_ _null_ ));
  DESCR("last xlog replay location");
  DATA(insert OID = 3830 ( pg_last_xact_replay_timestamp	PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 1184 "" _null_ _null_ _null_ _null_ pg_last_xact_replay_timestamp _null_ _null_ _null_ ));
  DESCR("timestamp of last replay xact");
--- 3001,3009 ----
  DATA(insert OID = 3810 (  pg_is_in_recovery		PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ pg_is_in_recovery _null_ _null_ _null_ ));
  DESCR("true if server is in recovery");
  
! DATA(insert OID = 3820 ( pg_last_xlog_receive_location	PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 3220 "" _null_ _null_ _null_ _null_ pg_last_xlog_receive_location _null_ _null_ _null_ ));
  DESCR("current xlog flush location");
! DATA(insert OID = 3821 ( pg_last_xlog_replay_location	PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 3220 "" _null_ _null_ _null_ _null_ pg_last_xlog_replay_location _null_ _null_ _null_ ));
  DESCR("last xlog replay location");
  DATA(insert OID = 3830 ( pg_last_xact_replay_timestamp	PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 1184 "" _null_ _null_ _null_ _null_ pg_last_xact_replay_timestamp _null_ _null_ _null_ ));
  DESCR("timestamp of last replay xact");
***************
*** 4800,4810 **** DATA(insert OID = 3473 (  spg_range_quad_leaf_consistent	PGNSP PGUID 12 1 0 0 0
  DESCR("SP-GiST support for quad tree over range");
  
  /* replication slots */
! DATA(insert OID = 3779 (  pg_create_physical_replication_slot PGNSP PGUID 12 1 0 0 0 f f f f f f v 1 0 2249 "19" "{19,25,25}" "{i,o,o}" "{slotname,slotname,xlog_position}" _null_ pg_create_physical_replication_slot _null_ _null_ _null_ ));
  DESCR("create a physical replication slot");
  DATA(insert OID = 3780 (  pg_drop_replication_slot PGNSP PGUID 12 1 0 0 0 f f f f f f v 1 0 2278 "19" _null_ _null_ _null_ _null_ pg_drop_replication_slot _null_ _null_ _null_ ));
  DESCR("drop a replication slot");
! DATA(insert OID = 3781 (  pg_get_replication_slots	PGNSP PGUID 12 1 10 0 0 f f f f f t s 0 0 2249 "" "{25,25,26,16,28,25}" "{o,o,o,o,o,o}" "{slot_name,slot_type,datoid,active,xmin,restart_lsn}" _null_ pg_get_replication_slots _null_ _null_ _null_ ));
  DESCR("information about replication slots currently in use");
  
  /* event triggers */
--- 4800,4810 ----
  DESCR("SP-GiST support for quad tree over range");
  
  /* replication slots */
! DATA(insert OID = 3779 (  pg_create_physical_replication_slot PGNSP PGUID 12 1 0 0 0 f f f f f f v 1 0 2249 "19" "{19,25,3220}" "{i,o,o}" "{slotname,slotname,xlog_position}" _null_ pg_create_physical_replication_slot _null_ _null_ _null_ ));
  DESCR("create a physical replication slot");
  DATA(insert OID = 3780 (  pg_drop_replication_slot PGNSP PGUID 12 1 0 0 0 f f f f f f v 1 0 2278 "19" _null_ _null_ _null_ _null_ pg_drop_replication_slot _null_ _null_ _null_ ));
  DESCR("drop a replication slot");
! DATA(insert OID = 3781 (  pg_get_replication_slots	PGNSP PGUID 12 1 10 0 0 f f f f f t s 0 0 2249 "" "{25,25,26,16,28,3220}" "{o,o,o,o,o,o}" "{slot_name,slot_type,datoid,active,xmin,restart_lsn}" _null_ pg_get_replication_slots _null_ _null_ _null_ ));
  DESCR("information about replication slots currently in use");
  
  /* event triggers */
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to