LCOV - code coverage report
Current view: top level - src/backend/catalog - catalog.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 77.8 % 167 130
Test Date: 2026-02-17 17:20:33 Functions: 94.4 % 18 17
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1