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