Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)