LCOV - code coverage report
Current view: top level - src/backend/utils/adt - pg_lsn.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 92 101 91.1 %
Date: 2025-10-02 06:18:21 Functions: 17 19 89.5 %
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-2025, 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        8116 : 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        8116 :     len1 = strspn(str, "0123456789abcdefABCDEF");
      42        8116 :     if (len1 < 1 || len1 > MAXPG_LSNCOMPONENT || str[len1] != '/')
      43          36 :         goto syntax_error;
      44             : 
      45        8080 :     len2 = strspn(str + len1 + 1, "0123456789abcdefABCDEF");
      46        8080 :     if (len2 < 1 || len2 > MAXPG_LSNCOMPONENT || str[len1 + 1 + len2] != '\0')
      47           6 :         goto syntax_error;
      48             : 
      49             :     /* Decode result. */
      50        8074 :     id = (uint32) strtoul(str, NULL, 16);
      51        8074 :     off = (uint32) strtoul(str + len1 + 1, NULL, 16);
      52        8074 :     result = ((uint64) id << 32) | off;
      53             : 
      54        8074 :     return result;
      55             : 
      56          42 : syntax_error:
      57          42 :     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        8098 : pg_lsn_in(PG_FUNCTION_ARGS)
      65             : {
      66        8098 :     char       *str = PG_GETARG_CSTRING(0);
      67             :     XLogRecPtr  result;
      68             : 
      69        8098 :     result = pg_lsn_in_safe(str, fcinfo->context);
      70             : 
      71        8068 :     PG_RETURN_LSN(result);
      72             : }
      73             : 
      74             : Datum
      75        6580 : pg_lsn_out(PG_FUNCTION_ARGS)
      76             : {
      77        6580 :     XLogRecPtr  lsn = PG_GETARG_LSN(0);
      78             :     char        buf[MAXPG_LSNLEN + 1];
      79             :     char       *result;
      80             : 
      81        6580 :     snprintf(buf, sizeof buf, "%X/%08X", LSN_FORMAT_ARGS(lsn));
      82        6580 :     result = pstrdup(buf);
      83        6580 :     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       13488 : pg_lsn_eq(PG_FUNCTION_ARGS)
     114             : {
     115       13488 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     116       13488 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     117             : 
     118       13488 :     PG_RETURN_BOOL(lsn1 == lsn2);
     119             : }
     120             : 
     121             : Datum
     122          12 : pg_lsn_ne(PG_FUNCTION_ARGS)
     123             : {
     124          12 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     125          12 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     126             : 
     127          12 :     PG_RETURN_BOOL(lsn1 != lsn2);
     128             : }
     129             : 
     130             : Datum
     131       13948 : pg_lsn_lt(PG_FUNCTION_ARGS)
     132             : {
     133       13948 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     134       13948 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     135             : 
     136       13948 :     PG_RETURN_BOOL(lsn1 < lsn2);
     137             : }
     138             : 
     139             : Datum
     140        4490 : pg_lsn_gt(PG_FUNCTION_ARGS)
     141             : {
     142        4490 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     143        4490 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     144             : 
     145        4490 :     PG_RETURN_BOOL(lsn1 > lsn2);
     146             : }
     147             : 
     148             : Datum
     149        5294 : pg_lsn_le(PG_FUNCTION_ARGS)
     150             : {
     151        5294 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     152        5294 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     153             : 
     154        5294 :     PG_RETURN_BOOL(lsn1 <= lsn2);
     155             : }
     156             : 
     157             : Datum
     158        3388 : pg_lsn_ge(PG_FUNCTION_ARGS)
     159             : {
     160        3388 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     161        3388 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     162             : 
     163        3388 :     PG_RETURN_BOOL(lsn1 >= lsn2);
     164             : }
     165             : 
     166             : Datum
     167          20 : pg_lsn_larger(PG_FUNCTION_ARGS)
     168             : {
     169          20 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     170          20 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     171             : 
     172          20 :     PG_RETURN_LSN((lsn1 > lsn2) ? lsn1 : lsn2);
     173             : }
     174             : 
     175             : Datum
     176           6 : pg_lsn_smaller(PG_FUNCTION_ARGS)
     177             : {
     178           6 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     179           6 :     XLogRecPtr  lsn2 = PG_GETARG_LSN(1);
     180             : 
     181           6 :     PG_RETURN_LSN((lsn1 < lsn2) ? lsn1 : lsn2);
     182             : }
     183             : 
     184             : /* btree index opclass support */
     185             : Datum
     186        6732 : pg_lsn_cmp(PG_FUNCTION_ARGS)
     187             : {
     188        6732 :     XLogRecPtr  a = PG_GETARG_LSN(0);
     189        6732 :     XLogRecPtr  b = PG_GETARG_LSN(1);
     190             : 
     191        6732 :     if (a > b)
     192        3542 :         PG_RETURN_INT32(1);
     193        3190 :     else if (a == b)
     194          38 :         PG_RETURN_INT32(0);
     195             :     else
     196        3152 :         PG_RETURN_INT32(-1);
     197             : }
     198             : 
     199             : /* hash index opclass support */
     200             : Datum
     201        5314 : pg_lsn_hash(PG_FUNCTION_ARGS)
     202             : {
     203             :     /* We can use hashint8 directly */
     204        5314 :     return hashint8(fcinfo);
     205             : }
     206             : 
     207             : Datum
     208          60 : pg_lsn_hash_extended(PG_FUNCTION_ARGS)
     209             : {
     210          60 :     return hashint8extended(fcinfo);
     211             : }
     212             : 
     213             : 
     214             : /*----------------------------------------------------------
     215             :  *  Arithmetic operators on PostgreSQL LSNs.
     216             :  *---------------------------------------------------------*/
     217             : 
     218             : Datum
     219        3204 : pg_lsn_mi(PG_FUNCTION_ARGS)
     220             : {
     221        3204 :     XLogRecPtr  lsn1 = PG_GETARG_LSN(0);
     222        3204 :     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        3204 :     if (lsn1 < lsn2)
     228          36 :         snprintf(buf, sizeof buf, "-" UINT64_FORMAT, lsn2 - lsn1);
     229             :     else
     230        3168 :         snprintf(buf, sizeof buf, UINT64_FORMAT, lsn1 - lsn2);
     231             : 
     232             :     /* Convert to numeric. */
     233        3204 :     result = DirectFunctionCall3(numeric_in,
     234             :                                  CStringGetDatum(buf),
     235             :                                  ObjectIdGetDatum(0),
     236             :                                  Int32GetDatum(-1));
     237             : 
     238        3204 :     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          60 : pg_lsn_pli(PG_FUNCTION_ARGS)
     247             : {
     248          60 :     XLogRecPtr  lsn = PG_GETARG_LSN(0);
     249          60 :     Numeric     nbytes = PG_GETARG_NUMERIC(1);
     250             :     Datum       num;
     251             :     Datum       res;
     252             :     char        buf[32];
     253             : 
     254          60 :     if (numeric_is_nan(nbytes))
     255           6 :         ereport(ERROR,
     256             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     257             :                  errmsg("cannot add NaN to pg_lsn")));
     258             : 
     259             :     /* Convert to numeric */
     260          54 :     snprintf(buf, sizeof(buf), UINT64_FORMAT, lsn);
     261          54 :     num = DirectFunctionCall3(numeric_in,
     262             :                               CStringGetDatum(buf),
     263             :                               ObjectIdGetDatum(0),
     264             :                               Int32GetDatum(-1));
     265             : 
     266             :     /* Add two numerics */
     267          54 :     res = DirectFunctionCall2(numeric_add,
     268             :                               num,
     269             :                               NumericGetDatum(nbytes));
     270             : 
     271             :     /* Convert to pg_lsn */
     272          54 :     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          36 : pg_lsn_mii(PG_FUNCTION_ARGS)
     281             : {
     282          36 :     XLogRecPtr  lsn = PG_GETARG_LSN(0);
     283          36 :     Numeric     nbytes = PG_GETARG_NUMERIC(1);
     284             :     Datum       num;
     285             :     Datum       res;
     286             :     char        buf[32];
     287             : 
     288          36 :     if (numeric_is_nan(nbytes))
     289           6 :         ereport(ERROR,
     290             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     291             :                  errmsg("cannot subtract NaN from pg_lsn")));
     292             : 
     293             :     /* Convert to numeric */
     294          30 :     snprintf(buf, sizeof(buf), UINT64_FORMAT, lsn);
     295          30 :     num = DirectFunctionCall3(numeric_in,
     296             :                               CStringGetDatum(buf),
     297             :                               ObjectIdGetDatum(0),
     298             :                               Int32GetDatum(-1));
     299             : 
     300             :     /* Subtract two numerics */
     301          30 :     res = DirectFunctionCall2(numeric_sub,
     302             :                               num,
     303             :                               NumericGetDatum(nbytes));
     304             : 
     305             :     /* Convert to pg_lsn */
     306          30 :     return DirectFunctionCall1(numeric_pg_lsn, res);
     307             : }

Generated by: LCOV version 1.16