Skip to content

Commit 9bae7e4

Browse files
committed
Add +(pg_lsn,numeric) and -(pg_lsn,numeric) operators.
By using these operators, the number of bytes can be added into and subtracted from LSN. Bump catalog version. Author: Fujii Masao Reviewed-by: Kyotaro Horiguchi, Michael Paquier, Asif Rehman Discussion: https://postgr.es/m/ed9f7f74-e996-67f8-554a-52ebd3779b3b@oss.nttdata.com
1 parent 324435e commit 9bae7e4

File tree

10 files changed

+296
-2
lines changed

10 files changed

+296
-2
lines changed

doc/src/sgml/datatype.sgml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4801,7 +4801,13 @@ SELECT * FROM pg_attribute
48014801
standard comparison operators, like <literal>=</literal> and
48024802
<literal>&gt;</literal>. Two LSNs can be subtracted using the
48034803
<literal>-</literal> operator; the result is the number of bytes separating
4804-
those write-ahead log locations.
4804+
those write-ahead log locations. Also the number of bytes can be
4805+
added into and subtracted from LSN using the
4806+
<literal>+(pg_lsn,numeric)</literal> and
4807+
<literal>-(pg_lsn,numeric)</literal> operators, respectively. Note that
4808+
the calculated LSN should be in the range of <type>pg_lsn</type> type,
4809+
i.e., between <literal>0/0</literal> and
4810+
<literal>FFFFFFFF/FFFFFFFF</literal>.
48054811
</para>
48064812
</sect1>
48074813

src/backend/utils/adt/numeric.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "utils/guc.h"
4242
#include "utils/int8.h"
4343
#include "utils/numeric.h"
44+
#include "utils/pg_lsn.h"
4445
#include "utils/sortsupport.h"
4546

