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

Generated by: LCOV version 1.13