Age Owner TLA 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-2023, 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 : 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
3266 tgl 50 CBC 2865 : forkname_to_number(const char *forkName)
51 : {
52 : ForkNumber forkNum;
53 :
54 2876 : for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
55 2875 : if (strcmp(forkNames[forkNum], forkName) == 0)
56 2864 : 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 :
3266 tgl 66 UBC 0 : 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
3699 alvherre 81 CBC 145789 : forkname_chars(const char *str, ForkNumber *fork)
82 : {
83 : ForkNumber forkNum;
84 :
85 218618 : for (forkNum = 1; forkNum <= MAX_FORKNUM; forkNum++)
86 : {
87 218618 : int len = strlen(forkNames[forkNum]);
88 :
89 218618 : if (strncmp(forkNames[forkNum], str, len) == 0)
90 : {
91 145789 : if (fork)
92 145767 : *fork = forkNum;
93 145789 : return len;
94 : }
95 : }
3266 tgl 96 UBC 0 : if (fork)
97 0 : *fork = InvalidForkNumber;
3699 alvherre 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 *
277 rhaas 110 GNC 213616 : GetDatabasePath(Oid dbOid, Oid spcOid)
111 : {
112 213616 : if (spcOid == GLOBALTABLESPACE_OID)
113 : {
114 : /* Shared system relations live in {datadir}/global */
115 2 : Assert(dbOid == 0);
3266 tgl 116 CBC 2 : return pstrdup("global");
117 : }
277 rhaas 118 GNC 213614 : else if (spcOid == DEFAULTTABLESPACE_OID)
119 : {
120 : /* The default tablespace is {datadir}/base */
121 212252 : return psprintf("base/%u", dbOid);
122 : }
123 : else
124 : {
125 : /* All other tablespaces are accessed via symlinks */
3266 tgl 126 CBC 1362 : 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, backendId would be declared as type BackendId, but relpath.h
137 : * would have to include a backend-only header to do that; doesn't seem worth
138 : * the trouble considering BackendId is just int anyway.
139 : */
140 : char *
277 rhaas 141 GNC 2105549 : GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
142 : int backendId, ForkNumber forkNumber)
143 : {
144 : char *path;
145 :
146 2105549 : if (spcOid == GLOBALTABLESPACE_OID)
147 : {
148 : /* Shared system relations live in {datadir}/global */
149 121833 : Assert(dbOid == 0);
3266 tgl 150 CBC 121833 : Assert(backendId == InvalidBackendId);
151 121833 : if (forkNumber != MAIN_FORKNUM)
193 rhaas 152 33076 : path = psprintf("global/%u_%s",
277 rhaas 153 GNC 33076 : relNumber, forkNames[forkNumber]);
154 : else
193 155 88757 : path = psprintf("global/%u", relNumber);
156 : }
277 157 1983716 : else if (spcOid == DEFAULTTABLESPACE_OID)
158 : {
159 : /* The default tablespace is {datadir}/base */
3266 tgl 160 CBC 1978290 : if (backendId == InvalidBackendId)
161 : {
162 1951910 : if (forkNumber != MAIN_FORKNUM)
193 rhaas 163 694255 : path = psprintf("base/%u/%u_%s",
164 : dbOid, relNumber,
3266 tgl 165 694255 : forkNames[forkNumber]);
166 : else
193 rhaas 167 1257655 : path = psprintf("base/%u/%u",
168 : dbOid, relNumber);
169 : }
170 : else
171 : {
3266 tgl 172 26380 : if (forkNumber != MAIN_FORKNUM)
193 rhaas 173 13992 : path = psprintf("base/%u/t%d_%u_%s",
174 : dbOid, backendId, relNumber,
3266 tgl 175 13992 : forkNames[forkNumber]);
176 : else
193 rhaas 177 12388 : path = psprintf("base/%u/t%d_%u",
178 : dbOid, backendId, relNumber);
179 : }
180 : }
181 : else
182 : {
183 : /* All other tablespaces are accessed via symlinks */
3266 tgl 184 5426 : if (backendId == InvalidBackendId)
185 : {
186 5369 : if (forkNumber != MAIN_FORKNUM)
193 rhaas 187 2328 : path = psprintf("pg_tblspc/%u/%s/%u/%u_%s",
188 : spcOid, TABLESPACE_VERSION_DIRECTORY,
189 : dbOid, relNumber,
3266 tgl 190 2328 : forkNames[forkNumber]);
191 : else
193 rhaas 192 3041 : path = psprintf("pg_tblspc/%u/%s/%u/%u",
193 : spcOid, TABLESPACE_VERSION_DIRECTORY,
194 : dbOid, relNumber);
195 : }
196 : else
197 : {
3266 tgl 198 57 : if (forkNumber != MAIN_FORKNUM)
193 rhaas 199 30 : path = psprintf("pg_tblspc/%u/%s/%u/t%d_%u_%s",
200 : spcOid, TABLESPACE_VERSION_DIRECTORY,
201 : dbOid, backendId, relNumber,
3266 tgl 202 30 : forkNames[forkNumber]);
203 : else
193 rhaas 204 27 : path = psprintf("pg_tblspc/%u/%s/%u/t%d_%u",
205 : spcOid, TABLESPACE_VERSION_DIRECTORY,
206 : dbOid, backendId, relNumber);
207 : }
208 : }
3699 alvherre 209 2105549 : return path;
210 : }
|