4647
/* ----------
@@ -472,6 +473,7 @@ static void apply_typmod(NumericVar *var, int32 typmod);
472473
static bool numericvar_to_int32(const NumericVar *var, int32 *result);
473474
static bool numericvar_to_int64(const NumericVar *var, int64 *result);
474475
static void int64_to_numericvar(int64 val, NumericVar *var);
476+
static bool numericvar_to_uint64(const NumericVar *var, uint64 *result);
475477
#ifdef HAVE_INT128
476478
static bool numericvar_to_int128(const NumericVar *var, int128 *result);
477479
static void int128_to_numericvar(int128 val, NumericVar *var);
@@ -3692,6 +3694,30 @@ numeric_float4(PG_FUNCTION_ARGS)
36923694
}
36933695

36943696

3697+
Datum
3698+
numeric_pg_lsn(PG_FUNCTION_ARGS)
3699+
{
3700+
Numeric num = PG_GETARG_NUMERIC(0);
3701+
NumericVar x;
3702+
XLogRecPtr result;
3703+
3704+
if (NUMERIC_IS_NAN(num))
3705+
ereport(ERROR,
3706+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3707+
errmsg("cannot convert NaN to pg_lsn")));
3708+
3709+
/* Convert to variable format and thence to pg_lsn */
3710+
init_var_from_num(num, &x);
3711+
3712+
if (!numericvar_to_uint64(&x, (uint64 *) &result))
3713+
ereport(ERROR,
3714+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3715+
errmsg("pg_lsn out of range")));
3716+
3717+
PG_RETURN_LSN(result);
3718+
}
3719+
3720+
36953721
/* ----------------------------------------------------------------------
36963722
*
36973723
* Aggregate functions
@@ -6742,6 +6768,78 @@ int64_to_numericvar(int64 val, NumericVar *var)
67426768
var->weight = ndigits - 1;
67436769
}
67446770

6771+
/*
6772+
* Convert numeric to uint64, rounding if needed.
6773+
*
6774+
* If overflow, return false (no error is raised). Return true if okay.
6775+
*/
6776+
static bool
6777+
numericvar_to_uint64(const NumericVar *var, uint64 *result)
6778+
{
6779+
NumericDigit *digits;
6780+
int ndigits;
6781+
int weight;
6782+
int i;
6783+
uint64 val;
6784+
NumericVar rounded;
6785+
6786+
/* Round to nearest integer */
6787+
init_var(&rounded);
6788+
set_var_from_var(var, &rounded);
6789+
round_var(&rounded, 0);
6790+
6791+
/* Check for zero input */
6792+
strip_var(&rounded);
6793+
ndigits = rounded.ndigits;
6794+
if (ndigits == 0)
6795+
{
6796+
*result = 0;
6797+
free_var(&rounded);
6798+
return true;
6799+
}
6800+
6801+
/* Check for negative input */
6802+
if (rounded.sign == NUMERIC_NEG)
6803+
{
6804+
free_var(&rounded);
6805+
return false;
6806+
}
6807+
6808+
/*
6809+
* For input like 10000000000, we must treat stripped digits as real. So
6810+
* the loop assumes there are weight+1 digits before the decimal point.
6811+
*/
6812+
weight = rounded.weight;
6813+
Assert(weight >= 0 && ndigits <= weight + 1);
6814+
6815+
/* Construct the result */
6816+
digits = rounded.digits;
6817+
val = digits[0];
6818+
for (i = 1; i <= weight; i++)
6819+
{
6820+
if (unlikely(pg_mul_u64_overflow(val, NBASE, &val)))
6821+
{
6822+
free_var(&rounded);
6823+
return false;
6824+
}
6825+
6826+
if (i < ndigits)
6827+
{
6828+
if (unlikely(pg_add_u64_overflow(val, digits[i], &val)))
6829+
{
6830+
free_var(&rounded);
6831+
return false;
6832+
}
6833+
}
6834+
}
6835+
6836+
free_var(&rounded);
6837+
6838+
*result = val;
6839+
6840+
return true;
6841+
}
6842+
67456843
#ifdef HAVE_INT128
67466844
/*
67476845
* Convert numeric to int128, rounding if needed.

src/backend/utils/adt/pg_lsn.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "funcapi.h"
1717
#include "libpq/pqformat.h"
1818
#include "utils/builtins.h"
19+
#include "utils/numeric.h"
1920
#include "utils/pg_lsn.h"
2021

2122
#define MAXPG_LSNLEN 17
@@ -248,3 +249,71 @@ pg_lsn_mi(PG_FUNCTION_ARGS)
248249

249250
return result;
250251
}
252+
253+
/*
254+
* Add the number of bytes to pg_lsn, giving a new pg_lsn.
255+
* Must handle both positive and negative numbers of bytes.
256+
*/
257+
Datum
258+
pg_lsn_pli(PG_FUNCTION_ARGS)
259+
{
260+
XLogRecPtr lsn = PG_GETARG_LSN(0);
261+
Numeric nbytes = PG_GETARG_NUMERIC(1);
262+
Datum num;
263+
Datum res;
264+
char buf[32];
265+
266+
if (numeric_is_nan(nbytes))
267+
ereport(ERROR,
268+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
269+
errmsg("cannot add NaN to pg_lsn")));
270+
271+
/* Convert to numeric */
272+
snprintf(buf, sizeof(buf), UINT64_FORMAT, lsn);
273+
num = DirectFunctionCall3(numeric_in,
274+
CStringGetDatum(buf),
275+
ObjectIdGetDatum(0),
276+
Int32GetDatum(-1));
277+
278+
/* Add two numerics */
279+
res = DirectFunctionCall2(numeric_add,
280+
NumericGetDatum(num),
281+
NumericGetDatum(nbytes));
282+
283+
/* Convert to pg_lsn */
284+
return DirectFunctionCall1(numeric_pg_lsn, res);
285+
}
286+
287+
/*
288+
* Subtract the number of bytes from pg_lsn, giving a new pg_lsn.
289+
* Must handle both positive and negative numbers of bytes.
290+
*/
291+
Datum
292+
pg_lsn_mii(PG_FUNCTION_ARGS)
293+
{
294+
XLogRecPtr lsn = PG_GETARG_LSN(0);
295+
Numeric nbytes = PG_GETARG_NUMERIC(1);
296+
Datum num;
297+
Datum res;
298+
char buf[32];
299+
300+
if (numeric_is_nan(nbytes))
301+
ereport(ERROR,
302+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
303+
errmsg("cannot subtract NaN from pg_lsn")));
304+
305+
/* Convert to numeric */
306+
snprintf(buf, sizeof(buf), UINT64_FORMAT, lsn);
307+
num = DirectFunctionCall3(numeric_in,
308+
CStringGetDatum(buf),
309+
ObjectIdGetDatum(0),
310+
Int32GetDatum(-1));
311+
312+
/* Subtract two numerics */
313+
res = DirectFunctionCall2(numeric_sub,
314+
NumericGetDatum(num),
315+
NumericGetDatum(nbytes));
316+
317+
/* Convert to pg_lsn */
318+
return DirectFunctionCall1(numeric_pg_lsn, res);
319+
}

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 202006151
56+
#define CATALOG_VERSION_NO 202006301
5757

5858
#endif

