LCOV - code coverage report
Current view: top level - src/backend/utils/adt - pg_lsn.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 91.1 % 101 92
Test Date: 2026-02-17 17:20:33 Functions: 89.5 % 19 17
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * pg_lsn.c
       4              :  *    Operations for the pg_lsn datatype.
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, 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 "libpq/pqformat.h"
      17              : #include "utils/fmgrprotos.h"
      18              : #include "utils/numeric.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              : /*
      29              :  * Internal version of pg_lsn_in() with support for soft error reporting.
      30              :  */
      31              : XLogRecPtr
      32         4065 : pg_lsn_in_safe(const char *str, Node *escontext)
      33              : {
      34              :     int         len1,
      35              :                 len2;
      36              :     uint32      id,
      37              :                 off;
      38              :     XLogRecPtr  result;
      39              : 
      40              :     /* Sanity check input format. */
      41         4065 :     len1 = strspn(str, "0123456789abcdefABCDEF");
      42         4065 :     if (len1 < 1 || len1 > MAXPG_LSNCOMPONENT || str[len1] != '/')
      43           19 :         goto syntax_error;
      44              : 
      45         4046 :     len2 = strspn(str + len1 + 1, "0123456789abcdefABCDEF");
      46         4046 :     if (len2 < 1 || len2 > MAXPG_LSNCOMPONENT || str[len1 + 1 + len2] != '\0')
      47            3 :         goto syntax_error;
      48              : 
      49              :     /* Decode result. */
      50         4043 :     id = (uint32) strtoul(str, NULL, 16);
      51         4043 :     off = (uint32) strtoul(str + len1 + 1, NULL, 16);
      52         4043 :     result = ((uint64) id << 32) | off;
      53              : 
      54         4043 :     return result;
      55              : 
      56           22 : syntax_error:
      57           22 :     ereturn(escontext, InvalidXLogRecPtr,
      58              :             (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
      59              :              errmsg("invalid input syntax for type %s: \"%s\"",
      60              :                     "pg_lsn", str)));
      61              : }
      62              : 
      63              : Datum
      64         4057 : pg_lsn_in(PG_FUNCTION_ARGS)
      65              : {
      66         4057 :     char       *str = PG_GETARG_CSTRING(0);
      67              :     XLogRecPtr  result;
      68              : 
      69         4057 :     result = pg_lsn_in_safe(str, fcinfo->context);
      70              : 
      71         4041 :     PG_RETURN_LSN(result);
      72              : }
      73              : 
      74              : Datum
      75         3383 : pg_lsn_out(PG_FUNCTION_ARGS)
      76              : {
      77         3383 :     XLogRecPtr  lsn = PG_GETARG_LSN(0);
      78              :     char        buf[MAXPG_LSNLEN + 1];
      79              :     char       *result;
      80              : 
      81         3383 :     snprintf(buf, sizeof buf, "%X/%08X", LSN_FORMAT_ARGS(lsn));
      82         3383 :     result = pstrdup(buf);
      83         3383 :     PG_RETURN_CSTRING(result);
      84              : }
      85              : 
      86              : Datum
      87            0 : pg_lsn_recv(PG_FUNCTION_ARGS)
      88              : {
      89            0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
      90              :     XLogRecPtr  result;
      91              : 
      92            0 :     result = pq_getmsgint64(buf);
      93            0 :     PG_RETURN_LSN(result);
      94              : }
      95              : 
      96              : Datum
      97            0 : pg_lsn_send(PG_FUNCTION_ARGS)
      98              : {
      99            0 :     XLogRecPtr  lsn = PG_GETARG_LSN(0);
     100              :     StringInfoData buf;
     101              : 
     102            0 :     pq_begintypsend(&buf);
     103            0 :     pq_sendint64(&buf, lsn);
     104            0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     105              : }
     106              : 
     107              : 
     108              : /*----------------------------------------------------------
     109              :  *  Operators for PostgreSQL LSNs
     110              :  *---------------------------------------------------------*/
     111              : 
     112              : Datum
     113         6746 : pg_lsn_eq(PG_FUNCTION_ARGS)
     114              : {
     115         6746 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     116         6746 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     117              : 
     118         6746 :     PG_RETURN_BOOL(lsn1 == lsn2);
     119              : }
     120              : 
     121              : Datum
     122            6 : pg_lsn_ne(PG_FUNCTION_ARGS)
     123              : {
     124            6 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     125            6 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     126              : 
     127            6 :     PG_RETURN_BOOL(lsn1 != lsn2);
     128              : }
     129              : 
     130              : Datum
     131         6980 : pg_lsn_lt(PG_FUNCTION_ARGS)
     132              : {
     133         6980 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     134         6980 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     135              : 
     136         6980 :     PG_RETURN_BOOL(lsn1 < lsn2);
     137              : }
     138              : 
     139              : Datum
     140         2243 : pg_lsn_gt(PG_FUNCTION_ARGS)
     141              : {
     142         2243 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     143         2243 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     144              : 
     145         2243 :     PG_RETURN_BOOL(lsn1 > lsn2);
     146              : }
     147              : 
     148              : Datum
     149         2592 : pg_lsn_le(PG_FUNCTION_ARGS)
     150              : {
     151         2592 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     152         2592 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     153              : 
     154         2592 :     PG_RETURN_BOOL(lsn1 <= lsn2);
     155              : }
     156              : 
     157              : Datum
     158         1694 : pg_lsn_ge(PG_FUNCTION_ARGS)
     159              : {
     160         1694 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     161         1694 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     162              : 
     163         1694 :     PG_RETURN_BOOL(lsn1 >= lsn2);
     164              : }
     165              : 
     166              : Datum
     167           14 : pg_lsn_larger(PG_FUNCTION_ARGS)
     168              : {
     169           14 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     170           14 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     171              : 
     172           14 :     PG_RETURN_LSN((lsn1 > lsn2) ? lsn1 : lsn2);
     173              : }
     174              : 
     175              : Datum
     176            3 : pg_lsn_smaller(PG_FUNCTION_ARGS)
     177              : {
     178            3 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     179            3 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     180              : 
     181            3 :     PG_RETURN_LSN((lsn1 < lsn2) ? lsn1 : lsn2);
     182              : }
     183              : 
     184              : /* btree index opclass support */
     185              : Datum
     186         4778 : pg_lsn_cmp(PG_FUNCTION_ARGS)
     187              : {
     188         4778 :     XLogRecPtr  a = PG_GETARG_LSN(0);
     189         4778 :     XLogRecPtr  b = PG_GETARG_LSN(1);
     190              : 
     191         4778 :     if (a > b)
     192         2452 :         PG_RETURN_INT32(1);
     193         2326 :     else if (a == b)
     194           40 :         PG_RETURN_INT32(0);
     195              :     else
     196         2286 :         PG_RETURN_INT32(-1);
     197              : }
     198              : 
     199              : /* hash index opclass support */
     200              : Datum
     201         2659 : pg_lsn_hash(PG_FUNCTION_ARGS)
     202              : {
     203              :     /* We can use hashint8 directly */
     204         2659 :     return hashint8(fcinfo);
     205              : }
     206              : 
     207              : Datum
     208           30 : pg_lsn_hash_extended(PG_FUNCTION_ARGS)
     209              : {
     210           30 :     return hashint8extended(fcinfo);
     211              : }
     212              : 
     213              : 
     214              : /*----------------------------------------------------------
     215              :  *  Arithmetic operators on PostgreSQL LSNs.
     216              :  *---------------------------------------------------------*/
     217              : 
     218              : Datum
     219         1600 : pg_lsn_mi(PG_FUNCTION_ARGS)
     220              : {
     221         1600 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     222         1600 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     223              :     char        buf[256];
     224              :     Datum       result;
     225              : 
     226              :     /* Output could be as large as plus or minus 2^63 - 1. */
     227         1600 :     if (lsn1 < lsn2)
     228           24 :         snprintf(buf, sizeof buf, "-" UINT64_FORMAT, lsn2 - lsn1);
     229              :     else
     230         1576 :         snprintf(buf, sizeof buf, UINT64_FORMAT, lsn1 - lsn2);
     231              : 
     232              :     /* Convert to numeric. */
     233         1600 :     result = DirectFunctionCall3(numeric_in,
     234              :                                  CStringGetDatum(buf),
     235              :                                  ObjectIdGetDatum(0),
     236              :                                  Int32GetDatum(-1));
     237              : 
     238         1600 :     return result;
     239              : }
     240              : 
     241              : /*
     242              :  * Add the number of bytes to pg_lsn, giving a new pg_lsn.
     243              :  * Must handle both positive and negative numbers of bytes.
     244              :  */
     245              : Datum
     246           32 : pg_lsn_pli(PG_FUNCTION_ARGS)
     247              : {
     248           32 :     XLogRecPtr  lsn = PG_GETARG_LSN(0);
     249           32 :     Numeric     nbytes = PG_GETARG_NUMERIC(1);
     250              :     Datum       num;
     251              :     Datum       res;
     252              :     char        buf[32];
     253              : 
     254           32 :     if (numeric_is_nan(nbytes))
     255            3 :         ereport(ERROR,
     256              :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     257              :                  errmsg("cannot add NaN to pg_lsn")));
     258              : 
     259              :     /* Convert to numeric */
     260           29 :     snprintf(buf, sizeof(buf), UINT64_FORMAT, lsn);
     261           29 :     num = DirectFunctionCall3(numeric_in,
     262              :                               CStringGetDatum(buf),
     263              :                               ObjectIdGetDatum(0),
     264              :                               Int32GetDatum(-1));
     265              : 
     266              :     /* Add two numerics */
     267           29 :     res = DirectFunctionCall2(numeric_add,
     268              :                               num,
     269              :                               NumericGetDatum(nbytes));
     270              : 
     271              :     /* Convert to pg_lsn */
     272           29 :     return DirectFunctionCall1(numeric_pg_lsn, res);
     273              : }
     274              : 
     275              : /*
     276              :  * Subtract the number of bytes from pg_lsn, giving a new pg_lsn.
     277              :  * Must handle both positive and negative numbers of bytes.
     278              :  */
     279              : Datum
     280           18 : pg_lsn_mii(PG_FUNCTION_ARGS)
     281              : {
     282           18 :     XLogRecPtr  lsn = PG_GETARG_LSN(0);
     283           18 :     Numeric     nbytes = PG_GETARG_NUMERIC(1);
     284              :     Datum       num;
     285              :     Datum       res;
     286              :     char        buf[32];
     287              : 
     288           18 :     if (numeric_is_nan(nbytes))
     289            3 :         ereport(ERROR,
     290              :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     291              :                  errmsg("cannot subtract NaN from pg_lsn")));
     292              : 
     293              :     /* Convert to numeric */
     294           15 :     snprintf(buf, sizeof(buf), UINT64_FORMAT, lsn);
     295           15 :     num = DirectFunctionCall3(numeric_in,
     296              :                               CStringGetDatum(buf),
     297              :                               ObjectIdGetDatum(0),
     298              :                               Int32GetDatum(-1));
     299              : 
     300              :     /* Subtract two numerics */
     301           15 :     res = DirectFunctionCall2(numeric_sub,
     302              :                               num,
     303              :                               NumericGetDatum(nbytes));
     304              : 
     305              :     /* Convert to pg_lsn */
     306           15 :     return DirectFunctionCall1(numeric_pg_lsn, res);
     307              : }
        

Generated by: LCOV version 2.0-1