Skip to content

Commit 7d03a83

Browse files
committed
Add a pg_lsn data type, to represent an LSN.
Robert Haas and Michael Paquier
1 parent a222f7f commit 7d03a83

File tree

14 files changed

+391
-3
lines changed

14 files changed

+391
-3
lines changed

doc/src/sgml/datatype.sgml

+32
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,12 @@
180180
<entry>geometric path on a plane</entry>
181181
</row>
182182

183+
<row>
184+
<entry><type>pg_lsn</type></entry>
185+
<entry></entry>
186+
<entry><productname>PostgreSQL</productname> Log Sequence Number</entry>
187+
</row>
188+
183189
<row>
184190
<entry><type>point</type></entry>
185191
<entry></entry>
@@ -4504,6 +4510,32 @@ SELECT * FROM pg_attribute
45044510
</para>
45054511
</sect1>
45064512

4513+
<sect1 id="datatype-pg-lsn">
4514+
<title><acronym>pg_lsn Type</acronym></title>
4515+
4516+
<indexterm zone="datatype-pg-lsn">
4517+
<primary>pg_lsn</primary>
4518+
</indexterm>
4519+
4520+
<para>
4521+
The <type>pg_lsn</type> data type can be used to store LSN (Log Sequence
4522+
Number) data which is a pointer to a location in the XLOG. This type is a
4523+
representation of XLogRecPtr and an internal system type of
4524+
<productname>PostgreSQL</productname>.
4525+
</para>
4526+
4527+
<para>
4528+
Internally, an LSN is a 64-bit integer, representing a byte position in
4529+
the write-ahead log stream. It is printed as two hexadecimal numbers of
4530+
up to 8 digits each, separated by a slash; for example,
4531+
<literal>16/B374D848</>. The <type>pg_lsn</type> type supports the
4532+
standard comparison operators, like <literal>=</literal> and
4533+
<literal>&gt;</literal>. Two LSNs can be subtracted using the
4534+
<literal>-</literal> operator; the result is the number of bytes separating
4535+
those write-ahead log positions.
4536+
</para>
4537+
</sect1>
4538+
45074539
<sect1 id="datatype-pseudo">
45084540
<title>Pseudo-Types</title>
45094541

src/backend/utils/adt/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ OBJS = acl.o arrayfuncs.o array_selfuncs.o array_typanalyze.o \
2424
int8.o json.o jsonfuncs.o like.o \
2525
lockfuncs.o mac.o misc.o nabstime.o name.o network.o numeric.o \
2626
numutils.o oid.o oracle_compat.o orderedsetaggs.o \
27-
pg_lzcompress.o pg_locale.o pgstatfuncs.o \
27+
pg_lzcompress.o pg_locale.o pg_lsn.o pgstatfuncs.o \
2828
pseudotypes.o quote.o rangetypes.o rangetypes_gist.o \
2929
rangetypes_selfuncs.o rangetypes_spgist.o rangetypes_typanalyze.o \
3030
regexp.o regproc.o ri_triggers.o rowtypes.o ruleutils.o \

src/backend/utils/adt/pg_lsn.c

