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-2018, 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/backendid.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", /* MAIN_FORKNUM */
35  "fsm", /* FSM_FORKNUM */
36  "vm", /* VISIBILITYMAP_FORKNUM */
37  "init" /* INIT_FORKNUM */
38 };
39 
40 /*
41  * forkname_to_number - look up fork number by name
42  *
43  * In backend, we throw an error for no match; in frontend, we just
44  * return InvalidForkNumber.
45  */
47 forkname_to_number(const char *forkName)
48 {
49  ForkNumber forkNum;
50 
51  for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
52  if (strcmp(forkNames[forkNum], forkName) == 0)
53  return forkNum;
54 
55 #ifndef FRONTEND
56  ereport(ERROR,
57  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
58  errmsg("invalid fork name"),
59  errhint("Valid fork names are \"main\", \"fsm\", "
60  "\"vm\", and \"init\".")));
61 #endif
62 
63  return InvalidForkNumber;
64 }
65 
66 /*
67  * forkname_chars
68  * We use this to figure out whether a filename could be a relation
69  * fork (as opposed to an oddly named stray file that somehow ended
70  * up in the database directory). If the passed string begins with
71  * a fork name (other than the main fork name), we return its length,
72  * and set *fork (if not NULL) to the fork number. If not, we return 0.
73  *
74  * Note that the present coding assumes that there are no fork names which
75  * are prefixes of other fork names.
76  */
77 int
78 forkname_chars(const char *str, ForkNumber *fork)
79 {
80  ForkNumber forkNum;
81 
82  for (forkNum = 1; forkNum <= MAX_FORKNUM; forkNum++)
83  {
84  int len = strlen(forkNames[forkNum]);
85 
86  if (strncmp(forkNames[forkNum], str, len) == 0)
87  {
88  if (fork)
89  *fork = forkNum;
90  return len;
91  }
92  }
93  if (fork)
94  *fork = InvalidForkNumber;
95  return 0;
96 }
97 
98 
99 /*
100  * GetDatabasePath - construct path to a database directory
101  *
102  * Result is a palloc'd string.
103  *
104  * XXX this must agree with GetRelationPath()!
105  */
106 char *
107 GetDatabasePath(Oid dbNode, Oid spcNode)
108 {
109  if (spcNode == GLOBALTABLESPACE_OID)
110  {
111  /* Shared system relations live in {datadir}/global */
112  Assert(dbNode == 0);
113  return pstrdup("global");
114  }
115  else if (spcNode == DEFAULTTABLESPACE_OID)
116  {
117  /* The default tablespace is {datadir}/base */
118  return psprintf("base/%u", dbNode);
119  }
120  else
121  {
122  /* All other tablespaces are accessed via symlinks */
123  return psprintf("pg_tblspc/%u/%s/%u",
124  spcNode, TABLESPACE_VERSION_DIRECTORY, dbNode);
125  }
126 }
127 
128 /*
129  * GetRelationPath - construct path to a relation's file
130  *
131  * Result is a palloc'd string.
132  *
133  * Note: ideally, backendId would be declared as type BackendId, but relpath.h
134  * would have to include a backend-only header to do that; doesn't seem worth
135  * the trouble considering BackendId is just int anyway.
136  */
137 char *
138 GetRelationPath(Oid dbNode, Oid spcNode, Oid relNode,
139  int backendId, ForkNumber forkNumber)
140 {
141  char *path;
142 
143  if (spcNode == GLOBALTABLESPACE_OID)
144  {
145  /* Shared system relations live in {datadir}/global */
146  Assert(dbNode == 0);
147  Assert(backendId == InvalidBackendId);
148  if (forkNumber != MAIN_FORKNUM)
149  path = psprintf("global/%u_%s",
150  relNode, forkNames[forkNumber]);
151  else
152  path = psprintf("global/%u", relNode);
153  }
154  else if (spcNode == DEFAULTTABLESPACE_OID)
155  {
156  /* The default tablespace is {datadir}/base */
157  if (backendId == InvalidBackendId)
158  {
159  if (forkNumber != MAIN_FORKNUM)
160  path = psprintf("base/%u/%u_%s",
161  dbNode, relNode,
162  forkNames[forkNumber]);
163  else
164  path = psprintf("base/%u/%u",
165  dbNode, relNode);
166  }
167  else
168  {
169  if (forkNumber != MAIN_FORKNUM)
170  path = psprintf("base/%u/t%d_%u_%s",
171  dbNode, backendId, relNode,
172  forkNames[forkNumber]);
173  else
174  path = psprintf("base/%u/t%d_%u",
175  dbNode, backendId, relNode);
176  }
177  }
178  else
179  {
180  /* All other tablespaces are accessed via symlinks */
181  if (backendId == InvalidBackendId)
182  {
183  if (forkNumber != MAIN_FORKNUM)
184  path = psprintf("pg_tblspc/%u/%s/%u/%u_%s",
186  dbNode, relNode,
187  forkNames[forkNumber]);
188  else
189  path = psprintf("pg_tblspc/%u/%s/%u/%u",
191  dbNode, relNode);
192  }
193  else
194  {
195  if (forkNumber != MAIN_FORKNUM)
196  path = psprintf("pg_tblspc/%u/%s/%u/t%d_%u_%s",
198  dbNode, backendId, relNode,
199  forkNames[forkNumber]);
200  else
201  path = psprintf("pg_tblspc/%u/%s/%u/t%d_%u",
203  dbNode, backendId, relNode);
204  }
205  }
206  return path;
207 }
int errhint(const char *fmt,...)
Definition: elog.c:987
char * GetRelationPath(Oid dbNode, Oid spcNode, Oid relNode, int backendId, ForkNumber forkNumber)
Definition: relpath.c:138
char * pstrdup(const char *in)
Definition: mcxt.c:1161
int forkname_chars(const char *str, ForkNumber *fork)
Definition: relpath.c:78
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
ForkNumber forkname_to_number(const char *forkName)
Definition: relpath.c:47
#define ERROR
Definition: elog.h:43
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:26
#define ereport(elevel, rest)
Definition: elog.h:122
char * GetDatabasePath(Oid dbNode, Oid spcNode)
Definition: relpath.c:107
ForkNumber
Definition: relpath.h:40
#define InvalidBackendId
Definition: backendid.h:23
#define Assert(condition)
Definition: c.h:699
#define MAX_FORKNUM
Definition: relpath.h:55
int errmsg(const char *fmt,...)
Definition: elog.c:797
const char *const forkNames[]
Definition: relpath.c:33