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

Generated by: LCOV version 1.13