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