PostgreSQL Source Code  git master
relpath.c
Go to the documentation of this file.
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-2024, 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 
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  */
50 forkname_to_number(const char *forkName)
51 {
52  ForkNumber forkNum;
53 
54  for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
55  if (strcmp(forkNames[forkNum], forkName) == 0)
56  return forkNum;
57 
58 #ifndef FRONTEND
59  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  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 forkname_chars(const char *str, ForkNumber *fork)
82 {
83  ForkNumber forkNum;
84 
85  for (forkNum = 1; forkNum <= MAX_FORKNUM; forkNum++)
86  {
87  int len = strlen(forkNames[forkNum]);
88 
89  if (strncmp(forkNames[forkNum], str, len) == 0)
90  {
91  if (fork)
92  *fork = forkNum;
93  return len;
94  }
95  }
96  if (fork)
97  *fork = InvalidForkNumber;
98  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 GetDatabasePath(Oid dbOid, Oid spcOid)
111 {
112  if (spcOid == GLOBALTABLESPACE_OID)
113  {
114  /* Shared system relations live in {datadir}/global */
115  Assert(dbOid == 0);
116  return pstrdup("global");
117  }
118  else if (spcOid == DEFAULTTABLESPACE_OID)
119  {
120  /* The default tablespace is {datadir}/base */
121  return psprintf("base/%u", dbOid);
122  }
123  else
124  {
125  /* All other tablespaces are accessed via symlinks */
126  return psprintf("pg_tblspc/%u/%s/%u",
127  spcOid, TABLESPACE_VERSION_DIRECTORY, dbOid);
128  }
129 }
130 
131 /*
132  * GetRelationPath - construct path to a relation's file
133  *
134  * Result is a palloc'd string.
135  *
136  * Note: ideally, procNumber would be declared as type ProcNumber, but
137  * relpath.h would have to include a backend-only header to do that; doesn't
138  * seem worth the trouble considering ProcNumber is just int anyway.
139  */
140 char *
141 GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
142  int procNumber, ForkNumber forkNumber)
143 {
144  char *path;
145 
146  if (spcOid == GLOBALTABLESPACE_OID)
147  {
148  /* Shared system relations live in {datadir}/global */
149  Assert(dbOid == 0);
150  Assert(procNumber == INVALID_PROC_NUMBER);
151  if (forkNumber != MAIN_FORKNUM)
152  path = psprintf("global/%u_%s",
153  relNumber, forkNames[forkNumber]);
154  else
155  path = psprintf("global/%u", relNumber);
156  }
157  else if (spcOid == DEFAULTTABLESPACE_OID)
158  {
159  /* The default tablespace is {datadir}/base */
160  if (procNumber == INVALID_PROC_NUMBER)
161  {
162  if (forkNumber != MAIN_FORKNUM)
163  path = psprintf("base/%u/%u_%s",
164  dbOid, relNumber,
165  forkNames[forkNumber]);
166  else
167  path = psprintf("base/%u/%u",
168  dbOid, relNumber);
169  }
170  else
171  {
172  if (forkNumber != MAIN_FORKNUM)
173  path = psprintf("base/%u/t%d_%u_%s",
174  dbOid, procNumber, relNumber,
175  forkNames[forkNumber]);
176  else
177  path = psprintf("base/%u/t%d_%u",
178  dbOid, procNumber, relNumber);
179  }
180  }
181  else
182  {
183  /* All other tablespaces are accessed via symlinks */
184  if (procNumber == INVALID_PROC_NUMBER)
185  {
186  if (forkNumber != MAIN_FORKNUM)
187  path = psprintf("pg_tblspc/%u/%s/%u/%u_%s",
189  dbOid, relNumber,
190  forkNames[forkNumber]);
191  else
192  path = psprintf("pg_tblspc/%u/%s/%u/%u",
194  dbOid, relNumber);
195  }
196  else
197  {
198  if (forkNumber != MAIN_FORKNUM)
199  path = psprintf("pg_tblspc/%u/%s/%u/t%d_%u_%s",
201  dbOid, procNumber, relNumber,
202  forkNames[forkNumber]);
203  else
204  path = psprintf("pg_tblspc/%u/%s/%u/t%d_%u",
206  dbOid, procNumber, relNumber);
207  }
208  }
209  return path;
210 }
#define lengthof(array)
Definition: c.h:775
int errhint(const char *fmt,...)
Definition: elog.c:1319
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
Assert(fmt[strlen(fmt) - 1] !='\n')
char * pstrdup(const char *in)
Definition: mcxt.c:1683
const void size_t len
unsigned int Oid
Definition: postgres_ext.h:31
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
StaticAssertDecl(lengthof(forkNames)==(MAX_FORKNUM+1), "array length mismatch")
char * GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber, int procNumber, ForkNumber forkNumber)
Definition: relpath.c:141
char * GetDatabasePath(Oid dbOid, Oid spcOid)
Definition: relpath.c:110
int forkname_chars(const char *str, ForkNumber *fork)
Definition: relpath.c:81
ForkNumber forkname_to_number(const char *forkName)
Definition: relpath.c:50
const char *const forkNames[]
Definition: relpath.c:33
Oid RelFileNumber
Definition: relpath.h:25
ForkNumber
Definition: relpath.h:48
@ FSM_FORKNUM
Definition: relpath.h:51
@ VISIBILITYMAP_FORKNUM
Definition: relpath.h:52
@ MAIN_FORKNUM
Definition: relpath.h:50
@ InvalidForkNumber
Definition: relpath.h:49
@ INIT_FORKNUM
Definition: relpath.h:53
#define MAX_FORKNUM
Definition: relpath.h:62
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33