diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index c2e42f31c0..c5469e4678 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -4776,7 +4776,10 @@ SELECT * FROM pg_attribute standard comparison operators, like = and >. Two LSNs can be subtracted using the - operator; the result is the number of bytes separating - those write-ahead log locations. + those write-ahead log locations. Also the number of bytes can be added + into and substracted from LSN using the + and + - operators, respectively. + diff --git a/src/backend/utils/adt/pg_lsn.c b/src/backend/utils/adt/pg_lsn.c index d9754a7778..e4bdad3ef7 100644 --- a/src/backend/utils/adt/pg_lsn.c +++ b/src/backend/utils/adt/pg_lsn.c @@ -248,3 +248,49 @@ pg_lsn_mi(PG_FUNCTION_ARGS) return result; } + +/* + * Add the number of bytes to pg_lsn, giving a new pg_lsn. + * Must handle both positive and negative numbers of bytes. + */ +Datum +pg_lsn_pli(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn = PG_GETARG_LSN(0); + int64 nbytes = PG_GETARG_INT64(1); + XLogRecPtr result; + + result = lsn + nbytes; + + /* Check for pg_lsn overflow */ + if ((nbytes >= 0 && result < lsn) || + (nbytes < 0 && result > lsn)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("pg_lsn out of range"))); + + PG_RETURN_LSN(result); +} + +/* + * Substract the number of bytes from pg_lsn, giving a new pg_lsn. + * Must handle both positive and negative numbers of bytes. + */ +Datum +pg_lsn_mii(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn = PG_GETARG_LSN(0); + int64 nbytes = PG_GETARG_INT64(1); + XLogRecPtr result; + + result = lsn - nbytes; + + /* Check for pg_lsn overflow */ + if ((nbytes >= 0 && result > lsn) || + (nbytes < 0 && result < lsn)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("pg_lsn out of range"))); + + PG_RETURN_LSN(result); +} diff --git a/src/include/catalog/pg_operator.dat b/src/include/catalog/pg_operator.dat index 00ada7e48f..dc3dcc30c5 100644 --- a/src/include/catalog/pg_operator.dat +++ b/src/include/catalog/pg_operator.dat @@ -2909,6 +2909,12 @@ { oid => '3228', descr => 'minus', oprname => '-', oprleft => 'pg_lsn', oprright => 'pg_lsn', oprresult => 'numeric', oprcode => 'pg_lsn_mi' }, +{ oid => '4179', descr => 'add', + oprname => '+', oprleft => 'pg_lsn', oprright => 'int8', + oprresult => 'pg_lsn', oprcode => 'pg_lsn_pli' }, +{ oid => '4180', descr => 'subtract', + oprname => '-', oprleft => 'pg_lsn', oprright => 'int8', + oprresult => 'pg_lsn', oprcode => 'pg_lsn_mii' }, # enum operators { oid => '3516', descr => 'equal', diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 4bce3ad8de..198feddc91 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -8578,6 +8578,12 @@ { oid => '4188', descr => 'smaller of two', proname => 'pg_lsn_smaller', prorettype => 'pg_lsn', proargtypes => 'pg_lsn pg_lsn', prosrc => 'pg_lsn_smaller' }, +{ oid => '4198', + proname => 'pg_lsn_pli', prorettype => 'pg_lsn', + proargtypes => 'pg_lsn int8', prosrc => 'pg_lsn_pli' }, +{ oid => '4199', + proname => 'pg_lsn_mii', prorettype => 'pg_lsn', + proargtypes => 'pg_lsn int8', prosrc => 'pg_lsn_mii' }, # enum related procs { oid => '3504', descr => 'I/O', diff --git a/src/test/regress/expected/pg_lsn.out b/src/test/regress/expected/pg_lsn.out index 64d41dfdad..175b5dc9a7 100644 --- a/src/test/regress/expected/pg_lsn.out +++ b/src/test/regress/expected/pg_lsn.out @@ -71,6 +71,34 @@ SELECT '0/16AE7F8'::pg_lsn - '0/16AE7F7'::pg_lsn; 1 (1 row) +SELECT '0/16AE7F7'::pg_lsn + 16::bigint; + ?column? +----------- + 0/16AE807 +(1 row) + +SELECT '0/16AE7F7'::pg_lsn - 16::bigint; + ?column? +----------- + 0/16AE7E7 +(1 row) + +SELECT 'FFFFFFFF/FFFFFFFE'::pg_lsn + 1::bigint; + ?column? +------------------- + FFFFFFFF/FFFFFFFF +(1 row) + +SELECT 'FFFFFFFF/FFFFFFFE'::pg_lsn + 2::bigint; -- out of range error +ERROR: pg_lsn out of range +SELECT '0/1'::pg_lsn - 1::bigint; + ?column? +---------- + 0/0 +(1 row) + +SELECT '0/1'::pg_lsn - 2::bigint; -- out of range error +ERROR: pg_lsn out of range -- Check btree and hash opclasses EXPLAIN (COSTS OFF) SELECT DISTINCT (i || '/' || j)::pg_lsn f diff --git a/src/test/regress/sql/pg_lsn.sql b/src/test/regress/sql/pg_lsn.sql index 2c143c82ff..d64ac852c4 100644 --- a/src/test/regress/sql/pg_lsn.sql +++ b/src/test/regress/sql/pg_lsn.sql @@ -27,6 +27,12 @@ SELECT '0/16AE7F7' < '0/16AE7F8'::pg_lsn; SELECT '0/16AE7F8' > pg_lsn '0/16AE7F7'; SELECT '0/16AE7F7'::pg_lsn - '0/16AE7F8'::pg_lsn; SELECT '0/16AE7F8'::pg_lsn - '0/16AE7F7'::pg_lsn; +SELECT '0/16AE7F7'::pg_lsn + 16::bigint; +SELECT '0/16AE7F7'::pg_lsn - 16::bigint; +SELECT 'FFFFFFFF/FFFFFFFE'::pg_lsn + 1::bigint; +SELECT 'FFFFFFFF/FFFFFFFE'::pg_lsn + 2::bigint; -- out of range error +SELECT '0/1'::pg_lsn - 1::bigint; +SELECT '0/1'::pg_lsn - 2::bigint; -- out of range error -- Check btree and hash opclasses EXPLAIN (COSTS OFF)