LCOV - code coverage report
Current view: top level - src/common - relpath.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 93.8 % 48 45
Test Date: 2026-03-12 06:14:44 Functions: 100.0 % 4 4
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  * relpath.c
       3              :  *      Shared frontend/backend code to compute pathnames of relation files
       4              :  *
       5              :  * This module also contains some logic associated with fork names.
       6              :  *
       7              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8              :  * Portions Copyright (c) 1994, Regents of the University of California
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/common/relpath.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : #ifndef FRONTEND
      16              : #include "postgres.h"
      17              : #else
      18              : #include "postgres_fe.h"
      19              : #endif
      20              : 
      21              : #include "catalog/pg_tablespace_d.h"
      22              : #include "common/relpath.h"
      23              : #include "storage/procnumber.h"
      24              : 
      25              : 
      26              : /*
      27              :  * Lookup table of fork name by fork number.
      28              :  *
      29              :  * If you add a new entry, remember to update the errhint in
      30              :  * forkname_to_number() below, and update the SGML documentation for
      31              :  * pg_relation_size().
      32              :  */
      33              : const char *const forkNames[] = {
      34              :     [MAIN_FORKNUM] = "main",
      35              :     [FSM_FORKNUM] = "fsm",
      36              :     [VISIBILITYMAP_FORKNUM] = "vm",
      37              :     [INIT_FORKNUM] = "init",
      38              : };
      39              : 
      40              : StaticAssertDecl(lengthof(forkNames) == (MAX_FORKNUM + 1),
      41              :                  "array length mismatch");
      42              : 
      43              : /*
      44              :  * forkname_to_number - look up fork number by name
      45              :  *
      46              :  * In backend, we throw an error for no match; in frontend, we just
      47              :  * return InvalidForkNumber.
      48              :  */
      49              : ForkNumber
      50         2875 : forkname_to_number(const char *forkName)
      51              : {
      52              :     ForkNumber  forkNum;
      53              : 
      54         2893 :     for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
      55         2891 :         if (strcmp(forkNames[forkNum], forkName) == 0)
      56         2873 :             return forkNum;
      57              : 
      58              : #ifndef FRONTEND
      59            1 :     ereport(ERROR,
      60              :             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      61              :              errmsg("invalid fork name"),
      62              :              errhint("Valid fork names are \"main\", \"fsm\", "
      63              :                      "\"vm\", and \"init\".")));
      64              : #endif
      65              : 
      66            1 :     return InvalidForkNumber;
      67              : }
      68              : 
      69              : /*
      70              :  * forkname_chars
      71              :  *      We use this to figure out whether a filename could be a relation
      72              :  *      fork (as opposed to an oddly named stray file that somehow ended
      73              :  *      up in the database directory).  If the passed string begins with
      74              :  *      a fork name (other than the main fork name), we return its length,
      75              :  *      and set *fork (if not NULL) to the fork number.  If not, we return 0.
      76              :  *
      77              :  * Note that the present coding assumes that there are no fork names which
      78              :  * are prefixes of other fork names.
      79              :  */
      80              : int
      81       211225 : forkname_chars(const char *str, ForkNumber *fork)
      82              : {
      83              :     ForkNumber  forkNum;
      84              : 
      85       316765 :     for (forkNum = 1; forkNum <= MAX_FORKNUM; forkNum++)
      86              :     {
      87       316765 :         int         len = strlen(forkNames[forkNum]);
      88              : 
      89       316765 :         if (strncmp(forkNames[forkNum], str, len) == 0)
      90              :         {
      91       211225 :             if (fork)
      92       211205 :                 *fork = forkNum;
      93       211225 :             return len;
      94              :         }
      95              :     }
      96            0 :     if (fork)
      97            0 :         *fork = InvalidForkNumber;
      98            0 :     return 0;
      99              : }
     100              : 
     101              : 
     102              : /*
     103              :  * GetDatabasePath - construct path to a database directory
     104              :  *
     105              :  * Result is a palloc'd string.
     106              :  *
     107              :  * XXX this must agree with GetRelationPath()!
     108              :  */
     109              : char *
     110       191986 : GetDatabasePath(Oid dbOid, Oid spcOid)
     111              : {
     112       191986 :     if (spcOid == GLOBALTABLESPACE_OID)
     113              :     {
     114              :         /* Shared system relations live in {datadir}/global */
     115              :         Assert(dbOid == 0);
     116            2 :         return pstrdup("global");
     117              :     }
     118       191984 :     else if (spcOid == DEFAULTTABLESPACE_OID)
     119              :     {
     120              :         /* The default tablespace is {datadir}/base */
     121       188868 :         return psprintf("base/%u", dbOid);
     122              :     }
     123              :     else
     124              :     {
     125              :         /* All other tablespaces are accessed via symlinks */
     126         3116 :         return psprintf("%s/%u/%s/%u",
     127              :                         PG_TBLSPC_DIR, spcOid,
     128              :                         TABLESPACE_VERSION_DIRECTORY, dbOid);
     129              :     }
     130              : }
     131              : 
     132              : /*
     133              :  * GetRelationPath - construct path to a relation's file
     134              :  *
     135              :  * The result is returned in-place as a struct, to make it suitable for use in
     136              :  * critical sections etc.
     137              :  *
     138              :  * Note: ideally, procNumber would be declared as type ProcNumber, but
     139              :  * relpath.h would have to include a backend-only header to do that; doesn't
     140              :  * seem worth the trouble considering ProcNumber is just int anyway.
     141              :  */
     142              : RelPathStr
     143      1993437 : GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
     144              :                 int procNumber, ForkNumber forkNumber)
     145              : {
     146              :     RelPathStr  rp;
     147              : 
     148      1993437 :     if (spcOid == GLOBALTABLESPACE_OID)
     149              :     {
     150              :         /* Shared system relations live in {datadir}/global */
     151              :         Assert(dbOid == 0);
     152              :         Assert(procNumber == INVALID_PROC_NUMBER);
     153       115379 :         if (forkNumber != MAIN_FORKNUM)
     154        35557 :             sprintf(rp.str, "global/%u_%s",
     155        35557 :                     relNumber, forkNames[forkNumber]);
     156              :         else
     157        79822 :             sprintf(rp.str, "global/%u",
     158              :                     relNumber);
     159              :     }
     160      1878058 :     else if (spcOid == DEFAULTTABLESPACE_OID)
     161              :     {
     162              :         /* The default tablespace is {datadir}/base */
     163      1862835 :         if (procNumber == INVALID_PROC_NUMBER)
     164              :         {
     165      1832275 :             if (forkNumber != MAIN_FORKNUM)
     166              :             {
     167       737409 :                 sprintf(rp.str, "base/%u/%u_%s",
     168              :                         dbOid, relNumber,
     169       737409 :                         forkNames[forkNumber]);
     170              :             }
     171              :             else
     172      1094866 :                 sprintf(rp.str, "base/%u/%u",
     173              :                         dbOid, relNumber);
     174              :         }
     175              :         else
     176              :         {
     177        30560 :             if (forkNumber != MAIN_FORKNUM)
     178        15832 :                 sprintf(rp.str, "base/%u/t%d_%u_%s",
     179              :                         dbOid, procNumber, relNumber,
     180        15832 :                         forkNames[forkNumber]);
     181              :             else
     182        14728 :                 sprintf(rp.str, "base/%u/t%d_%u",
     183              :                         dbOid, procNumber, relNumber);
     184              :         }
     185              :     }
     186              :     else
     187              :     {
     188              :         /* All other tablespaces are accessed via symlinks */
     189        15223 :         if (procNumber == INVALID_PROC_NUMBER)
     190              :         {
     191        15163 :             if (forkNumber != MAIN_FORKNUM)
     192         6693 :                 sprintf(rp.str, "%s/%u/%s/%u/%u_%s",
     193              :                         PG_TBLSPC_DIR, spcOid,
     194              :                         TABLESPACE_VERSION_DIRECTORY,
     195              :                         dbOid, relNumber,
     196         6693 :                         forkNames[forkNumber]);
     197              :             else
     198         8470 :                 sprintf(rp.str, "%s/%u/%s/%u/%u",
     199              :                         PG_TBLSPC_DIR, spcOid,
     200              :                         TABLESPACE_VERSION_DIRECTORY,
     201              :                         dbOid, relNumber);
     202              :         }
     203              :         else
     204              :         {
     205           60 :             if (forkNumber != MAIN_FORKNUM)
     206           33 :                 sprintf(rp.str, "%s/%u/%s/%u/t%d_%u_%s",
     207              :                         PG_TBLSPC_DIR, spcOid,
     208              :                         TABLESPACE_VERSION_DIRECTORY,
     209              :                         dbOid, procNumber, relNumber,
     210           33 :                         forkNames[forkNumber]);
     211              :             else
     212           27 :                 sprintf(rp.str, "%s/%u/%s/%u/t%d_%u",
     213              :                         PG_TBLSPC_DIR, spcOid,
     214              :                         TABLESPACE_VERSION_DIRECTORY,
     215              :                         dbOid, procNumber, relNumber);
     216              :         }
     217              :     }
     218              : 
     219              :     Assert(strnlen(rp.str, REL_PATH_STR_MAXLEN + 1) <= REL_PATH_STR_MAXLEN);
     220              : 
     221      1993437 :     return rp;
     222              : }
        

Generated by: LCOV version 2.0-1