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

Lines changed: 32 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 180 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 16 additions & 0 deletions
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

Lines changed: 17 additions & 0 deletions
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

Lines changed: 5 additions & 0 deletions
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

Lines changed: 2 additions & 0 deletions
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

Lines changed: 14 additions & 0 deletions
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

Lines changed: 34 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy