/*-------------------------------------------------------------------------
* relpath . c
* Shared frontend / backend code to compute pathnames of relation files
*
* This module also contains some logic associated with fork names .
*
* Portions Copyright ( c ) 1996 - 2025 , PostgreSQL Global Development Group
* Portions Copyright ( c ) 1994 , Regents of the University of California
*
* IDENTIFICATION
* src / common / relpath . c
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
#ifndef FRONTEND
#include "postgres.h"
#else
#include "postgres_fe.h"
#endif
#include "catalog/pg_tablespace_d.h"
#include "common/relpath.h"
#include "storage/procnumber.h"
/*
* Lookup table of fork name by fork number .
*
* If you add a new entry , remember to update the errhint in
* forkname_to_number ( ) below , and update the SGML documentation for
* pg_relation_size ( ) .
*/
const char *const forkNames[] = {
[MAIN_FORKNUM] = "main" ,
[FSM_FORKNUM] = "fsm" ,
[VISIBILITYMAP_FORKNUM] = "vm" ,
[INIT_FORKNUM] = "init" ,
};
StaticAssertDecl(lengthof(forkNames) == (MAX_FORKNUM + 1 ),
"array length mismatch" );
/*
* forkname_to_number - look up fork number by name
*
* In backend , we throw an error for no match ; in frontend , we just
* return InvalidForkNumber .
*/
ForkNumber
forkname_to_number(const char *forkName)
{
ForkNumber forkNum;
for (forkNum = 0 ; forkNum <= MAX_FORKNUM; forkNum++)
if (strcmp(forkNames[forkNum], forkName) == 0 )
return forkNum;
#ifndef FRONTEND
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid fork name" ),
errhint("Valid fork names are \" main\", \" fsm\", "
"\" vm\", and \" init\"." )));
#endif
return InvalidForkNumber;
}
/*
* forkname_chars
* We use this to figure out whether a filename could be a relation
* fork ( as opposed to an oddly named stray file that somehow ended
* up in the database directory ) . If the passed string begins with
* a fork name ( other than the main fork name ) , we return its length ,
* and set * fork ( if not NULL ) to the fork number . If not , we return 0 .
*
* Note that the present coding assumes that there are no fork names which
* are prefixes of other fork names .
*/
int
forkname_chars(const char *str, ForkNumber *fork)
{
ForkNumber forkNum;
for (forkNum = 1 ; forkNum <= MAX_FORKNUM; forkNum++)
{
int len = strlen(forkNames[forkNum]);
if (strncmp(forkNames[forkNum], str, len) == 0 )
{
if (fork)
*fork = forkNum;
return len;
}
}
if (fork)
*fork = InvalidForkNumber;
return 0 ;
}
/*
* GetDatabasePath - construct path to a database directory
*
* Result is a palloc ' d string .
*
* XXX this must agree with GetRelationPath ( ) !
*/
char *
GetDatabasePath(Oid dbOid, Oid spcOid)
{
if (spcOid == GLOBALTABLESPACE_OID)
{
/* Shared system relations live in {datadir}/global */
Assert(dbOid == 0 );
return pstrdup("global" );
}
else if (spcOid == DEFAULTTABLESPACE_OID)
{
/* The default tablespace is {datadir}/base */
return psprintf("base/%u" , dbOid);
}
else
{
/* All other tablespaces are accessed via symlinks */
return psprintf("%s/%u/%s/%u" ,
PG_TBLSPC_DIR, spcOid,
TABLESPACE_VERSION_DIRECTORY, dbOid);
}
}
/*
* GetRelationPath - construct path to a relation ' s file
*
* The result is returned in - place as a struct , to make it suitable for use in
* critical sections etc .
*
* Note : ideally , procNumber would be declared as type ProcNumber , but
* relpath . h would have to include a backend - only header to do that ; doesn ' t
* seem worth the trouble considering ProcNumber is just int anyway .
*/
RelPathStr
GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
int procNumber, ForkNumber forkNumber)
{
RelPathStr rp;
if (spcOid == GLOBALTABLESPACE_OID)
{
/* Shared system relations live in {datadir}/global */
Assert(dbOid == 0 );
Assert(procNumber == INVALID_PROC_NUMBER);
if (forkNumber != MAIN_FORKNUM)
sprintf(rp.str, "global/%u_%s" ,
relNumber, forkNames[forkNumber]);
else
sprintf(rp.str, "global/%u" ,
relNumber);
}
else if (spcOid == DEFAULTTABLESPACE_OID)
{
/* The default tablespace is {datadir}/base */
if (procNumber == INVALID_PROC_NUMBER)
{
if (forkNumber != MAIN_FORKNUM)
{
sprintf(rp.str, "base/%u/%u_%s" ,
dbOid, relNumber,
forkNames[forkNumber]);
}
else
sprintf(rp.str, "base/%u/%u" ,
dbOid, relNumber);
}
else
{
if (forkNumber != MAIN_FORKNUM)
sprintf(rp.str, "base/%u/t%d_%u_%s" ,
dbOid, procNumber, relNumber,
forkNames[forkNumber]);
else
sprintf(rp.str, "base/%u/t%d_%u" ,
dbOid, procNumber, relNumber);
}
}
else
{
/* All other tablespaces are accessed via symlinks */
if (procNumber == INVALID_PROC_NUMBER)
{
if (forkNumber != MAIN_FORKNUM)
sprintf(rp.str, "%s/%u/%s/%u/%u_%s" ,
PG_TBLSPC_DIR, spcOid,
TABLESPACE_VERSION_DIRECTORY,
dbOid, relNumber,
forkNames[forkNumber]);
else
sprintf(rp.str, "%s/%u/%s/%u/%u" ,
PG_TBLSPC_DIR, spcOid,
TABLESPACE_VERSION_DIRECTORY,
dbOid, relNumber);
}
else
{
if (forkNumber != MAIN_FORKNUM)
sprintf(rp.str, "%s/%u/%s/%u/t%d_%u_%s" ,
PG_TBLSPC_DIR, spcOid,
TABLESPACE_VERSION_DIRECTORY,
dbOid, procNumber, relNumber,
forkNames[forkNumber]);
else
sprintf(rp.str, "%s/%u/%s/%u/t%d_%u" ,
PG_TBLSPC_DIR, spcOid,
TABLESPACE_VERSION_DIRECTORY,
dbOid, procNumber, relNumber);
}
}
Assert(strnlen(rp.str, REL_PATH_STR_MAXLEN + 1 ) <= REL_PATH_STR_MAXLEN);
return rp;
}
Messung V0.5 in Prozent C=92 H=91 G=91
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet am 2026-08-10)
¤
*© Formatika GbR, Deutschland