src/include/catalog/pg_operator.dat

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2909,6 +2909,17 @@
29092909
{ oid => '3228', descr => 'minus',
29102910
oprname => '-', oprleft => 'pg_lsn', oprright => 'pg_lsn',
29112911
oprresult => 'numeric', oprcode => 'pg_lsn_mi' },
2912+
{ oid => '5025', descr => 'add',
2913+
oprname => '+', oprleft => 'pg_lsn', oprright => 'numeric',
2914+
oprresult => 'pg_lsn', oprcom => '+(numeric,pg_lsn)',
2915+
oprcode => 'pg_lsn_pli' },
2916+
{ oid => '5026', descr => 'add',
2917+
oprname => '+', oprleft => 'numeric', oprright => 'pg_lsn',
2918+
oprresult => 'pg_lsn', oprcom => '+(pg_lsn,numeric)',
2919+
oprcode => 'numeric_pl_pg_lsn' },
2920+
{ oid => '5027', descr => 'subtract',
2921+
oprname => '-', oprleft => 'pg_lsn', oprright => 'numeric',
2922+
oprresult => 'pg_lsn', oprcode => 'pg_lsn_mii' },
29122923

29132924
# enum operators
29142925
{ oid => '3516', descr => 'equal',

src/include/catalog/pg_proc.dat

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4398,6 +4398,9 @@
43984398
{ oid => '1783', descr => 'convert numeric to int2',
43994399
proname => 'int2', prorettype => 'int2', proargtypes => 'numeric',
44004400
prosrc => 'numeric_int2' },
4401+
{ oid => '6103', descr => 'convert numeric to pg_lsn',
4402+
proname => 'pg_lsn', prorettype => 'pg_lsn', proargtypes => 'numeric',
4403+
prosrc => 'numeric_pg_lsn' },
44014404

44024405
{ oid => '3556', descr => 'convert jsonb to boolean',
44034406
proname => 'bool', prorettype => 'bool', proargtypes => 'jsonb',
@@ -8576,6 +8579,15 @@
85768579
{ oid => '4188', descr => 'smaller of two',
85778580
proname => 'pg_lsn_smaller', prorettype => 'pg_lsn',
85788581
proargtypes => 'pg_lsn pg_lsn', prosrc => 'pg_lsn_smaller' },
8582+
{ oid => '5022',
8583+
proname => 'pg_lsn_pli', prorettype => 'pg_lsn',
8584+
proargtypes => 'pg_lsn numeric', prosrc => 'pg_lsn_pli' },
8585+
{ oid => '5023',
8586+
proname => 'numeric_pl_pg_lsn', prolang => 'sql', prorettype => 'pg_lsn',
8587+
proargtypes => 'numeric pg_lsn', prosrc => 'select $2 + $1' },
8588+
{ oid => '5024',
8589+
proname => 'pg_lsn_mii', prorettype => 'pg_lsn',
8590+
proargtypes => 'pg_lsn numeric', prosrc => 'pg_lsn_mii' },
85798591

85808592
# enum related procs
85818593
{ oid => '3504', descr => 'I/O',

src/test/regress/expected/numeric.out

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,3 +2348,30 @@ SELECT -4!;
23482348
ERROR: factorial of a negative number is undefined
23492349
SELECT factorial(-4);
23502350
ERROR: factorial of a negative number is undefined
2351+
--
2352+
-- Tests for pg_lsn()
2353+
--
2354+
SELECT pg_lsn(23783416::numeric);
2355+
pg_lsn
2356+
-----------
2357+
0/16AE7F8
2358+
(1 row)
2359+
2360+
SELECT pg_lsn(0::numeric);
2361+
pg_lsn
2362+
--------
2363+
0/0
2364+
(1 row)
2365+
2366+
SELECT pg_lsn(18446744073709551615::numeric);
2367+
pg_lsn
2368+
-------------------
2369+
FFFFFFFF/FFFFFFFF
2370+
(1 row)
2371+
2372+
SELECT pg_lsn(-1::numeric);
2373+
ERROR: pg_lsn out of range
2374+
SELECT pg_lsn(18446744073709551616::numeric);
2375+
ERROR: pg_lsn out of range
2376+
SELECT pg_lsn('NaN'::numeric);
2377+
ERROR: cannot convert NaN to pg_lsn

src/test/regress/expected/pg_lsn.out

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,56 @@ SELECT '0/16AE7F8'::pg_lsn - '0/16AE7F7'::pg_lsn;
7171
1
7272
(1 row)
7373

74+
SELECT '0/16AE7F7'::pg_lsn + 16::numeric;
75+
?column?
76+
-----------
77+
0/16AE807
78+
(1 row)
79+
80+
SELECT 16::numeric + '0/16AE7F7'::pg_lsn;
81+
?column?
82+
-----------
83+
0/16AE807
84+
(1 row)
85+
86+
SELECT '0/16AE7F7'::pg_lsn - 16::numeric;
87+
?column?
88+
-----------
89+
0/16AE7E7
90+
(1 row)
91+
92+
SELECT 'FFFFFFFF/FFFFFFFE'::pg_lsn + 1::numeric;
93+
?column?
94+
-------------------
95+
FFFFFFFF/FFFFFFFF
96+
(1 row)
97+
98+
SELECT 'FFFFFFFF/FFFFFFFE'::pg_lsn + 2::numeric; -- out of range error
99+
ERROR: pg_lsn out of range
100+
SELECT '0/1'::pg_lsn - 1::numeric;
101+
?column?
102+
----------
103+
0/0
104+
(1 row)
105+
106+
SELECT '0/1'::pg_lsn - 2::numeric; -- out of range error
107+
ERROR: pg_lsn out of range
108+
SELECT '0/0'::pg_lsn + ('FFFFFFFF/FFFFFFFF'::pg_lsn - '0/0'::pg_lsn);
109+
?column?
110+
-------------------
111+
FFFFFFFF/FFFFFFFF
112+
(1 row)
113+
114+
SELECT 'FFFFFFFF/FFFFFFFF'::pg_lsn - ('FFFFFFFF/FFFFFFFF'::pg_lsn - '0/0'::pg_lsn);
115+
?column?
116+
----------
117+
0/0
118+
(1 row)
119+
120+
SELECT '0/16AE7F7'::pg_lsn + 'NaN'::numeric;
121+
ERROR: cannot add NaN to pg_lsn
122+
SELECT '0/16AE7F7'::pg_lsn - 'NaN'::numeric;
123+
ERROR: cannot subtract NaN from pg_lsn
74124
-- Check btree and hash opclasses
75125
EXPLAIN (COSTS OFF)
76126
SELECT DISTINCT (i || '/' || j)::pg_lsn f

src/test/regress/sql/numeric.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,3 +1122,13 @@ SELECT 100000!;
11221122
SELECT 0!;
11231123
SELECT -4!;
11241124
SELECT factorial(-4);
1125+
1126+
--
1127+
-- Tests for pg_lsn()
1128+
--
1129+
SELECT pg_lsn(23783416::numeric);
1130+
SELECT pg_lsn(0::numeric);
1131+
SELECT pg_lsn(18446744073709551615::numeric);
1132+
SELECT pg_lsn(-1::numeric);
1133+
SELECT pg_lsn(18446744073709551616::numeric);
1134+
SELECT pg_lsn('NaN'::numeric);

src/test/regress/sql/pg_lsn.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@ SELECT '0/16AE7F7' < '0/16AE7F8'::pg_lsn;
2727
SELECT '0/16AE7F8' > pg_lsn '0/16AE7F7';
2828
SELECT '0/16AE7F7'::pg_lsn - '0/16AE7F8'::pg_lsn;
2929
SELECT '0/16AE7F8'::pg_lsn - '0/16AE7F7'::pg_lsn;
30+
SELECT '0/16AE7F7'::pg_lsn + 16::numeric;
31+
SELECT 16::numeric + '0/16AE7F7'::pg_lsn;
32+
SELECT '0/16AE7F7'::pg_lsn - 16::numeric;
33+
SELECT 'FFFFFFFF/FFFFFFFE'::pg_lsn + 1::numeric;
34+
SELECT 'FFFFFFFF/FFFFFFFE'::pg_lsn + 2::numeric; -- out of range error
35+
SELECT '0/1'::pg_lsn - 1::numeric;
36+
SELECT '0/1'::pg_lsn - 2::numeric; -- out of range error
37+
SELECT '0/0'::pg_lsn + ('FFFFFFFF/FFFFFFFF'::pg_lsn - '0/0'::pg_lsn);
38+
SELECT 'FFFFFFFF/FFFFFFFF'::pg_lsn - ('FFFFFFFF/FFFFFFFF'::pg_lsn - '0/0'::pg_lsn);
39+
SELECT '0/16AE7F7'::pg_lsn + 'NaN'::numeric;
40+
SELECT '0/16AE7F7'::pg_lsn - 'NaN'::numeric;
3041

3142
-- Check btree and hash opclasses
3243
EXPLAIN (COSTS OFF)

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