LCOV - code coverage report
Current view: top level - contrib/pg_logicalinspect - pg_logicalinspect.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 98 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 7 0
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * pg_logicalinspect.c
       4              :  *                Functions to inspect contents of PostgreSQL logical snapshots
       5              :  *
       6              :  * Copyright (c) 2024-2026, PostgreSQL Global Development Group
       7              :  *
       8              :  * IDENTIFICATION
       9              :  *                contrib/pg_logicalinspect/pg_logicalinspect.c
      10              :  *
      11              :  *-------------------------------------------------------------------------
      12              :  */
      13              : #include "postgres.h"
      14              : 
      15              : #include "funcapi.h"
      16              : #include "replication/snapbuild_internal.h"
      17              : #include "utils/array.h"
      18              : #include "utils/builtins.h"
      19              : #include "utils/pg_lsn.h"
      20              : 
      21            0 : PG_MODULE_MAGIC_EXT(
      22              :                                         .name = "pg_logicalinspect",
      23              :                                         .version = PG_VERSION
      24              : );
      25              : 
      26            0 : PG_FUNCTION_INFO_V1(pg_get_logical_snapshot_meta);
      27            0 : PG_FUNCTION_INFO_V1(pg_get_logical_snapshot_info);
      28              : 
      29              : /* Return the description of SnapBuildState */
      30              : static const char *
      31            0 : get_snapbuild_state_desc(SnapBuildState state)
      32              : {
      33            0 :         const char *stateDesc = "unknown state";
      34              : 
      35            0 :         switch (state)
      36              :         {
      37              :                 case SNAPBUILD_START:
      38            0 :                         stateDesc = "start";
      39            0 :                         break;
      40              :                 case SNAPBUILD_BUILDING_SNAPSHOT:
      41            0 :                         stateDesc = "building";
      42            0 :                         break;
      43              :                 case SNAPBUILD_FULL_SNAPSHOT:
      44            0 :                         stateDesc = "full";
      45            0 :                         break;
      46              :                 case SNAPBUILD_CONSISTENT:
      47            0 :                         stateDesc = "consistent";
      48            0 :                         break;
      49              :         }
      50              : 
      51            0 :         return stateDesc;
      52            0 : }
      53              : 
      54              : /*
      55              :  * Extract the LSN from the given serialized snapshot file name.
      56              :  */
      57              : static XLogRecPtr
      58            0 : parse_snapshot_filename(const char *filename)
      59              : {
      60            0 :         uint32          hi;
      61            0 :         uint32          lo;
      62            0 :         XLogRecPtr      lsn;
      63            0 :         char            tmpfname[MAXPGPATH];
      64              : 
      65              :         /*
      66              :          * Extract the values to build the LSN.
      67              :          *
      68              :          * Note: Including ".snap" doesn't mean that sscanf() also does the format
      69              :          * check including the suffix. The subsequent check validates if the given
      70              :          * filename has the expected suffix.
      71              :          */
      72            0 :         if (sscanf(filename, "%X-%X.snap", &hi, &lo) != 2)
      73            0 :                 goto parse_error;
      74              : 
      75              :         /*
      76              :          * Bring back the extracted LSN to the snapshot file format and compare it
      77              :          * to the given filename. This check strictly checks if the given filename
      78              :          * follows the format of the snapshot filename.
      79              :          */
      80            0 :         sprintf(tmpfname, "%X-%X.snap", hi, lo);
      81            0 :         if (strcmp(tmpfname, filename) != 0)
      82            0 :                 goto parse_error;
      83              : 
      84            0 :         lsn = ((uint64) hi) << 32 | lo;
      85              : 
      86            0 :         return lsn;
      87              : 
      88              : parse_error:
      89            0 :         ereport(ERROR,
      90              :                         errmsg("invalid snapshot file name \"%s\"", filename));
      91              : 
      92            0 :         return InvalidXLogRecPtr;       /* keep compiler quiet */
      93            0 : }
      94              : 
      95              : /*
      96              :  * Retrieve the logical snapshot file metadata.
      97              :  */
      98              : Datum
      99            0 : pg_get_logical_snapshot_meta(PG_FUNCTION_ARGS)
     100              : {
     101              : #define PG_GET_LOGICAL_SNAPSHOT_META_COLS 3
     102            0 :         SnapBuildOnDisk ondisk;
     103            0 :         HeapTuple       tuple;
     104            0 :         Datum           values[PG_GET_LOGICAL_SNAPSHOT_META_COLS] = {0};
     105            0 :         bool            nulls[PG_GET_LOGICAL_SNAPSHOT_META_COLS] = {0};
     106            0 :         TupleDesc       tupdesc;
     107            0 :         XLogRecPtr      lsn;
     108            0 :         int                     i = 0;
     109            0 :         text       *filename_t = PG_GETARG_TEXT_PP(0);
     110              : 
     111              :         /* Build a tuple descriptor for our result type */
     112            0 :         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
     113            0 :                 elog(ERROR, "return type must be a row type");
     114              : 
     115            0 :         lsn = parse_snapshot_filename(text_to_cstring(filename_t));
     116              : 
     117              :         /* Validate and restore the snapshot to 'ondisk' */
     118            0 :         SnapBuildRestoreSnapshot(&ondisk, lsn, CurrentMemoryContext, false);
     119              : 
     120            0 :         values[i++] = UInt32GetDatum(ondisk.magic);
     121            0 :         values[i++] = Int64GetDatum((int64) ondisk.checksum);
     122            0 :         values[i++] = UInt32GetDatum(ondisk.version);
     123              : 
     124            0 :         Assert(i == PG_GET_LOGICAL_SNAPSHOT_META_COLS);
     125              : 
     126            0 :         tuple = heap_form_tuple(tupdesc, values, nulls);
     127              : 
     128            0 :         PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
     129              : 
     130              : #undef PG_GET_LOGICAL_SNAPSHOT_META_COLS
     131            0 : }
     132              : 
     133              : Datum
     134            0 : pg_get_logical_snapshot_info(PG_FUNCTION_ARGS)
     135              : {
     136              : #define PG_GET_LOGICAL_SNAPSHOT_INFO_COLS 14
     137            0 :         SnapBuildOnDisk ondisk;
     138            0 :         HeapTuple       tuple;
     139            0 :         Datum           values[PG_GET_LOGICAL_SNAPSHOT_INFO_COLS] = {0};
     140            0 :         bool            nulls[PG_GET_LOGICAL_SNAPSHOT_INFO_COLS] = {0};
     141            0 :         TupleDesc       tupdesc;
     142            0 :         XLogRecPtr      lsn;
     143            0 :         int                     i = 0;
     144            0 :         text       *filename_t = PG_GETARG_TEXT_PP(0);
     145              : 
     146              :         /* Build a tuple descriptor for our result type */
     147            0 :         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
     148            0 :                 elog(ERROR, "return type must be a row type");
     149              : 
     150            0 :         lsn = parse_snapshot_filename(text_to_cstring(filename_t));
     151              : 
     152              :         /* Validate and restore the snapshot to 'ondisk' */
     153            0 :         SnapBuildRestoreSnapshot(&ondisk, lsn, CurrentMemoryContext, false);
     154              : 
     155            0 :         values[i++] = CStringGetTextDatum(get_snapbuild_state_desc(ondisk.builder.state));
     156            0 :         values[i++] = TransactionIdGetDatum(ondisk.builder.xmin);
     157            0 :         values[i++] = TransactionIdGetDatum(ondisk.builder.xmax);
     158            0 :         values[i++] = LSNGetDatum(ondisk.builder.start_decoding_at);
     159            0 :         values[i++] = LSNGetDatum(ondisk.builder.two_phase_at);
     160            0 :         values[i++] = TransactionIdGetDatum(ondisk.builder.initial_xmin_horizon);
     161            0 :         values[i++] = BoolGetDatum(ondisk.builder.building_full_snapshot);
     162            0 :         values[i++] = BoolGetDatum(ondisk.builder.in_slot_creation);
     163            0 :         values[i++] = LSNGetDatum(ondisk.builder.last_serialized_snapshot);
     164            0 :         values[i++] = TransactionIdGetDatum(ondisk.builder.next_phase_at);
     165              : 
     166            0 :         values[i++] = UInt32GetDatum(ondisk.builder.committed.xcnt);
     167            0 :         if (ondisk.builder.committed.xcnt > 0)
     168              :         {
     169            0 :                 Datum      *arrayelems;
     170              : 
     171            0 :                 arrayelems = (Datum *) palloc(ondisk.builder.committed.xcnt * sizeof(Datum));
     172              : 
     173            0 :                 for (int j = 0; j < ondisk.builder.committed.xcnt; j++)
     174            0 :                         arrayelems[j] = TransactionIdGetDatum(ondisk.builder.committed.xip[j]);
     175              : 
     176            0 :                 values[i++] = PointerGetDatum(construct_array_builtin(arrayelems,
     177            0 :                                                                                                                           ondisk.builder.committed.xcnt,
     178              :                                                                                                                           XIDOID));
     179            0 :         }
     180              :         else
     181            0 :                 nulls[i++] = true;
     182              : 
     183            0 :         values[i++] = UInt32GetDatum(ondisk.builder.catchange.xcnt);
     184            0 :         if (ondisk.builder.catchange.xcnt > 0)
     185              :         {
     186            0 :                 Datum      *arrayelems;
     187              : 
     188            0 :                 arrayelems = (Datum *) palloc(ondisk.builder.catchange.xcnt * sizeof(Datum));
     189              : 
     190            0 :                 for (int j = 0; j < ondisk.builder.catchange.xcnt; j++)
     191            0 :                         arrayelems[j] = TransactionIdGetDatum(ondisk.builder.catchange.xip[j]);
     192              : 
     193            0 :                 values[i++] = PointerGetDatum(construct_array_builtin(arrayelems,
     194            0 :                                                                                                                           ondisk.builder.catchange.xcnt,
     195              :                                                                                                                           XIDOID));
     196            0 :         }
     197              :         else
     198            0 :                 nulls[i++] = true;
     199              : 
     200            0 :         Assert(i == PG_GET_LOGICAL_SNAPSHOT_INFO_COLS);
     201              : 
     202            0 :         tuple = heap_form_tuple(tupdesc, values, nulls);
     203              : 
     204            0 :         PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
     205              : 
     206              : #undef PG_GET_LOGICAL_SNAPSHOT_INFO_COLS
     207            0 : }
        

Generated by: LCOV version 2.3.2-1