LCOV - differential code coverage report
Current view: top level - src/backend/catalog - catalog.c (source / functions) Coverage Total Hit LBC UIC UBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 77.7 % 166 129 4 26 7 36 12 81 29 41 1 3
Current Date: 2023-04-08 15:15:32 Functions: 93.3 % 15 14 1 3 2 9 1 3 1
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           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
      75 CBC     1289189 : IsSystemRelation(Relation relation)
      76                 : {
      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 */
      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
     105        29522131 : IsCatalogRelation(Relation relation)
     106                 : {
     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                 :      */
     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
     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                 : {
     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
     184          228516 : IsCatalogNamespace(Oid namespaceId)
     185                 : {
     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                 : {
     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
     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
     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 ||
     251        29128150 :         relationId == DbRoleSettingRelationId ||
     252        29117330 :         relationId == ParameterAclRelationId ||
     253        29104130 :         relationId == ReplicationOriginRelationId ||
     254        28363568 :         relationId == SharedDependRelationId ||
     255        28358669 :         relationId == SharedDescriptionRelationId ||
     256        28351162 :         relationId == SharedSecLabelRelationId ||
     257        28334390 :         relationId == SubscriptionRelationId ||
     258                 :         relationId == TableSpaceRelationId)
     259         1017261 :         return true;
     260                 :     /* These are their indexes */
     261        28315095 :     if (relationId == AuthIdOidIndexId ||
     262        28269666 :         relationId == AuthIdRolnameIndexId ||
     263        28260458 :         relationId == AuthMemMemRoleIndexId ||
     264        28254401 :         relationId == AuthMemRoleMemIndexId ||
     265 GNC    28250340 :         relationId == AuthMemOidIndexId ||
     266        28248093 :         relationId == AuthMemGrantorIndexId ||
     267 CBC    28219502 :         relationId == DatabaseNameIndexId ||
     268        28194858 :         relationId == DatabaseOidIndexId ||
     269        28151234 :         relationId == DbRoleSettingDatidRolidIndexId ||
     270        28148223 :         relationId == ParameterAclOidIndexId ||
     271        28145244 :         relationId == ParameterAclParnameIndexId ||
     272        28141375 :         relationId == ReplicationOriginIdentIndex ||
     273        28137618 :         relationId == ReplicationOriginNameIndex ||
     274        28020760 :         relationId == SharedDependDependerIndexId ||
     275        28014879 :         relationId == SharedDependReferenceIndexId ||
     276        28011329 :         relationId == SharedDescriptionObjIndexId ||
     277        28007005 :         relationId == SharedSecLabelObjectIndexId ||
     278        28003277 :         relationId == SubscriptionNameIndexId ||
     279        27999276 :         relationId == SubscriptionObjectIndexId ||
     280        27997076 :         relationId == TablespaceNameIndexId ||
     281 ECB             :         relationId == TablespaceOidIndexId)
     282 CBC      325789 :         return true;
     283                 :     /* These are their toast tables and toast indexes */
     284        27989306 :     if (relationId == PgAuthidToastTable ||
     285 GIC    27987579 :         relationId == PgAuthidToastIndex ||
     286 CBC    27986256 :         relationId == PgDatabaseToastTable ||
     287        27985275 :         relationId == PgDatabaseToastIndex ||
     288        27984281 :         relationId == PgDbRoleSettingToastTable ||
     289        27983624 :         relationId == PgDbRoleSettingToastIndex ||
     290        27982630 :         relationId == PgParameterAclToastTable ||
     291        27981973 :         relationId == PgParameterAclToastIndex ||
     292        27980979 :         relationId == PgReplicationOriginToastTable ||
     293        27980322 :         relationId == PgReplicationOriginToastIndex ||
     294        27979303 :         relationId == PgShdescriptionToastTable ||
     295        27978623 :         relationId == PgShdescriptionToastIndex ||
     296        27977629 :         relationId == PgShseclabelToastTable ||
     297        27976972 :         relationId == PgShseclabelToastIndex ||
     298        27975978 :         relationId == PgSubscriptionToastTable ||
     299        27975321 :         relationId == PgSubscriptionToastIndex ||
     300        27974308 :         relationId == PgTablespaceToastTable ||
     301 ECB             :         relationId == PgTablespaceToastIndex)
     302 CBC       15674 :         return true;
     303 GIC    27973632 :     return false;
     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
     315 GIC     4157584 : IsPinnedObject(Oid classId, Oid objectId)
     316                 : {
     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                 :      */
     322 GIC     4157584 :     if (objectId >= FirstUnpinnedObjectId)
     323          756528 :         return false;
     324 ECB             : 
     325                 :     /*
     326                 :      * Large objects are never pinned.  We need this special case because
     327                 :      * their OIDs can be user-assigned.
     328                 :      */
     329 GIC     3401056 :     if (classId == LargeObjectRelationId)
     330              27 :         return false;
     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 */
     345 GIC     3401029 :     if (classId == NamespaceRelationId &&
     346                 :         objectId == PG_PUBLIC_NAMESPACE)
     347 CBC       24674 :         return false;
     348                 : 
     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                 :      */
     355 GIC     3376355 :     if (classId == DatabaseRelationId)
     356 UIC           0 :         return false;
     357 ECB             : 
     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                 :      */
     365 GIC     3376355 :     return true;
     366                 : }
     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
     393 GIC     1106812 : GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
     394                 : {
     395 ECB             :     Oid         newOid;
     396                 :     SysScanDesc scan;
     397                 :     ScanKeyData key;
     398                 :     bool        collides;
     399 GIC     1106812 :     uint64      retries = 0;
     400         1106812 :     uint64      retries_before_log = GETNEWOID_LOG_THRESHOLD;
     401 ECB             : 
     402                 :     /* Only system relations are supported */
     403 GIC     1106812 :     Assert(IsSystemRelation(relation));
     404                 : 
     405 ECB             :     /* In bootstrap mode, we don't have any indexes to use */
     406 GIC     1106812 :     if (IsBootstrapProcessingMode())
     407           35075 :         return GetNewObjectId();
     408 ECB             : 
     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 GIC     1071737 :     Assert(!IsBinaryUpgrade || RelationGetRelid(relation) != TypeRelationId);
     416                 : 
     417 ECB             :     /* Generate new OIDs until we find one not in the table */
     418                 :     do
     419                 :     {
     420 GIC     1071737 :         CHECK_FOR_INTERRUPTS();
     421                 : 
     422 CBC     1071737 :         newOid = GetNewObjectId();
     423                 : 
     424         1071737 :         ScanKeyInit(&key,
     425                 :                     oidcolumn,
     426 ECB             :                     BTEqualStrategyNumber, F_OIDEQ,
     427                 :                     ObjectIdGetDatum(newOid));
     428                 : 
     429                 :         /* see notes above about using SnapshotAny */
     430 GIC     1071737 :         scan = systable_beginscan(relation, indexId, true,
     431                 :                                   SnapshotAny, 1, &key);
     432 ECB             : 
     433 GIC     1071737 :         collides = HeapTupleIsValid(systable_getnext(scan));
     434                 : 
     435 CBC     1071737 :         systable_endscan(scan);
     436                 : 
     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                 :          */
     446 GIC     1071737 :         if (retries >= retries_before_log)
     447                 :         {
     448 LBC           0 :             ereport(LOG,
     449                 :                     (errmsg("still searching for an unused OID in relation \"%s\"",
     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                 :              */
     460 UIC           0 :             if (retries_before_log * 2 <= GETNEWOID_LOG_MAX_INTERVAL)
     461               0 :                 retries_before_log *= 2;
     462 EUB             :             else
     463 UBC           0 :                 retries_before_log += GETNEWOID_LOG_MAX_INTERVAL;
     464                 :         }
     465 EUB             : 
     466 GIC     1071737 :         retries++;
     467         1071737 :     } while (collides);
     468 ECB             : 
     469                 :     /*
     470                 :      * If at least one log message is emitted, also log the completion of OID
     471                 :      * assignment.
     472                 :      */
     473 GIC     1071737 :     if (retries > GETNEWOID_LOG_THRESHOLD)
     474                 :     {
     475 LBC           0 :         ereport(LOG,
     476                 :                 (errmsg_plural("new OID has been assigned in relation \"%s\" after %llu retry",
     477 EUB             :                                "new OID has been assigned in relation \"%s\" after %llu retries",
     478                 :                                retries,
     479                 :                                RelationGetRelationName(relation), (unsigned long long) retries)));
     480                 :     }
     481                 : 
     482 GIC     1071737 :     return newOid;
     483                 : }
     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
     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                 :      */
     514 GIC       88262 :     Assert(!IsBinaryUpgrade);
     515                 : 
     516 CBC       88262 :     switch (relpersistence)
     517                 :     {
     518            3043 :         case RELPERSISTENCE_TEMP:
     519 GIC        3043 :             backend = BackendIdForTempRelations();
     520 CBC        3043 :             break;
     521           85219 :         case RELPERSISTENCE_UNLOGGED:
     522 ECB             :         case RELPERSISTENCE_PERMANENT:
     523 CBC       85219 :             backend = InvalidBackendId;
     524 GIC       85219 :             break;
     525 LBC           0 :         default:
     526               0 :             elog(ERROR, "invalid relpersistence: %c", relpersistence);
     527                 :             return InvalidRelFileNumber;    /* placate compiler */
     528 EUB             :     }
     529                 : 
     530                 :     /* This logic should match RelationInitPhysicalAddr */
     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;
     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                 :      */
     541 GNC       88262 :     rlocator.backend = backend;
     542                 : 
     543                 :     do
     544                 :     {
     545 CBC       88262 :         CHECK_FOR_INTERRUPTS();
     546                 : 
     547                 :         /* Generate the OID */
     548 GIC       88262 :         if (pg_class)
     549 GNC       83728 :             rlocator.locator.relNumber = GetNewOidWithIndex(pg_class, ClassOidIndexId,
     550                 :                                                             Anum_pg_class_oid);
     551                 :         else
     552            4534 :             rlocator.locator.relNumber = GetNewObjectId();
     553 ECB             : 
     554                 :         /* Check for existing file of same name */
     555 GNC       88262 :         rpath = relpath(rlocator, MAIN_FORKNUM);
     556 ECB             : 
     557 GIC       88262 :         if (access(rpath, F_OK) == 0)
     558                 :         {
     559 ECB             :             /* definite collision */
     560 UIC           0 :             collides = true;
     561 ECB             :         }
     562                 :         else
     563                 :         {
     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                 :              */
     571 GIC       88262 :             collides = false;
     572                 :         }
     573                 : 
     574           88262 :         pfree(rpath);
     575 CBC       88262 :     } while (collides);
     576                 : 
     577 GNC       88262 :     return rlocator.locator.relNumber;
     578 ECB             : }
     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 UIC           0 : pg_nextoid(PG_FUNCTION_ARGS)
     589                 : {
     590               0 :     Oid         reloid = PG_GETARG_OID(0);
     591               0 :     Name        attname = PG_GETARG_NAME(1);
     592 UBC           0 :     Oid         idxoid = PG_GETARG_OID(2);
     593                 :     Relation    rel;
     594 EUB             :     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 UIC           0 :     if (!superuser())
     607               0 :         ereport(ERROR,
     608                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     609                 :                  errmsg("must be superuser to call %s()",
     610 EUB             :                         "pg_nextoid")));
     611                 : 
     612 UIC           0 :     rel = table_open(reloid, RowExclusiveLock);
     613               0 :     idx = index_open(idxoid, RowExclusiveLock);
     614                 : 
     615               0 :     if (!IsSystemRelation(rel))
     616 UBC           0 :         ereport(ERROR,
     617 EUB             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     618                 :                  errmsg("pg_nextoid() can only be used on system catalogs")));
     619                 : 
     620 UBC           0 :     if (idx->rd_index->indrelid != RelationGetRelid(rel))
     621 UIC           0 :         ereport(ERROR,
     622                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     623                 :                  errmsg("index \"%s\" does not belong to table \"%s\"",
     624 EUB             :                         RelationGetRelationName(idx),
     625                 :                         RelationGetRelationName(rel))));
     626                 : 
     627 UIC           0 :     atttuple = SearchSysCacheAttName(reloid, NameStr(*attname));
     628               0 :     if (!HeapTupleIsValid(atttuple))
     629               0 :         ereport(ERROR,
     630                 :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
     631 EUB             :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
     632                 :                         NameStr(*attname), RelationGetRelationName(rel))));
     633                 : 
     634 UIC           0 :     attform = ((Form_pg_attribute) GETSTRUCT(atttuple));
     635               0 :     attno = attform->attnum;
     636                 : 
     637               0 :     if (attform->atttypid != OIDOID)
     638 UBC           0 :         ereport(ERROR,
     639 EUB             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     640                 :                  errmsg("column \"%s\" is not of type oid",
     641                 :                         NameStr(*attname))));
     642                 : 
     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),
     647 EUB             :                  errmsg("index \"%s\" is not the index for column \"%s\"",
     648                 :                         RelationGetRelationName(idx),
     649                 :                         NameStr(*attname))));
     650                 : 
     651 UIC           0 :     newoid = GetNewOidWithIndex(rel, idxoid, attno);
     652                 : 
     653               0 :     ReleaseSysCache(atttuple);
     654               0 :     table_close(rel, RowExclusiveLock);
     655 UBC           0 :     index_close(idx, RowExclusiveLock);
     656                 : 
     657               0 :     PG_RETURN_OID(newoid);
     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
     667 GIC         303 : pg_stop_making_pinned_objects(PG_FUNCTION_ARGS)
     668                 : {
     669                 :     /*
     670                 :      * Belt-and-suspenders check, since StopGeneratingPinnedObjectIds will
     671 ECB             :      * fail anyway in non-single-user mode.
     672                 :      */
     673 GIC         303 :     if (!superuser())
     674 UIC           0 :         ereport(ERROR,
     675                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     676                 :                  errmsg("must be superuser to call %s()",
     677 ECB             :                         "pg_stop_making_pinned_objects")));
     678 EUB             : 
     679 GIC         303 :     StopGeneratingPinnedObjectIds();
     680                 : 
     681             303 :     PG_RETURN_VOID();
     682                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a