+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* pg_lsn.c
4+
* Internal PostgreSQL LSN operations
5+
*
6+
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7+
* Portions Copyright (c) 1994, Regents of the University of California
8+
*
9+
* IDENTIFICATION
10+
* src/backend/utils/adt/pg_lsn.c
11+
*
12+
*-------------------------------------------------------------------------
13+
*/
14+
#include "postgres.h"
15+
16+
#include "funcapi.h"
17+
#include "libpq/pqformat.h"
18+
#include "utils/builtins.h"
19+
#include "utils/pg_lsn.h"
20+
21+
#define MAXPG_LSNLEN 17
22+
#define MAXPG_LSNCOMPONENT 8
23+
24+
/*----------------------------------------------------------
25+
* Formatting and conversion routines.
26+
*---------------------------------------------------------*/
27+
28+
Datum
29+
pg_lsn_in(PG_FUNCTION_ARGS)
30+
{
31+
char *str = PG_GETARG_CSTRING(0);
32+
int len1, len2;
33+
uint32 id, off;
34+
XLogRecPtr result;
35+
36+
/* Sanity check input format. */
37+
len1 = strspn(str, "0123456789abcdefABCDEF");
38+
if (len1 < 1 || len1 > MAXPG_LSNCOMPONENT || str[len1] != '/')
39+
ereport(ERROR,
40+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
41+
errmsg("invalid input syntax for transaction log location: \"%s\"", str)));
42+
len2 = strspn(str + len1 + 1, "0123456789abcdefABCDEF");
43+
if (len2 < 1 || len2 > MAXPG_LSNCOMPONENT || str[len1 + 1 + len2] != '\0')
44+
ereport(ERROR,
45+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
46+
errmsg("invalid input syntax for transaction log location: \"%s\"", str)));
47+
48+
/* Decode result. */
49+
id = (uint32) strtoul(str, NULL, 16);
50+
off = (uint32) strtoul(str + len1 + 1, NULL, 16);
51+
result = (XLogRecPtr) ((uint64) id << 32) | off;
52+
53+
PG_RETURN_PG_LSN(result);
54+
}
55+
56+
Datum
57+
pg_lsn_out(PG_FUNCTION_ARGS)
58+
{
59+
XLogRecPtr lsn = (XLogRecPtr) PG_GETARG_PG_LSN(0);
60+
char buf[MAXPG_LSNLEN + 1];
61+
char *result;
62+
uint32 id, off;
63+
64+
/* Decode ID and offset */
65+
id = (uint32) (lsn >> 32);
66+
off = (uint32) lsn;
67+
68+
snprintf(buf, sizeof buf, "%X/%X", id, off);
69+
result = pstrdup(buf);
70+
PG_RETURN_CSTRING(result);
71+
}
72+
73+
Datum
74+
pg_lsn_recv(PG_FUNCTION_ARGS)
75+
{
76+
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
77+
XLogRecPtr result;
78+
79+
result = pq_getmsgint64(buf);
80+
PG_RETURN_PG_LSN(result);
81+
}
82+
83+
Datum
84+
pg_lsn_send(PG_FUNCTION_ARGS)
85+
{
86+
XLogRecPtr lsn = (XLogRecPtr) PG_GETARG_PG_LSN(0);
87+
StringInfoData buf;
88+
89+
pq_begintypsend(&buf);
90+
pq_sendint64(&buf, lsn);
91+
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
92+
}
93+
94+
95+
/*----------------------------------------------------------
96+
* Operators for PostgreSQL LSNs
97+
*---------------------------------------------------------*/
98+
99+
Datum
100+
pg_lsn_eq(PG_FUNCTION_ARGS)
101+
{
102+
XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_PG_LSN(0);
103+
XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_PG_LSN(1);
104+
105+
PG_RETURN_BOOL(lsn1 == lsn2);
106+
}
107+
108+
Datum
109+
pg_lsn_ne(PG_FUNCTION_ARGS)
110+
{
111+
XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_PG_LSN(0);
112+
XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_PG_LSN(1);
113+
114+
PG_RETURN_BOOL(lsn1 != lsn2);
115+
}
116+
117+
Datum
118+
pg_lsn_lt(PG_FUNCTION_ARGS)
119+
{
120+
XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_PG_LSN(0);
121+
XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_PG_LSN(1);
122+
123+
PG_RETURN_BOOL(lsn1 < lsn2);
124+
}
125+
126+
Datum
127+
pg_lsn_gt(PG_FUNCTION_ARGS)
128+
{
129+
XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_PG_LSN(0);
130+
XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_PG_LSN(1);
131+
132+
PG_RETURN_BOOL(lsn1 > lsn2);
133+
}
134+
135+
Datum
136+
pg_lsn_le(PG_FUNCTION_ARGS)
137+
{
138+
XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_PG_LSN(0);
139+
XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_PG_LSN(1);
140+
141+
PG_RETURN_BOOL(lsn1 <= lsn2);
142+
}
143+
144+
Datum
145+
pg_lsn_ge(PG_FUNCTION_ARGS)
146+
{
147+
XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_PG_LSN(0);
148+
XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_PG_LSN(1);
149+
150+
PG_RETURN_BOOL(lsn1 >= lsn2);
151+
}
152+
153+
154+
/*----------------------------------------------------------
155+
* Arithmetic operators on PostgreSQL LSNs.
156+
*---------------------------------------------------------*/
157+
158+
Datum
159+
pg_lsn_mi(PG_FUNCTION_ARGS)
160+
{
161+
XLogRecPtr lsn1 = (XLogRecPtr) PG_GETARG_PG_LSN(0);
162+
XLogRecPtr lsn2 = (XLogRecPtr) PG_GETARG_PG_LSN(1);
163+
char buf[256];
164+
Datum result;
165+
166+
/* Negative results are not allowed. */
167+
if (lsn1 < lsn2)
168+
ereport(ERROR,
169+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
170+
errmsg("transaction log location out of range")));
171+
172+
/* Convert to numeric. */
173+
snprintf(buf, sizeof buf, UINT64_FORMAT, lsn1 - lsn2);
174+
result = DirectFunctionCall3(numeric_in,
175+
CStringGetDatum(buf),
176+
ObjectIdGetDatum(0),
177+
Int32GetDatum(-1));
178+
179+
return result;
180+
}

