Age Owner TLA Line data Source code
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-2023, 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/namespace.h"
30 : #include "catalog/pg_auth_members.h"
31 : #include "catalog/pg_authid.h"
32 : #include "catalog/pg_database.h"
33 : #include "catalog/pg_db_role_setting.h"
34 : #include "catalog/pg_largeobject.h"
35 : #include "catalog/pg_namespace.h"
36 : #include "catalog/pg_parameter_acl.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 "miscadmin.h"
45 : #include "storage/fd.h"
46 : #include "utils/fmgroids.h"
47 : #include "utils/fmgrprotos.h"
48 : #include "utils/rel.h"
49 : #include "utils/snapmgr.h"
50 : #include "utils/syscache.h"
51 :
52 : /*
53 : * Parameters to determine when to emit a log message in
54 : * GetNewOidWithIndex()
55 : */
56 : #define GETNEWOID_LOG_THRESHOLD 1000000
57 : #define GETNEWOID_LOG_MAX_INTERVAL 128000000
58 :
59 : /*
60 : * IsSystemRelation
61 : * True iff the relation is either a system catalog or a toast table.
62 : * See IsCatalogRelation for the exact definition of a system catalog.
63 : *
64 : * We treat toast tables of user relations as "system relations" for
65 : * protection purposes, e.g. you can't change their schemas without
66 : * special permissions. Therefore, most uses of this function are
67 : * checking whether allow_system_table_mods restrictions apply.
68 : * For other purposes, consider whether you shouldn't be using
69 : * IsCatalogRelation instead.
70 : *
71 : * This function does not perform any catalog accesses.
72 : * Some callers rely on that!
73 : */
74 : bool
7667 tgl 75 CBC 1289189 : IsSystemRelation(Relation relation)
76 : {
3419 rhaas 77 1289189 : return IsSystemClass(RelationGetRelid(relation), relation->rd_rel);
78 : }
79 :
80 : /*
81 : * IsSystemClass
82 : * Like the above, but takes a Form_pg_class as argument.
83 : * Used when we do not want to open the relation and have to
84 : * search pg_class directly.
85 : */
86 : bool
87 1654511 : IsSystemClass(Oid relid, Form_pg_class reltuple)
88 : {
89 : /* IsCatalogRelationOid is a bit faster, so test that first */
1432 tgl 90 1654511 : return (IsCatalogRelationOid(relid) || IsToastClass(reltuple));
91 : }
92 :
93 : /*
94 : * IsCatalogRelation
95 : * True iff the relation is a system catalog.
96 : *
97 : * By a system catalog, we mean one that is created during the bootstrap
98 : * phase of initdb. That includes not just the catalogs per se, but
99 : * also their indexes, and TOAST tables and indexes if any.
100 : *
101 : * This function does not perform any catalog accesses.
102 : * Some callers rely on that!
103 : */
104 : bool
3419 rhaas 105 29522131 : IsCatalogRelation(Relation relation)
106 : {
1432 tgl 107 29522131 : return IsCatalogRelationOid(RelationGetRelid(relation));
108 : }
109 :
110 : /*
111 : * IsCatalogRelationOid
112 : * True iff the relation identified by this OID is a system catalog.
113 : *
114 : * By a system catalog, we mean one that is created during the bootstrap
115 : * phase of initdb. That includes not just the catalogs per se, but
116 : * also their indexes, and TOAST tables and indexes if any.
117 : *
118 : * This function does not perform any catalog accesses.
119 : * Some callers rely on that!
120 : */
121 : bool
122 31466028 : IsCatalogRelationOid(Oid relid)
123 : {
124 : /*
125 : * We consider a relation to be a system catalog if it has a pinned OID.
126 : * This includes all the defined catalogs, their indexes, and their TOAST
127 : * tables and indexes.
128 : *
129 : * This rule excludes the relations in information_schema, which are not
130 : * integral to the system and can be treated the same as user relations.
131 : * (Since it's valid to drop and recreate information_schema, any rule
132 : * that did not act this way would be wrong.)
133 : *
134 : * This test is reliable since an OID wraparound will skip this range of
135 : * OIDs; see GetNewObjectId().
136 : */
633 137 31466028 : return (relid < (Oid) FirstUnpinnedObjectId);
138 : }
139 :
140 : /*
141 : * IsToastRelation
142 : * True iff relation is a TOAST support relation (or index).
143 : *
144 : * Does not perform any catalog accesses.
145 : */
146 : bool
7667 147 4791896 : IsToastRelation(Relation relation)
148 : {
149 : /*
150 : * What we actually check is whether the relation belongs to a pg_toast
151 : * namespace. This should be equivalent because of restrictions that are
152 : * enforced elsewhere against creating user relations in, or moving
153 : * relations into/out of, a pg_toast namespace. Notice also that this
154 : * will not say "true" for toast tables belonging to other sessions' temp
155 : * tables; we expect that other mechanisms will prevent access to those.
156 : */
157 4791896 : return IsToastNamespace(RelationGetNamespace(relation));
158 : }
159 :
160 : /*
161 : * IsToastClass
162 : * Like the above, but takes a Form_pg_class as argument.
163 : * Used when we do not want to open the relation and have to
164 : * search pg_class directly.
165 : */
166 : bool
167 442363 : IsToastClass(Form_pg_class reltuple)
168 : {
7522 bruce 169 442363 : Oid relnamespace = reltuple->relnamespace;
170 :
171 442363 : return IsToastNamespace(relnamespace);
172 : }
173 :
174 : /*
175 : * IsCatalogNamespace
176 : * True iff namespace is pg_catalog.
177 : *
178 : * Does not perform any catalog accesses.
179 : *
180 : * NOTE: the reason this isn't a macro is to avoid having to include
181 : * catalog/pg_namespace.h in a lot of places.
182 : */
183 : bool
1432 tgl 184 228516 : IsCatalogNamespace(Oid namespaceId)
185 : {
7667 186 228516 : return namespaceId == PG_CATALOG_NAMESPACE;
187 : }
188 :
189 : /*
190 : * IsToastNamespace
191 : * True iff namespace is pg_toast or my temporary-toast-table namespace.
192 : *
193 : * Does not perform any catalog accesses.
194 : *
195 : * Note: this will return false for temporary-toast-table namespaces belonging
196 : * to other backends. Those are treated the same as other backends' regular
197 : * temp table namespaces, and access is prevented where appropriate.
198 : * If you need to check for those, you may be able to use isAnyTempNamespace,
199 : * but beware that that does involve a catalog access.
200 : */
201 : bool
202 5303305 : IsToastNamespace(Oid namespaceId)
203 : {
5737 204 10487008 : return (namespaceId == PG_TOAST_NAMESPACE) ||
205 5183703 : isTempToastNamespace(namespaceId);
206 : }
207 :
208 :
209 : /*
210 : * IsReservedName
211 : * True iff name starts with the pg_ prefix.
212 : *
213 : * For some classes of objects, the prefix pg_ is reserved for
214 : * system objects only. As of 8.0, this was only true for
215 : * schema and tablespace names. With 9.6, this is also true
216 : * for roles.
217 : */
218 : bool
7667 219 1450 : IsReservedName(const char *name)
220 : {
221 : /* ugly coding for speed */
222 1482 : return (name[0] == 'p' &&
223 1457 : name[1] == 'g' &&
224 7 : name[2] == '_');
225 : }
226 :
227 :
228 : /*
229 : * IsSharedRelation
230 : * Given the OID of a relation, determine whether it's supposed to be
231 : * shared across an entire database cluster.
232 : *
233 : * In older releases, this had to be hard-wired so that we could compute the
234 : * locktag for a relation and lock it before examining its catalog entry.
235 : * Since we now have MVCC catalog access, the race conditions that made that
236 : * a hard requirement are gone, so we could look at relaxing this restriction.
237 : * However, if we scanned the pg_class entry to find relisshared, and only
238 : * then locked the relation, pg_class could get updated in the meantime,
239 : * forcing us to scan the relation again, which would definitely be complex
240 : * and might have undesirable performance consequences. Fortunately, the set
241 : * of shared relations is fairly static, so a hand-maintained list of their
242 : * OIDs isn't completely impractical.
243 : */
244 : bool
6096 245 29332356 : IsSharedRelation(Oid relationId)
246 : {
247 : /* These are the shared catalogs (look for BKI_SHARED_RELATION) */
248 29332356 : if (relationId == AuthIdRelationId ||
249 29218527 : relationId == AuthMemRelationId ||
250 29144963 : relationId == DatabaseRelationId ||
2902 andres 251 29128150 : relationId == DbRoleSettingRelationId ||
368 tgl 252 29117330 : relationId == ParameterAclRelationId ||
2271 peter_e 253 29104130 : relationId == ReplicationOriginRelationId ||
368 tgl 254 28363568 : relationId == SharedDependRelationId ||
255 28358669 : relationId == SharedDescriptionRelationId ||
256 28351162 : relationId == SharedSecLabelRelationId ||
257 28334390 : relationId == SubscriptionRelationId ||
258 : relationId == TableSpaceRelationId)
6096 259 1017261 : return true;
260 : /* These are their indexes */
368 261 28315095 : if (relationId == AuthIdOidIndexId ||
262 28269666 : relationId == AuthIdRolnameIndexId ||
6096 263 28260458 : relationId == AuthMemMemRoleIndexId ||
368 264 28254401 : relationId == AuthMemRoleMemIndexId ||
234 rhaas 265 GNC 28250340 : relationId == AuthMemOidIndexId ||
266 28248093 : relationId == AuthMemGrantorIndexId ||
6096 tgl 267 CBC 28219502 : relationId == DatabaseNameIndexId ||
268 28194858 : relationId == DatabaseOidIndexId ||
2902 andres 269 28151234 : relationId == DbRoleSettingDatidRolidIndexId ||
368 tgl 270 28148223 : relationId == ParameterAclOidIndexId ||
271 28145244 : relationId == ParameterAclParnameIndexId ||
2902 andres 272 28141375 : relationId == ReplicationOriginIdentIndex ||
2271 peter_e 273 28137618 : relationId == ReplicationOriginNameIndex ||
368 tgl 274 28020760 : relationId == SharedDependDependerIndexId ||
275 28014879 : relationId == SharedDependReferenceIndexId ||
276 28011329 : relationId == SharedDescriptionObjIndexId ||
277 28007005 : relationId == SharedSecLabelObjectIndexId ||
278 28003277 : relationId == SubscriptionNameIndexId ||
2271 peter_e 279 27999276 : relationId == SubscriptionObjectIndexId ||
368 tgl 280 27997076 : relationId == TablespaceNameIndexId ||
368 tgl 281 ECB : relationId == TablespaceOidIndexId)
6096 tgl 282 CBC 325789 : return true;
283 : /* These are their toast tables and toast indexes */
1724 michael 284 27989306 : if (relationId == PgAuthidToastTable ||
1724 michael 285 GIC 27987579 : relationId == PgAuthidToastIndex ||
1724 michael 286 CBC 27986256 : relationId == PgDatabaseToastTable ||
287 27985275 : relationId == PgDatabaseToastIndex ||
4932 alvherre 288 27984281 : relationId == PgDbRoleSettingToastTable ||
2941 bruce 289 27983624 : relationId == PgDbRoleSettingToastIndex ||
368 tgl 290 27982630 : relationId == PgParameterAclToastTable ||
291 27981973 : relationId == PgParameterAclToastIndex ||
1724 michael 292 27980979 : relationId == PgReplicationOriginToastTable ||
293 27980322 : relationId == PgReplicationOriginToastIndex ||
294 27979303 : relationId == PgShdescriptionToastTable ||
295 27978623 : relationId == PgShdescriptionToastIndex ||
2941 bruce 296 27977629 : relationId == PgShseclabelToastTable ||
1724 michael 297 27976972 : relationId == PgShseclabelToastIndex ||
298 27975978 : relationId == PgSubscriptionToastTable ||
299 27975321 : relationId == PgSubscriptionToastIndex ||
300 27974308 : relationId == PgTablespaceToastTable ||
1724 michael 301 ECB : relationId == PgTablespaceToastIndex)
6096 tgl 302 CBC 15674 : return true;
6096 tgl 303 GIC 27973632 : return false;
6096 tgl 304 ECB : }
305 :
306 : /*
307 : * IsPinnedObject
308 : * Given the class + OID identity of a database object, report whether
309 : * it is "pinned", that is not droppable because the system requires it.
310 : *
311 : * We used to represent this explicitly in pg_depend, but that proved to be
312 : * an undesirable amount of overhead, so now we rely on an OID range test.
313 : */
314 : bool
633 tgl 315 GIC 4157584 : IsPinnedObject(Oid classId, Oid objectId)
316 : {
633 tgl 317 ECB : /*
318 : * Objects with OIDs above FirstUnpinnedObjectId are never pinned. Since
319 : * the OID generator skips this range when wrapping around, this check
320 : * guarantees that user-defined objects are never considered pinned.
321 : */
633 tgl 322 GIC 4157584 : if (objectId >= FirstUnpinnedObjectId)
323 756528 : return false;
633 tgl 324 ECB :
325 : /*
326 : * Large objects are never pinned. We need this special case because
327 : * their OIDs can be user-assigned.
328 : */
633 tgl 329 GIC 3401056 : if (classId == LargeObjectRelationId)
330 27 : return false;
633 tgl 331 ECB :
332 : /*
333 : * There are a few objects defined in the catalog .dat files that, as a
334 : * matter of policy, we prefer not to treat as pinned. We used to handle
335 : * that by excluding them from pg_depend, but it's just as easy to
336 : * hard-wire their OIDs here. (If the user does indeed drop and recreate
337 : * them, they'll have new but certainly-unpinned OIDs, so no problem.)
338 : *
339 : * Checking both classId and objectId is overkill, since OIDs below
340 : * FirstGenbkiObjectId should be globally unique, but do it anyway for
341 : * robustness.
342 : */
343 :
344 : /* the public namespace is not pinned */
633 tgl 345 GIC 3401029 : if (classId == NamespaceRelationId &&
346 : objectId == PG_PUBLIC_NAMESPACE)
633 tgl 347 CBC 24674 : return false;
348 :
353 tgl 349 ECB : /*
350 : * Databases are never pinned. It might seem that it'd be prudent to pin
351 : * at least template0; but we do this intentionally so that template0 and
352 : * template1 can be rebuilt from each other, thus letting them serve as
353 : * mutual backups (as long as you've not modified template1, anyway).
354 : */
353 tgl 355 GIC 3376355 : if (classId == DatabaseRelationId)
353 tgl 356 UIC 0 : return false;
353 tgl 357 ECB :
633 tgl 358 EUB : /*
359 : * All other initdb-created objects are pinned. This is overkill (the
360 : * system doesn't really depend on having every last weird datatype, for
361 : * instance) but generating only the minimum required set of dependencies
362 : * seems hard, and enforcing an accurate list would be much more expensive
363 : * than the simple range test used here.
364 : */
633 tgl 365 GIC 3376355 : return true;
366 : }
633 tgl 367 ECB :
368 :
369 : /*
370 : * GetNewOidWithIndex
371 : * Generate a new OID that is unique within the system relation.
372 : *
373 : * Since the OID is not immediately inserted into the table, there is a
374 : * race condition here; but a problem could occur only if someone else
375 : * managed to cycle through 2^32 OIDs and generate the same OID before we
376 : * finish inserting our row. This seems unlikely to be a problem. Note
377 : * that if we had to *commit* the row to end the race condition, the risk
378 : * would be rather higher; therefore we use SnapshotAny in the test, so that
379 : * we will see uncommitted rows. (We used to use SnapshotDirty, but that has
380 : * the disadvantage that it ignores recently-deleted rows, creating a risk
381 : * of transient conflicts for as long as our own MVCC snapshots think a
382 : * recently-deleted row is live. The risk is far higher when selecting TOAST
383 : * OIDs, because SnapshotToast considers dead rows as active indefinitely.)
384 : *
385 : * Note that we are effectively assuming that the table has a relatively small
386 : * number of entries (much less than 2^32) and there aren't very long runs of
387 : * consecutive existing OIDs. This is a mostly reasonable assumption for
388 : * system catalogs.
389 : *
390 : * Caller must have a suitable lock on the relation.
391 : */
392 : Oid
5475 tgl 393 GIC 1106812 : GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
394 : {
6449 tgl 395 ECB : Oid newOid;
396 : SysScanDesc scan;
397 : ScanKeyData key;
398 : bool collides;
746 fujii 399 GIC 1106812 : uint64 retries = 0;
400 1106812 : uint64 retries_before_log = GETNEWOID_LOG_THRESHOLD;
6449 tgl 401 ECB :
1601 andres 402 : /* Only system relations are supported */
1601 andres 403 GIC 1106812 : Assert(IsSystemRelation(relation));
404 :
1601 andres 405 ECB : /* In bootstrap mode, we don't have any indexes to use */
1601 andres 406 GIC 1106812 : if (IsBootstrapProcessingMode())
407 35075 : return GetNewObjectId();
1601 andres 408 ECB :
2127 tgl 409 : /*
410 : * We should never be asked to generate a new pg_type OID during
411 : * pg_upgrade; doing so would risk collisions with the OIDs it wants to
412 : * assign. Hitting this assert means there's some path where we failed to
413 : * ensure that a type OID is determined by commands in the dump script.
414 : */
2127 tgl 415 GIC 1071737 : Assert(!IsBinaryUpgrade || RelationGetRelid(relation) != TypeRelationId);
416 :
6449 tgl 417 ECB : /* Generate new OIDs until we find one not in the table */
418 : do
419 : {
5527 tgl 420 GIC 1071737 : CHECK_FOR_INTERRUPTS();
421 :
6449 tgl 422 CBC 1071737 : newOid = GetNewObjectId();
423 :
424 1071737 : ScanKeyInit(&key,
425 : oidcolumn,
6449 tgl 426 ECB : BTEqualStrategyNumber, F_OIDEQ,
427 : ObjectIdGetDatum(newOid));
428 :
429 : /* see notes above about using SnapshotAny */
5475 tgl 430 GIC 1071737 : scan = systable_beginscan(relation, indexId, true,
431 : SnapshotAny, 1, &key);
6449 tgl 432 ECB :
5475 tgl 433 GIC 1071737 : collides = HeapTupleIsValid(systable_getnext(scan));
434 :
5475 tgl 435 CBC 1071737 : systable_endscan(scan);
436 :
746 fujii 437 ECB : /*
438 : * Log that we iterate more than GETNEWOID_LOG_THRESHOLD but have not
439 : * yet found OID unused in the relation. Then repeat logging with
440 : * exponentially increasing intervals until we iterate more than
441 : * GETNEWOID_LOG_MAX_INTERVAL. Finally repeat logging every
442 : * GETNEWOID_LOG_MAX_INTERVAL unless an unused OID is found. This
443 : * logic is necessary not to fill up the server log with the similar
444 : * messages.
445 : */
746 fujii 446 GIC 1071737 : if (retries >= retries_before_log)
447 : {
746 fujii 448 LBC 0 : ereport(LOG,
449 : (errmsg("still searching for an unused OID in relation \"%s\"",
746 fujii 450 EUB : RelationGetRelationName(relation)),
451 : errdetail_plural("OID candidates have been checked %llu time, but no unused OID has been found yet.",
452 : "OID candidates have been checked %llu times, but no unused OID has been found yet.",
453 : retries,
454 : (unsigned long long) retries)));
455 :
456 : /*
457 : * Double the number of retries to do before logging next until it
458 : * reaches GETNEWOID_LOG_MAX_INTERVAL.
459 : */
746 fujii 460 UIC 0 : if (retries_before_log * 2 <= GETNEWOID_LOG_MAX_INTERVAL)
461 0 : retries_before_log *= 2;
746 fujii 462 EUB : else
746 fujii 463 UBC 0 : retries_before_log += GETNEWOID_LOG_MAX_INTERVAL;
464 : }
746 fujii 465 EUB :
746 fujii 466 GIC 1071737 : retries++;
6449 tgl 467 1071737 : } while (collides);
6449 tgl 468 ECB :
746 fujii 469 : /*
470 : * If at least one log message is emitted, also log the completion of OID
471 : * assignment.
472 : */
746 fujii 473 GIC 1071737 : if (retries > GETNEWOID_LOG_THRESHOLD)
474 : {
746 fujii 475 LBC 0 : ereport(LOG,
476 : (errmsg_plural("new OID has been assigned in relation \"%s\" after %llu retry",
650 peter 477 EUB : "new OID has been assigned in relation \"%s\" after %llu retries",
478 : retries,
479 : RelationGetRelationName(relation), (unsigned long long) retries)));
480 : }
481 :
6449 tgl 482 GIC 1071737 : return newOid;
483 : }
6449 tgl 484 ECB :
485 : /*
486 : * GetNewRelFileNumber
487 : * Generate a new relfilenumber that is unique within the
488 : * database of the given tablespace.
489 : *
490 : * If the relfilenumber will also be used as the relation's OID, pass the
491 : * opened pg_class catalog, and this routine will guarantee that the result
492 : * is also an unused OID within pg_class. If the result is to be used only
493 : * as a relfilenumber for an existing relation, pass NULL for pg_class.
494 : *
495 : * As with GetNewOidWithIndex(), there is some theoretical risk of a race
496 : * condition, but it doesn't seem worth worrying about.
497 : *
498 : * Note: we don't support using this in bootstrap mode. All relations
499 : * created by bootstrap have preassigned OIDs, so there's no need.
500 : */
501 : RelFileNumber
193 rhaas 502 GNC 88262 : GetNewRelFileNumber(Oid reltablespace, Relation pg_class, char relpersistence)
503 : {
504 : RelFileLocatorBackend rlocator;
505 : char *rpath;
506 : bool collides;
507 : BackendId backend;
508 :
509 : /*
510 : * If we ever get here during pg_upgrade, there's something wrong; all
511 : * relfilenumber assignments during a binary-upgrade run should be
512 : * determined by commands in the dump script.
513 : */
193 rhaas 514 GIC 88262 : Assert(!IsBinaryUpgrade);
515 :
193 rhaas 516 CBC 88262 : switch (relpersistence)
517 : {
518 3043 : case RELPERSISTENCE_TEMP:
193 rhaas 519 GIC 3043 : backend = BackendIdForTempRelations();
193 rhaas 520 CBC 3043 : break;
521 85219 : case RELPERSISTENCE_UNLOGGED:
193 rhaas 522 ECB : case RELPERSISTENCE_PERMANENT:
193 rhaas 523 CBC 85219 : backend = InvalidBackendId;
193 rhaas 524 GIC 85219 : break;
193 rhaas 525 LBC 0 : default:
526 0 : elog(ERROR, "invalid relpersistence: %c", relpersistence);
527 : return InvalidRelFileNumber; /* placate compiler */
193 rhaas 528 EUB : }
529 :
530 : /* This logic should match RelationInitPhysicalAddr */
193 rhaas 531 GNC 88262 : rlocator.locator.spcOid = reltablespace ? reltablespace : MyDatabaseTableSpace;
532 88262 : rlocator.locator.dbOid =
533 88262 : (rlocator.locator.spcOid == GLOBALTABLESPACE_OID) ?
534 88262 : InvalidOid : MyDatabaseId;
193 rhaas 535 ECB :
536 : /*
537 : * The relpath will vary based on the backend ID, so we must initialize
538 : * that properly here to make sure that any collisions based on filename
539 : * are properly detected.
540 : */
193 rhaas 541 GNC 88262 : rlocator.backend = backend;
542 :
543 : do
544 : {
193 rhaas 545 CBC 88262 : CHECK_FOR_INTERRUPTS();
546 :
547 : /* Generate the OID */
193 rhaas 548 GIC 88262 : if (pg_class)
193 rhaas 549 GNC 83728 : rlocator.locator.relNumber = GetNewOidWithIndex(pg_class, ClassOidIndexId,
550 : Anum_pg_class_oid);
551 : else
552 4534 : rlocator.locator.relNumber = GetNewObjectId();
193 rhaas 553 ECB :
554 : /* Check for existing file of same name */
193 rhaas 555 GNC 88262 : rpath = relpath(rlocator, MAIN_FORKNUM);
193 rhaas 556 ECB :
193 rhaas 557 GIC 88262 : if (access(rpath, F_OK) == 0)
558 : {
193 rhaas 559 ECB : /* definite collision */
193 rhaas 560 UIC 0 : collides = true;
193 rhaas 561 ECB : }
562 : else
563 : {
193 rhaas 564 EUB : /*
565 : * Here we have a little bit of a dilemma: if errno is something
566 : * other than ENOENT, should we declare a collision and loop? In
567 : * practice it seems best to go ahead regardless of the errno. If
568 : * there is a colliding file we will get an smgr failure when we
569 : * attempt to create the new relation file.
570 : */
193 rhaas 571 GIC 88262 : collides = false;
572 : }
573 :
574 88262 : pfree(rpath);
193 rhaas 575 CBC 88262 : } while (collides);
576 :
193 rhaas 577 GNC 88262 : return rlocator.locator.relNumber;
193 rhaas 578 ECB : }
579 :
580 : /*
1601 andres 581 : * SQL callable interface for GetNewOidWithIndex(). Outside of initdb's
582 : * direct insertions into catalog tables, and recovering from corruption, this
583 : * should rarely be needed.
584 : *
585 : * Function is intentionally not documented in the user facing docs.
586 : */
587 : Datum
1601 andres 588 UIC 0 : pg_nextoid(PG_FUNCTION_ARGS)
589 : {
1418 tgl 590 0 : Oid reloid = PG_GETARG_OID(0);
591 0 : Name attname = PG_GETARG_NAME(1);
1418 tgl 592 UBC 0 : Oid idxoid = PG_GETARG_OID(2);
593 : Relation rel;
1418 tgl 594 EUB : Relation idx;
595 : HeapTuple atttuple;
1601 andres 596 : Form_pg_attribute attform;
597 : AttrNumber attno;
598 : Oid newoid;
599 :
600 : /*
601 : * As this function is not intended to be used during normal running, and
602 : * only supports system catalogs (which require superuser permissions to
603 : * modify), just checking for superuser ought to not obstruct valid
604 : * usecases.
605 : */
1601 andres 606 UIC 0 : if (!superuser())
607 0 : ereport(ERROR,
608 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
609 : errmsg("must be superuser to call %s()",
633 tgl 610 EUB : "pg_nextoid")));
1601 andres 611 :
1539 andres 612 UIC 0 : rel = table_open(reloid, RowExclusiveLock);
1601 613 0 : idx = index_open(idxoid, RowExclusiveLock);
614 :
615 0 : if (!IsSystemRelation(rel))
1601 andres 616 UBC 0 : ereport(ERROR,
1601 andres 617 EUB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
618 : errmsg("pg_nextoid() can only be used on system catalogs")));
619 :
1601 andres 620 UBC 0 : if (idx->rd_index->indrelid != RelationGetRelid(rel))
1601 andres 621 UIC 0 : ereport(ERROR,
622 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
623 : errmsg("index \"%s\" does not belong to table \"%s\"",
1601 andres 624 EUB : RelationGetRelationName(idx),
625 : RelationGetRelationName(rel))));
626 :
1601 andres 627 UIC 0 : atttuple = SearchSysCacheAttName(reloid, NameStr(*attname));
628 0 : if (!HeapTupleIsValid(atttuple))
629 0 : ereport(ERROR,
630 : (errcode(ERRCODE_UNDEFINED_COLUMN),
1435 tgl 631 EUB : errmsg("column \"%s\" of relation \"%s\" does not exist",
632 : NameStr(*attname), RelationGetRelationName(rel))));
1601 andres 633 :
1601 andres 634 UIC 0 : attform = ((Form_pg_attribute) GETSTRUCT(atttuple));
635 0 : attno = attform->attnum;
636 :
637 0 : if (attform->atttypid != OIDOID)
1601 andres 638 UBC 0 : ereport(ERROR,
1601 andres 639 EUB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
640 : errmsg("column \"%s\" is not of type oid",
641 : NameStr(*attname))));
642 :
1601 andres 643 UIC 0 : if (IndexRelationGetNumberOfKeyAttributes(idx) != 1 ||
644 0 : idx->rd_index->indkey.values[0] != attno)
645 0 : ereport(ERROR,
646 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1435 tgl 647 EUB : errmsg("index \"%s\" is not the index for column \"%s\"",
1601 andres 648 : RelationGetRelationName(idx),
649 : NameStr(*attname))));
650 :
1601 andres 651 UIC 0 : newoid = GetNewOidWithIndex(rel, idxoid, attno);
652 :
653 0 : ReleaseSysCache(atttuple);
1539 654 0 : table_close(rel, RowExclusiveLock);
1601 andres 655 UBC 0 : index_close(idx, RowExclusiveLock);
656 :
633 tgl 657 0 : PG_RETURN_OID(newoid);
633 tgl 658 EUB : }
659 :
660 : /*
661 : * SQL callable interface for StopGeneratingPinnedObjectIds().
662 : *
663 : * This is only to be used by initdb, so it's intentionally not documented in
664 : * the user facing docs.
665 : */
666 : Datum
633 tgl 667 GIC 303 : pg_stop_making_pinned_objects(PG_FUNCTION_ARGS)
668 : {
669 : /*
670 : * Belt-and-suspenders check, since StopGeneratingPinnedObjectIds will
633 tgl 671 ECB : * fail anyway in non-single-user mode.
672 : */
633 tgl 673 GIC 303 : if (!superuser())
633 tgl 674 UIC 0 : ereport(ERROR,
675 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
676 : errmsg("must be superuser to call %s()",
633 tgl 677 ECB : "pg_stop_making_pinned_objects")));
633 tgl 678 EUB :
633 tgl 679 GIC 303 : StopGeneratingPinnedObjectIds();
680 :
681 303 : PG_RETURN_VOID();
682 : }
|