1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * catalog.c |
4 | * routines concerned with catalog naming conventions and other |
5 | * bits of hard-wired knowledge |
6 | * |
7 | * |
8 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
9 | * Portions Copyright (c) 1994, Regents of the University of California |
10 | * |
11 | * |
12 | * IDENTIFICATION |
13 | * src/backend/catalog/catalog.c |
14 | * |
15 | *------------------------------------------------------------------------- |
16 | */ |
17 | |
18 | #include "postgres.h" |
19 | |
20 | #include <fcntl.h> |
21 | #include <unistd.h> |
22 | |
23 | #include "access/genam.h" |
24 | #include "access/htup_details.h" |
25 | #include "access/sysattr.h" |
26 | #include "access/table.h" |
27 | #include "access/transam.h" |
28 | #include "catalog/catalog.h" |
29 | #include "catalog/indexing.h" |
30 | #include "catalog/namespace.h" |
31 | #include "catalog/pg_auth_members.h" |
32 | #include "catalog/pg_authid.h" |
33 | #include "catalog/pg_database.h" |
34 | #include "catalog/pg_namespace.h" |
35 | #include "catalog/pg_pltemplate.h" |
36 | #include "catalog/pg_db_role_setting.h" |
37 | #include "catalog/pg_replication_origin.h" |
38 | #include "catalog/pg_shdepend.h" |
39 | #include "catalog/pg_shdescription.h" |
40 | #include "catalog/pg_shseclabel.h" |
41 | #include "catalog/pg_subscription.h" |
42 | #include "catalog/pg_tablespace.h" |
43 | #include "catalog/pg_type.h" |
44 | #include "catalog/toasting.h" |
45 | #include "miscadmin.h" |
46 | #include "storage/fd.h" |
47 | #include "utils/fmgroids.h" |
48 | #include "utils/fmgrprotos.h" |
49 | #include "utils/rel.h" |
50 | #include "utils/snapmgr.h" |
51 | #include "utils/syscache.h" |
52 | |
53 | |
54 | /* |
55 | * IsSystemRelation |
56 | * True iff the relation is either a system catalog or a toast table. |
57 | * See IsCatalogRelation for the exact definition of a system catalog. |
58 | * |
59 | * We treat toast tables of user relations as "system relations" for |
60 | * protection purposes, e.g. you can't change their schemas without |
61 | * special permissions. Therefore, most uses of this function are |
62 | * checking whether allow_system_table_mods restrictions apply. |
63 | * For other purposes, consider whether you shouldn't be using |
64 | * IsCatalogRelation instead. |
65 | * |
66 | * This function does not perform any catalog accesses. |
67 | * Some callers rely on that! |
68 | */ |
69 | bool |
70 | IsSystemRelation(Relation relation) |
71 | { |
72 | return IsSystemClass(RelationGetRelid(relation), relation->rd_rel); |
73 | } |
74 | |
75 | /* |
76 | * IsSystemClass |
77 | * Like the above, but takes a Form_pg_class as argument. |
78 | * Used when we do not want to open the relation and have to |
79 | * search pg_class directly. |
80 | */ |
81 | bool |
82 | IsSystemClass(Oid relid, Form_pg_class reltuple) |
83 | { |
84 | /* IsCatalogRelationOid is a bit faster, so test that first */ |
85 | return (IsCatalogRelationOid(relid) || IsToastClass(reltuple)); |
86 | } |
87 | |
88 | /* |
89 | * IsCatalogRelation |
90 | * True iff the relation is a system catalog. |
91 | * |
92 | * By a system catalog, we mean one that is created during the bootstrap |
93 | * phase of initdb. That includes not just the catalogs per se, but |
94 | * also their indexes, and TOAST tables and indexes if any. |
95 | * |
96 | * This function does not perform any catalog accesses. |
97 | * Some callers rely on that! |
98 | */ |
99 | bool |
100 | IsCatalogRelation(Relation relation) |
101 | { |
102 | return IsCatalogRelationOid(RelationGetRelid(relation)); |
103 | } |
104 | |
105 | /* |
106 | * IsCatalogRelationOid |
107 | * True iff the relation identified by this OID is a system catalog. |
108 | * |
109 | * By a system catalog, we mean one that is created during the bootstrap |
110 | * phase of initdb. That includes not just the catalogs per se, but |
111 | * also their indexes, and TOAST tables and indexes if any. |
112 | * |
113 | * This function does not perform any catalog accesses. |
114 | * Some callers rely on that! |
115 | */ |
116 | bool |
117 | IsCatalogRelationOid(Oid relid) |
118 | { |
119 | /* |
120 | * We consider a relation to be a system catalog if it has an OID that was |
121 | * manually assigned or assigned by genbki.pl. This includes all the |
122 | * defined catalogs, their indexes, and their TOAST tables and indexes. |
123 | * |
124 | * This rule excludes the relations in information_schema, which are not |
125 | * integral to the system and can be treated the same as user relations. |
126 | * (Since it's valid to drop and recreate information_schema, any rule |
127 | * that did not act this way would be wrong.) |
128 | * |
129 | * This test is reliable since an OID wraparound will skip this range of |
130 | * OIDs; see GetNewObjectId(). |
131 | */ |
132 | return (relid < (Oid) FirstBootstrapObjectId); |
133 | } |
134 | |
135 | /* |
136 | * IsToastRelation |
137 | * True iff relation is a TOAST support relation (or index). |
138 | * |
139 | * Does not perform any catalog accesses. |
140 | */ |
141 | bool |
142 | IsToastRelation(Relation relation) |
143 | { |
144 | /* |
145 | * What we actually check is whether the relation belongs to a pg_toast |
146 | * namespace. This should be equivalent because of restrictions that are |
147 | * enforced elsewhere against creating user relations in, or moving |
148 | * relations into/out of, a pg_toast namespace. Notice also that this |
149 | * will not say "true" for toast tables belonging to other sessions' temp |
150 | * tables; we expect that other mechanisms will prevent access to those. |
151 | */ |
152 | return IsToastNamespace(RelationGetNamespace(relation)); |
153 | } |
154 | |
155 | /* |
156 | * IsToastClass |
157 | * Like the above, but takes a Form_pg_class as argument. |
158 | * Used when we do not want to open the relation and have to |
159 | * search pg_class directly. |
160 | */ |
161 | bool |
162 | IsToastClass(Form_pg_class reltuple) |
163 | { |
164 | Oid relnamespace = reltuple->relnamespace; |
165 | |
166 | return IsToastNamespace(relnamespace); |
167 | } |
168 | |
169 | /* |
170 | * IsCatalogNamespace |
171 | * True iff namespace is pg_catalog. |
172 | * |
173 | * Does not perform any catalog accesses. |
174 | * |
175 | * NOTE: the reason this isn't a macro is to avoid having to include |
176 | * catalog/pg_namespace.h in a lot of places. |
177 | */ |
178 | bool |
179 | IsCatalogNamespace(Oid namespaceId) |
180 | { |
181 | return namespaceId == PG_CATALOG_NAMESPACE; |
182 | } |
183 | |
184 | /* |
185 | * IsToastNamespace |
186 | * True iff namespace is pg_toast or my temporary-toast-table namespace. |
187 | * |
188 | * Does not perform any catalog accesses. |
189 | * |
190 | * Note: this will return false for temporary-toast-table namespaces belonging |
191 | * to other backends. Those are treated the same as other backends' regular |
192 | * temp table namespaces, and access is prevented where appropriate. |
193 | * If you need to check for those, you may be able to use isAnyTempNamespace, |
194 | * but beware that that does involve a catalog access. |
195 | */ |
196 | bool |
197 | IsToastNamespace(Oid namespaceId) |
198 | { |
199 | return (namespaceId == PG_TOAST_NAMESPACE) || |
200 | isTempToastNamespace(namespaceId); |
201 | } |
202 | |
203 | |
204 | /* |
205 | * IsReservedName |
206 | * True iff name starts with the pg_ prefix. |
207 | * |
208 | * For some classes of objects, the prefix pg_ is reserved for |
209 | * system objects only. As of 8.0, this was only true for |
210 | * schema and tablespace names. With 9.6, this is also true |
211 | * for roles. |
212 | */ |
213 | bool |
214 | IsReservedName(const char *name) |
215 | { |
216 | /* ugly coding for speed */ |
217 | return (name[0] == 'p' && |
218 | name[1] == 'g' && |
219 | name[2] == '_'); |
220 | } |
221 | |
222 | |
223 | /* |
224 | * IsSharedRelation |
225 | * Given the OID of a relation, determine whether it's supposed to be |
226 | * shared across an entire database cluster. |
227 | * |
228 | * In older releases, this had to be hard-wired so that we could compute the |
229 | * locktag for a relation and lock it before examining its catalog entry. |
230 | * Since we now have MVCC catalog access, the race conditions that made that |
231 | * a hard requirement are gone, so we could look at relaxing this restriction. |
232 | * However, if we scanned the pg_class entry to find relisshared, and only |
233 | * then locked the relation, pg_class could get updated in the meantime, |
234 | * forcing us to scan the relation again, which would definitely be complex |
235 | * and might have undesirable performance consequences. Fortunately, the set |
236 | * of shared relations is fairly static, so a hand-maintained list of their |
237 | * OIDs isn't completely impractical. |
238 | */ |
239 | bool |
240 | IsSharedRelation(Oid relationId) |
241 | { |
242 | /* These are the shared catalogs (look for BKI_SHARED_RELATION) */ |
243 | if (relationId == AuthIdRelationId || |
244 | relationId == AuthMemRelationId || |
245 | relationId == DatabaseRelationId || |
246 | relationId == PLTemplateRelationId || |
247 | relationId == SharedDescriptionRelationId || |
248 | relationId == SharedDependRelationId || |
249 | relationId == SharedSecLabelRelationId || |
250 | relationId == TableSpaceRelationId || |
251 | relationId == DbRoleSettingRelationId || |
252 | relationId == ReplicationOriginRelationId || |
253 | relationId == SubscriptionRelationId) |
254 | return true; |
255 | /* These are their indexes (see indexing.h) */ |
256 | if (relationId == AuthIdRolnameIndexId || |
257 | relationId == AuthIdOidIndexId || |
258 | relationId == AuthMemRoleMemIndexId || |
259 | relationId == AuthMemMemRoleIndexId || |
260 | relationId == DatabaseNameIndexId || |
261 | relationId == DatabaseOidIndexId || |
262 | relationId == PLTemplateNameIndexId || |
263 | relationId == SharedDescriptionObjIndexId || |
264 | relationId == SharedDependDependerIndexId || |
265 | relationId == SharedDependReferenceIndexId || |
266 | relationId == SharedSecLabelObjectIndexId || |
267 | relationId == TablespaceOidIndexId || |
268 | relationId == TablespaceNameIndexId || |
269 | relationId == DbRoleSettingDatidRolidIndexId || |
270 | relationId == ReplicationOriginIdentIndex || |
271 | relationId == ReplicationOriginNameIndex || |
272 | relationId == SubscriptionObjectIndexId || |
273 | relationId == SubscriptionNameIndexId) |
274 | return true; |
275 | /* These are their toast tables and toast indexes (see toasting.h) */ |
276 | if (relationId == PgAuthidToastTable || |
277 | relationId == PgAuthidToastIndex || |
278 | relationId == PgDatabaseToastTable || |
279 | relationId == PgDatabaseToastIndex || |
280 | relationId == PgDbRoleSettingToastTable || |
281 | relationId == PgDbRoleSettingToastIndex || |
282 | relationId == PgPlTemplateToastTable || |
283 | relationId == PgPlTemplateToastIndex || |
284 | relationId == PgReplicationOriginToastTable || |
285 | relationId == PgReplicationOriginToastIndex || |
286 | relationId == PgShdescriptionToastTable || |
287 | relationId == PgShdescriptionToastIndex || |
288 | relationId == PgShseclabelToastTable || |
289 | relationId == PgShseclabelToastIndex || |
290 | relationId == PgSubscriptionToastTable || |
291 | relationId == PgSubscriptionToastIndex || |
292 | relationId == PgTablespaceToastTable || |
293 | relationId == PgTablespaceToastIndex) |
294 | return true; |
295 | return false; |
296 | } |
297 | |
298 | |
299 | /* |
300 | * GetNewOidWithIndex |
301 | * Generate a new OID that is unique within the system relation. |
302 | * |
303 | * Since the OID is not immediately inserted into the table, there is a |
304 | * race condition here; but a problem could occur only if someone else |
305 | * managed to cycle through 2^32 OIDs and generate the same OID before we |
306 | * finish inserting our row. This seems unlikely to be a problem. Note |
307 | * that if we had to *commit* the row to end the race condition, the risk |
308 | * would be rather higher; therefore we use SnapshotAny in the test, so that |
309 | * we will see uncommitted rows. (We used to use SnapshotDirty, but that has |
310 | * the disadvantage that it ignores recently-deleted rows, creating a risk |
311 | * of transient conflicts for as long as our own MVCC snapshots think a |
312 | * recently-deleted row is live. The risk is far higher when selecting TOAST |
313 | * OIDs, because SnapshotToast considers dead rows as active indefinitely.) |
314 | * |
315 | * Note that we are effectively assuming that the table has a relatively small |
316 | * number of entries (much less than 2^32) and there aren't very long runs of |
317 | * consecutive existing OIDs. This is a mostly reasonable assumption for |
318 | * system catalogs. |
319 | * |
320 | * This is exported separately because there are cases where we want to use |
321 | * an index that will not be recognized by RelationGetOidIndex: TOAST tables |
322 | * have indexes that are usable, but have multiple columns and are on |
323 | * ordinary columns rather than a true OID column. This code will work |
324 | * anyway, so long as the OID is the index's first column. The caller must |
325 | * pass in the actual heap attnum of the OID column, however. |
326 | * |
327 | * Caller must have a suitable lock on the relation. |
328 | */ |
329 | Oid |
330 | GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn) |
331 | { |
332 | Oid newOid; |
333 | SysScanDesc scan; |
334 | ScanKeyData key; |
335 | bool collides; |
336 | |
337 | /* Only system relations are supported */ |
338 | Assert(IsSystemRelation(relation)); |
339 | |
340 | /* In bootstrap mode, we don't have any indexes to use */ |
341 | if (IsBootstrapProcessingMode()) |
342 | return GetNewObjectId(); |
343 | |
344 | /* |
345 | * We should never be asked to generate a new pg_type OID during |
346 | * pg_upgrade; doing so would risk collisions with the OIDs it wants to |
347 | * assign. Hitting this assert means there's some path where we failed to |
348 | * ensure that a type OID is determined by commands in the dump script. |
349 | */ |
350 | Assert(!IsBinaryUpgrade || RelationGetRelid(relation) != TypeRelationId); |
351 | |
352 | /* Generate new OIDs until we find one not in the table */ |
353 | do |
354 | { |
355 | CHECK_FOR_INTERRUPTS(); |
356 | |
357 | newOid = GetNewObjectId(); |
358 | |
359 | ScanKeyInit(&key, |
360 | oidcolumn, |
361 | BTEqualStrategyNumber, F_OIDEQ, |
362 | ObjectIdGetDatum(newOid)); |
363 | |
364 | /* see notes above about using SnapshotAny */ |
365 | scan = systable_beginscan(relation, indexId, true, |
366 | SnapshotAny, 1, &key); |
367 | |
368 | collides = HeapTupleIsValid(systable_getnext(scan)); |
369 | |
370 | systable_endscan(scan); |
371 | } while (collides); |
372 | |
373 | return newOid; |
374 | } |
375 | |
376 | /* |
377 | * GetNewRelFileNode |
378 | * Generate a new relfilenode number that is unique within the |
379 | * database of the given tablespace. |
380 | * |
381 | * If the relfilenode will also be used as the relation's OID, pass the |
382 | * opened pg_class catalog, and this routine will guarantee that the result |
383 | * is also an unused OID within pg_class. If the result is to be used only |
384 | * as a relfilenode for an existing relation, pass NULL for pg_class. |
385 | * |
386 | * As with GetNewOidWithIndex(), there is some theoretical risk of a race |
387 | * condition, but it doesn't seem worth worrying about. |
388 | * |
389 | * Note: we don't support using this in bootstrap mode. All relations |
390 | * created by bootstrap have preassigned OIDs, so there's no need. |
391 | */ |
392 | Oid |
393 | GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence) |
394 | { |
395 | RelFileNodeBackend rnode; |
396 | char *rpath; |
397 | bool collides; |
398 | BackendId backend; |
399 | |
400 | /* |
401 | * If we ever get here during pg_upgrade, there's something wrong; all |
402 | * relfilenode assignments during a binary-upgrade run should be |
403 | * determined by commands in the dump script. |
404 | */ |
405 | Assert(!IsBinaryUpgrade); |
406 | |
407 | switch (relpersistence) |
408 | { |
409 | case RELPERSISTENCE_TEMP: |
410 | backend = BackendIdForTempRelations(); |
411 | break; |
412 | case RELPERSISTENCE_UNLOGGED: |
413 | case RELPERSISTENCE_PERMANENT: |
414 | backend = InvalidBackendId; |
415 | break; |
416 | default: |
417 | elog(ERROR, "invalid relpersistence: %c" , relpersistence); |
418 | return InvalidOid; /* placate compiler */ |
419 | } |
420 | |
421 | /* This logic should match RelationInitPhysicalAddr */ |
422 | rnode.node.spcNode = reltablespace ? reltablespace : MyDatabaseTableSpace; |
423 | rnode.node.dbNode = (rnode.node.spcNode == GLOBALTABLESPACE_OID) ? InvalidOid : MyDatabaseId; |
424 | |
425 | /* |
426 | * The relpath will vary based on the backend ID, so we must initialize |
427 | * that properly here to make sure that any collisions based on filename |
428 | * are properly detected. |
429 | */ |
430 | rnode.backend = backend; |
431 | |
432 | do |
433 | { |
434 | CHECK_FOR_INTERRUPTS(); |
435 | |
436 | /* Generate the OID */ |
437 | if (pg_class) |
438 | rnode.node.relNode = GetNewOidWithIndex(pg_class, ClassOidIndexId, |
439 | Anum_pg_class_oid); |
440 | else |
441 | rnode.node.relNode = GetNewObjectId(); |
442 | |
443 | /* Check for existing file of same name */ |
444 | rpath = relpath(rnode, MAIN_FORKNUM); |
445 | |
446 | if (access(rpath, F_OK) == 0) |
447 | { |
448 | /* definite collision */ |
449 | collides = true; |
450 | } |
451 | else |
452 | { |
453 | /* |
454 | * Here we have a little bit of a dilemma: if errno is something |
455 | * other than ENOENT, should we declare a collision and loop? In |
456 | * practice it seems best to go ahead regardless of the errno. If |
457 | * there is a colliding file we will get an smgr failure when we |
458 | * attempt to create the new relation file. |
459 | */ |
460 | collides = false; |
461 | } |
462 | |
463 | pfree(rpath); |
464 | } while (collides); |
465 | |
466 | return rnode.node.relNode; |
467 | } |
468 | |
469 | /* |
470 | * SQL callable interface for GetNewOidWithIndex(). Outside of initdb's |
471 | * direct insertions into catalog tables, and recovering from corruption, this |
472 | * should rarely be needed. |
473 | * |
474 | * Function is intentionally not documented in the user facing docs. |
475 | */ |
476 | Datum |
477 | pg_nextoid(PG_FUNCTION_ARGS) |
478 | { |
479 | Oid reloid = PG_GETARG_OID(0); |
480 | Name attname = PG_GETARG_NAME(1); |
481 | Oid idxoid = PG_GETARG_OID(2); |
482 | Relation rel; |
483 | Relation idx; |
484 | HeapTuple atttuple; |
485 | Form_pg_attribute attform; |
486 | AttrNumber attno; |
487 | Oid newoid; |
488 | |
489 | /* |
490 | * As this function is not intended to be used during normal running, and |
491 | * only supports system catalogs (which require superuser permissions to |
492 | * modify), just checking for superuser ought to not obstruct valid |
493 | * usecases. |
494 | */ |
495 | if (!superuser()) |
496 | ereport(ERROR, |
497 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
498 | errmsg("must be superuser to call pg_nextoid()" ))); |
499 | |
500 | rel = table_open(reloid, RowExclusiveLock); |
501 | idx = index_open(idxoid, RowExclusiveLock); |
502 | |
503 | if (!IsSystemRelation(rel)) |
504 | ereport(ERROR, |
505 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
506 | errmsg("pg_nextoid() can only be used on system catalogs" ))); |
507 | |
508 | if (idx->rd_index->indrelid != RelationGetRelid(rel)) |
509 | ereport(ERROR, |
510 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
511 | errmsg("index \"%s\" does not belong to table \"%s\"" , |
512 | RelationGetRelationName(idx), |
513 | RelationGetRelationName(rel)))); |
514 | |
515 | atttuple = SearchSysCacheAttName(reloid, NameStr(*attname)); |
516 | if (!HeapTupleIsValid(atttuple)) |
517 | ereport(ERROR, |
518 | (errcode(ERRCODE_UNDEFINED_COLUMN), |
519 | errmsg("column \"%s\" of relation \"%s\" does not exist" , |
520 | NameStr(*attname), RelationGetRelationName(rel)))); |
521 | |
522 | attform = ((Form_pg_attribute) GETSTRUCT(atttuple)); |
523 | attno = attform->attnum; |
524 | |
525 | if (attform->atttypid != OIDOID) |
526 | ereport(ERROR, |
527 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
528 | errmsg("column \"%s\" is not of type oid" , |
529 | NameStr(*attname)))); |
530 | |
531 | if (IndexRelationGetNumberOfKeyAttributes(idx) != 1 || |
532 | idx->rd_index->indkey.values[0] != attno) |
533 | ereport(ERROR, |
534 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
535 | errmsg("index \"%s\" is not the index for column \"%s\"" , |
536 | RelationGetRelationName(idx), |
537 | NameStr(*attname)))); |
538 | |
539 | newoid = GetNewOidWithIndex(rel, idxoid, attno); |
540 | |
541 | ReleaseSysCache(atttuple); |
542 | table_close(rel, RowExclusiveLock); |
543 | index_close(idx, RowExclusiveLock); |
544 | |
545 | return newoid; |
546 | } |
547 | |