src/include/catalog/catversion.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201402031
56+
#define CATALOG_VERSION_NO 201402191
5757

5858
#endif

src/include/catalog/pg_operator.h

+16
Original file line numberDiff line numberDiff line change
@@ -1592,6 +1592,22 @@ DESCR("less than or equal");
15921592
DATA(insert OID = 2977 ( ">=" PGNSP PGUID b f f 2950 2950 16 2976 2974 uuid_ge scalargtsel scalargtjoinsel ));
15931593
DESCR("greater than or equal");
15941594

1595+
/* pg_lsn operators */
1596+
DATA(insert OID = 3222 ( "=" PGNSP PGUID b f f 3220 3220 16 3222 3223 pg_lsn_eq eqsel eqjoinsel ));
1597+
DESCR("equal");
1598+
DATA(insert OID = 3223 ( "<>" PGNSP PGUID b f f 3220 3220 16 3223 3222 pg_lsn_ne neqsel neqjoinsel ));
1599+
DESCR("not equal");
1600+
DATA(insert OID = 3224 ( "<" PGNSP PGUID b f f 3220 3220 16 3225 3227 pg_lsn_lt scalarltsel scalarltjoinsel ));
1601+
DESCR("less than");
1602+
DATA(insert OID = 3225 ( ">" PGNSP PGUID b f f 3220 3220 16 3224 3226 pg_lsn_gt scalargtsel scalargtjoinsel ));
1603+
DESCR("greater than");
1604+
DATA(insert OID = 3226 ( "<=" PGNSP PGUID b f f 3220 3220 16 3227 3225 pg_lsn_le scalarltsel scalarltjoinsel ));
1605+
DESCR("less than or equal");
1606+
DATA(insert OID = 3227 ( ">=" PGNSP PGUID b f f 3220 3220 16 3226 3224 pg_lsn_ge scalargtsel scalargtjoinsel ));
1607+
DESCR("greater than or equal");
1608+
DATA(insert OID = 3228 ( "-" PGNSP PGUID b f f 3220 3220 1700 0 0 pg_lsn_mi - - ));
1609+
DESCR("minus");
1610+
15951611
/* enum operators */
15961612
DATA(insert OID = 3516 ( "=" PGNSP PGUID b t t 3500 3500 16 3516 3517 enum_eq eqsel eqjoinsel ));
15971613
DESCR("equal");

src/include/catalog/pg_proc.h

+17
Original file line numberDiff line numberDiff line change
@@ -4212,6 +4212,23 @@ DESCR("I/O");
42124212
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_ ));
42134213
DESCR("hash");
42144214

4215+
/* pg_lsn */
4216+
DATA(insert OID = 3229 ( pg_lsn_in PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 3220 "2275" _null_ _null_ _null_ _null_ pg_lsn_in _null_ _null_ _null_ ));
4217+
DESCR("I/O");
4218+
DATA(insert OID = 3230 ( pg_lsn_out PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "3220" _null_ _null_ _null_ _null_ pg_lsn_out _null_ _null_ _null_ ));
4219+
DESCR("I/O");
4220+
DATA(insert OID = 3231 ( pg_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_ pg_lsn_lt _null_ _null_ _null_ ));
4221+
DATA(insert OID = 3232 ( pg_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_ pg_lsn_le _null_ _null_ _null_ ));
4222+
DATA(insert OID = 3233 ( pg_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_ pg_lsn_eq _null_ _null_ _null_ ));
4223+
DATA(insert OID = 3234 ( pg_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_ pg_lsn_ge _null_ _null_ _null_ ));
4224+
DATA(insert OID = 3235 ( pg_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_ pg_lsn_gt _null_ _null_ _null_ ));
4225+
DATA(insert OID = 3236 ( pg_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_ pg_lsn_ne _null_ _null_ _null_ ));
4226+
DATA(insert OID = 3237 ( pg_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_ pg_lsn_mi _null_ _null_ _null_ ));
4227+
DATA(insert OID = 3238 ( pg_lsn_recv PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 3220 "2281" _null_ _null_ _null_ _null_ pg_lsn_recv _null_ _null_ _null_ ));
4228+
DESCR("I/O");
4229+
DATA(insert OID = 3239 ( pg_lsn_send PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 17 "3220" _null_ _null_ _null_ _null_ pg_lsn_send _null_ _null_ _null_ ));
4230+
DESCR("I/O");
4231+
42154232
/* enum related procs */
42164233
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_ ));
42174234
DESCR("I/O");

