LCOV - code coverage report
Current view: top level - src/backend/catalog - catalog.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16beta1 Lines: 126 163 77.3 %
Date: 2023-05-30 17:15:13 Functions: 14 15 93.3 %
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-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
      75      357096 : IsSystemRelation(Relation relation)
      76             : {
      77      357096 :     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     1085690 : IsSystemClass(Oid relid, Form_pg_class reltuple)
      88             : {
      89             :     /* IsCatalogRelationOid is a bit faster, so test that first */
      90     1085690 :     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
     105    58590380 : IsCatalogRelation(Relation relation)
     106             : {
     107    58590380 :     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    60255500 : 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             :      */
     137    60255500 :     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
     147     9101100 : 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     9101100 :     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      869710 : IsToastClass(Form_pg_class reltuple)
     168             : {
     169      869710 :     Oid         relnamespace = reltuple->relnamespace;
     170             : 
     171      869710 :     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
     184      454812 : IsCatalogNamespace(Oid namespaceId)
     185             : {
     186      454812 :     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    10108372 : IsToastNamespace(Oid namespaceId)
     203             : {
     204    19988668 :     return (namespaceId == PG_TOAST_NAMESPACE) ||
     205     9880296 :         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
     219        3014 : IsReservedName(const char *name)
     220             : {
     221             :     /* ugly coding for speed */
     222        3078 :     return (name[0] == 'p' &&
     223        3028 :             name[1] == 'g' &&
     224          14 :             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
     245    55076686 : IsSharedRelation(Oid relationId)
     246             : {
     247             :     /* These are the shared catalogs (look for BKI_SHARED_RELATION) */
     248    55076686 :     if (relationId == AuthIdRelationId ||
     249    54834266 :         relationId == AuthMemRelationId ||
     250    54673550 :         relationId == DatabaseRelationId ||
     251    54636536 :         relationId == DbRoleSettingRelationId ||
     252    54615572 :         relationId == ParameterAclRelationId ||
     253    54589778 :         relationId == ReplicationOriginRelationId ||
     254    53525656 :         relationId == SharedDependRelationId ||
     255    53515900 :         relationId == SharedDescriptionRelationId ||
     256    53501144 :         relationId == SharedSecLabelRelationId ||
     257    53468436 :         relationId == SubscriptionRelationId ||
     258             :         relationId == TableSpaceRelationId)
     259     1646794 :         return true;
     260             :     /* These are their indexes */
     261    53429892 :     if (relationId == AuthIdOidIndexId ||
     262    53327428 :         relationId == AuthIdRolnameIndexId ||
     263    53309392 :         relationId == AuthMemMemRoleIndexId ||
     264    53297410 :         relationId == AuthMemRoleMemIndexId ||
     265    53289320 :         relationId == AuthMemOidIndexId ||
     266    53284846 :         relationId == AuthMemGrantorIndexId ||
     267    53220548 :         relationId == DatabaseNameIndexId ||
     268    53168020 :         relationId == DatabaseOidIndexId ||
     269    53066480 :         relationId == DbRoleSettingDatidRolidIndexId ||
     270    53060586 :         relationId == ParameterAclOidIndexId ||
     271    53054766 :         relationId == ParameterAclParnameIndexId ||
     272    53047158 :         relationId == ReplicationOriginIdentIndex ||
     273    53039752 :         relationId == ReplicationOriginNameIndex ||
     274    52812704 :         relationId == SharedDependDependerIndexId ||
     275    52800806 :         relationId == SharedDependReferenceIndexId ||
     276    52793740 :         relationId == SharedDescriptionObjIndexId ||
     277    52785318 :         relationId == SharedSecLabelObjectIndexId ||
     278    52777974 :         relationId == SubscriptionNameIndexId ||
     279    52770080 :         relationId == SubscriptionObjectIndexId ||
     280    52765710 :         relationId == TablespaceNameIndexId ||
     281             :         relationId == TablespaceOidIndexId)
     282      679722 :         return true;
     283             :     /* These are their toast tables and toast indexes */
     284    52750170 :     if (relationId == PgAuthidToastTable ||
     285    52746728 :         relationId == PgAuthidToastIndex ||
     286    52744094 :         relationId == PgDatabaseToastTable ||
     287    52742140 :         relationId == PgDatabaseToastIndex ||
     288    52740160 :         relationId == PgDbRoleSettingToastTable ||
     289    52738850 :         relationId == PgDbRoleSettingToastIndex ||
     290    52736870 :         relationId == PgParameterAclToastTable ||
     291    52735560 :         relationId == PgParameterAclToastIndex ||
     292    52733580 :         relationId == PgReplicationOriginToastTable ||
     293    52732270 :         relationId == PgReplicationOriginToastIndex ||
     294    52730240 :         relationId == PgShdescriptionToastTable ||
     295    52728884 :         relationId == PgShdescriptionToastIndex ||
     296    52726904 :         relationId == PgShseclabelToastTable ||
     297    52725594 :         relationId == PgShseclabelToastIndex ||
     298    52723614 :         relationId == PgSubscriptionToastTable ||
     299    52722304 :         relationId == PgSubscriptionToastIndex ||
     300    52720286 :         relationId == PgTablespaceToastTable ||
     301             :         relationId == PgTablespaceToastIndex)
     302       31232 :         return true;
     303    52718938 :     return false;
     304             : }
     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
     315     7434588 : IsPinnedObject(Oid classId, Oid objectId)
     316             : {
     317             :     /*
     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             :      */
     322     7434588 :     if (objectId >= FirstUnpinnedObjectId)
     323     1492328 :         return false;
     324             : 
     325             :     /*
     326             :      * Large objects are never pinned.  We need this special case because
     327             :      * their OIDs can be user-assigned.
     328             :      */
     329     5942260 :     if (classId == LargeObjectRelationId)
     330          54 :         return false;
     331             : 
     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 */
     345     5942206 :     if (classId == NamespaceRelationId &&
     346             :         objectId == PG_PUBLIC_NAMESPACE)
     347       49462 :         return false;
     348             : 
     349             :     /*
     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             :      */
     355     5892744 :     if (classId == DatabaseRelationId)
     356           0 :         return false;
     357             : 
     358             :     /*
     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             :      */
     365     5892744 :     return true;
     366             : }
     367             : 
     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
     393     1793816 : GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
     394             : {
     395             :     Oid         newOid;
     396             :     SysScanDesc scan;
     397             :     ScanKeyData key;
     398             :     bool        collides;
     399     1793816 :     uint64      retries = 0;
     400     1793816 :     uint64      retries_before_log = GETNEWOID_LOG_THRESHOLD;
     401             : 
     402             :     /* Only system relations are supported */
     403             :     Assert(IsSystemRelation(relation));
     404             : 
     405             :     /* In bootstrap mode, we don't have any indexes to use */
     406     1793816 :     if (IsBootstrapProcessingMode())
     407       69690 :         return GetNewObjectId();
     408             : 
     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             :      */
     415             :     Assert(!IsBinaryUpgrade || RelationGetRelid(relation) != TypeRelationId);
     416             : 
     417             :     /* Generate new OIDs until we find one not in the table */
     418             :     do
     419             :     {
     420     1724126 :         CHECK_FOR_INTERRUPTS();
     421             : 
     422     1724126 :         newOid = GetNewObjectId();
     423             : 
     424     1724126 :         ScanKeyInit(&key,
     425             :                     oidcolumn,
     426             :                     BTEqualStrategyNumber, F_OIDEQ,
     427             :                     ObjectIdGetDatum(newOid));
     428             : 
     429             :         /* see notes above about using SnapshotAny */
     430     1724126 :         scan = systable_beginscan(relation, indexId, true,
     431             :                                   SnapshotAny, 1, &key);
     432             : 
     433     1724126 :         collides = HeapTupleIsValid(systable_getnext(scan));
     434             : 
     435     1724126 :         systable_endscan(scan);
     436             : 
     437             :         /*
     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             :          */
     446     1724126 :         if (retries >= retries_before_log)
     447             :         {
     448           0 :             ereport(LOG,
     449             :                     (errmsg("still searching for an unused OID in relation \"%s\"",
     450             :                             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             :              */
     460           0 :             if (retries_before_log * 2 <= GETNEWOID_LOG_MAX_INTERVAL)
     461           0 :                 retries_before_log *= 2;
     462             :             else
     463           0 :                 retries_before_log += GETNEWOID_LOG_MAX_INTERVAL;
     464             :         }
     465             : 
     466     1724126 :         retries++;
     467     1724126 :     } while (collides);
     468             : 
     469             :     /*
     470             :      * If at least one log message is emitted, also log the completion of OID
     471             :      * assignment.
     472             :      */
     473     1724126 :     if (retries > GETNEWOID_LOG_THRESHOLD)
     474             :     {
     475           0 :         ereport(LOG,
     476             :                 (errmsg_plural("new OID has been assigned in relation \"%s\" after %llu retry",
     477             :                                "new OID has been assigned in relation \"%s\" after %llu retries",
     478             :                                retries,
     479             :                                RelationGetRelationName(relation), (unsigned long long) retries)));
     480             :     }
     481             : 
     482     1724126 :     return newOid;
     483             : }
     484             : 
     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
     502      175896 : 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             :      */
     514             :     Assert(!IsBinaryUpgrade);
     515             : 
     516      175896 :     switch (relpersistence)
     517             :     {
     518        6082 :         case RELPERSISTENCE_TEMP:
     519        6082 :             backend = BackendIdForTempRelations();
     520        6082 :             break;
     521      169814 :         case RELPERSISTENCE_UNLOGGED:
     522             :         case RELPERSISTENCE_PERMANENT:
     523      169814 :             backend = InvalidBackendId;
     524      169814 :             break;
     525           0 :         default:
     526           0 :             elog(ERROR, "invalid relpersistence: %c", relpersistence);
     527             :             return InvalidRelFileNumber;    /* placate compiler */
     528             :     }
     529             : 
     530             :     /* This logic should match RelationInitPhysicalAddr */
     531      175896 :     rlocator.locator.spcOid = reltablespace ? reltablespace : MyDatabaseTableSpace;
     532      175896 :     rlocator.locator.dbOid =
     533      175896 :         (rlocator.locator.spcOid == GLOBALTABLESPACE_OID) ?
     534      175896 :         InvalidOid : MyDatabaseId;
     535             : 
     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             :      */
     541      175896 :     rlocator.backend = backend;
     542             : 
     543             :     do
     544             :     {
     545      175896 :         CHECK_FOR_INTERRUPTS();
     546             : 
     547             :         /* Generate the OID */
     548      175896 :         if (pg_class)
     549      166824 :             rlocator.locator.relNumber = GetNewOidWithIndex(pg_class, ClassOidIndexId,
     550             :                                                             Anum_pg_class_oid);
     551             :         else
     552        9072 :             rlocator.locator.relNumber = GetNewObjectId();
     553             : 
     554             :         /* Check for existing file of same name */
     555      175896 :         rpath = relpath(rlocator, MAIN_FORKNUM);
     556             : 
     557      175896 :         if (access(rpath, F_OK) == 0)
     558             :         {
     559             :             /* definite collision */
     560           0 :             collides = true;
     561             :         }
     562             :         else
     563             :         {
     564             :             /*
     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             :              */
     571      175896 :             collides = false;
     572             :         }
     573             : 
     574      175896 :         pfree(rpath);
     575      175896 :     } while (collides);
     576             : 
     577      175896 :     return rlocator.locator.relNumber;
     578             : }
     579             : 
     580             : /*
     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
     588           0 : pg_nextoid(PG_FUNCTION_ARGS)
     589             : {
     590           0 :     Oid         reloid = PG_GETARG_OID(0);
     591           0 :     Name        attname = PG_GETARG_NAME(1);
     592           0 :     Oid         idxoid = PG_GETARG_OID(2);
     593             :     Relation    rel;
     594             :     Relation    idx;
     595             :     HeapTuple   atttuple;
     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             :      */
     606           0 :     if (!superuser())
     607           0 :         ereport(ERROR,
     608             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     609             :                  errmsg("must be superuser to call %s()",
     610             :                         "pg_nextoid")));
     611             : 
     612           0 :     rel = table_open(reloid, RowExclusiveLock);
     613           0 :     idx = index_open(idxoid, RowExclusiveLock);
     614             : 
     615           0 :     if (!IsSystemRelation(rel))
     616           0 :         ereport(ERROR,
     617             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     618             :                  errmsg("pg_nextoid() can only be used on system catalogs")));
     619             : 
     620           0 :     if (idx->rd_index->indrelid != RelationGetRelid(rel))
     621           0 :         ereport(ERROR,
     622             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     623             :                  errmsg("index \"%s\" does not belong to table \"%s\"",
     624             :                         RelationGetRelationName(idx),
     625             :                         RelationGetRelationName(rel))));
     626             : 
     627           0 :     atttuple = SearchSysCacheAttName(reloid, NameStr(*attname));
     628           0 :     if (!HeapTupleIsValid(atttuple))
     629           0 :         ereport(ERROR,
     630             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
     631             :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
     632             :                         NameStr(*attname), RelationGetRelationName(rel))));
     633             : 
     634           0 :     attform = ((Form_pg_attribute) GETSTRUCT(atttuple));
     635           0 :     attno = attform->attnum;
     636             : 
     637           0 :     if (attform->atttypid != OIDOID)
     638           0 :         ereport(ERROR,
     639             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     640             :                  errmsg("column \"%s\" is not of type oid",
     641             :                         NameStr(*attname))));
     642             : 
     643           0 :     if (IndexRelationGetNumberOfKeyAttributes(idx) != 1 ||
     644           0 :         idx->rd_index->indkey.values[0] != attno)
     645           0 :         ereport(ERROR,
     646             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     647             :                  errmsg("index \"%s\" is not the index for column \"%s\"",
     648             :                         RelationGetRelationName(idx),
     649             :                         NameStr(*attname))));
     650             : 
     651           0 :     newoid = GetNewOidWithIndex(rel, idxoid, attno);
     652             : 
     653           0 :     ReleaseSysCache(atttuple);
     654           0 :     table_close(rel, RowExclusiveLock);
     655           0 :     index_close(idx, RowExclusiveLock);
     656             : 
     657           0 :     PG_RETURN_OID(newoid);
     658             : }
     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
     667         602 : pg_stop_making_pinned_objects(PG_FUNCTION_ARGS)
     668             : {
     669             :     /*
     670             :      * Belt-and-suspenders check, since StopGeneratingPinnedObjectIds will
     671             :      * fail anyway in non-single-user mode.
     672             :      */
     673         602 :     if (!superuser())
     674           0 :         ereport(ERROR,
     675             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     676             :                  errmsg("must be superuser to call %s()",
     677             :                         "pg_stop_making_pinned_objects")));
     678             : 
     679         602 :     StopGeneratingPinnedObjectIds();
     680             : 
     681         602 :     PG_RETURN_VOID();
     682             : }

Generated by: LCOV version 1.14