src/include/catalog/pg_type.h

+5
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,11 @@ DESCR("UUID datatype");
577577
#define UUIDOID 2950
578578
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_ ));
579579

580+
/* pg_lsn */
581+
DATA(insert OID = 3220 ( pg_lsn PGNSP PGUID 8 t b U t t \054 0 0 3221 pg_lsn_in pg_lsn_out pg_lsn_recv pg_lsn_send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
582+
DESCR("PostgreSQL LSN datatype");
583+
DATA(insert OID = 3221 ( _pg_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_ ));
584+
580585
/* text search */
581586
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_ ));
582587
DESCR("text representation for text search");

src/include/fmgr.h

+2
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena * datum);
230230
#define PG_GETARG_CHAR(n) DatumGetChar(PG_GETARG_DATUM(n))
231231
#define PG_GETARG_BOOL(n) DatumGetBool(PG_GETARG_DATUM(n))
232232
#define PG_GETARG_OID(n) DatumGetObjectId(PG_GETARG_DATUM(n))
233+
#define PG_GETARG_PG_LSN(n) DatumGetPgLsn(PG_GETARG_DATUM(n))
233234
#define PG_GETARG_POINTER(n) DatumGetPointer(PG_GETARG_DATUM(n))
234235
#define PG_GETARG_CSTRING(n) DatumGetCString(PG_GETARG_DATUM(n))
235236
#define PG_GETARG_NAME(n) DatumGetName(PG_GETARG_DATUM(n))
@@ -302,6 +303,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena * datum);
302303
#define PG_RETURN_CHAR(x) return CharGetDatum(x)
303304
#define PG_RETURN_BOOL(x) return BoolGetDatum(x)
304305
#define PG_RETURN_OID(x) return ObjectIdGetDatum(x)
306+
#define PG_RETURN_PG_LSN(x) return PgLsnGetDatum(x)
305307
#define PG_RETURN_POINTER(x) return PointerGetDatum(x)
306308
#define PG_RETURN_CSTRING(x) return CStringGetDatum(x)
307309
#define PG_RETURN_NAME(x) return NameGetDatum(x)

src/include/postgres.h

+14
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,20 @@ typedef Datum *DatumPtr;
483483

484484
#define ObjectIdGetDatum(X) ((Datum) SET_4_BYTES(X))
485485

486+
/*
487+
* DatumGetPgLsn
488+
* Returns PostgreSQL log sequence number of a datum.
489+
*/
490+
491+
#define DatumGetPgLsn(X) ((XLogRecPtr) GET_8_BYTES(X))
492+
493+
/*
494+
* PG_LSNGetDatum
495+
* Returns datum representation for a PostgreSQL log sequence number.
496+
*/
497+
498+
#define PgLsnGetDatum(X) ((Datum) SET_8_BYTES(X))
499+
486500
/*
487501
* DatumGetTransactionId
488502
* Returns transaction identifier value of a datum.

src/include/utils/pg_lsn.h

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* pg_lsn.h
4+
* Declarations for operations on log sequence numbers (LSNs) of
5+
* PostgreSQL.
6+
*
7+
*
8+
* Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
9+
* Portions Copyright (c) 1994, Regents of the University of California
10+
*
11+
* src/include/utils/pg_lsn.h
12+
*
13+
*-------------------------------------------------------------------------
14+
*/
15+
#ifndef PG_LSN_H
16+
#define PG_LSN_H
17+
18+
#include "fmgr.h"
19+
20+
extern Datum pg_lsn_in(PG_FUNCTION_ARGS);
21+
extern Datum pg_lsn_out(PG_FUNCTION_ARGS);
22+
extern Datum pg_lsn_recv(PG_FUNCTION_ARGS);
23+
extern Datum pg_lsn_send(PG_FUNCTION_ARGS);
24+
25+
extern Datum pg_lsn_eq(PG_FUNCTION_ARGS);
26+
extern Datum pg_lsn_ne(PG_FUNCTION_ARGS);
27+
extern Datum pg_lsn_lt(PG_FUNCTION_ARGS);
28+
extern Datum pg_lsn_gt(PG_FUNCTION_ARGS);
29+
extern Datum pg_lsn_le(PG_FUNCTION_ARGS);
30+
extern Datum pg_lsn_ge(PG_FUNCTION_ARGS);
31+
32+
extern Datum pg_lsn_mi(PG_FUNCTION_ARGS);
33+
34+
#endif /* PG_LSN_H */

0 commit comments

Comments
 (0)