LCOV - code coverage report
Current view: top level - src/bin/pg_dump - common.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 94.5 % 438 414
Test Date: 2026-09-10 10:15:32 Functions: 100.0 % 29 29
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 78.6 % 206 162

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * common.c
       4                 :             :  *  Catalog routines used by pg_dump; long ago these were shared
       5                 :             :  *  by another dump tool, but not anymore.
       6                 :             :  *
       7                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       9                 :             :  *
      10                 :             :  *
      11                 :             :  * IDENTIFICATION
      12                 :             :  *    src/bin/pg_dump/common.c
      13                 :             :  *
      14                 :             :  *-------------------------------------------------------------------------
      15                 :             :  */
      16                 :             : #include "postgres_fe.h"
      17                 :             : 
      18                 :             : #include <ctype.h>
      19                 :             : 
      20                 :             : #include "catalog/pg_am_d.h"
      21                 :             : #include "catalog/pg_class_d.h"
      22                 :             : #include "catalog/pg_collation_d.h"
      23                 :             : #include "catalog/pg_extension_d.h"
      24                 :             : #include "catalog/pg_namespace_d.h"
      25                 :             : #include "catalog/pg_operator_d.h"
      26                 :             : #include "catalog/pg_proc_d.h"
      27                 :             : #include "catalog/pg_publication_d.h"
      28                 :             : #include "catalog/pg_subscription_d.h"
      29                 :             : #include "catalog/pg_type_d.h"
      30                 :             : #include "common/hashfn.h"
      31                 :             : #include "pg_backup_utils.h"
      32                 :             : #include "pg_dump.h"
      33                 :             : 
      34                 :             : /*
      35                 :             :  * Variables for mapping DumpId to DumpableObject
      36                 :             :  */
      37                 :             : static DumpableObject **dumpIdMap = NULL;
      38                 :             : static int  allocedDumpIds = 0;
      39                 :             : static DumpId lastDumpId = 0;   /* Note: 0 is InvalidDumpId */
      40                 :             : 
      41                 :             : /*
      42                 :             :  * Infrastructure for mapping CatalogId to DumpableObject
      43                 :             :  *
      44                 :             :  * We use a hash table generated by simplehash.h.  That infrastructure
      45                 :             :  * requires all the hash table entries to be the same size, and it also
      46                 :             :  * expects that it can move them around when resizing the table.  So we
      47                 :             :  * cannot make the DumpableObjects be elements of the hash table directly;
      48                 :             :  * instead, the hash table elements contain pointers to DumpableObjects.
      49                 :             :  * This does have the advantage of letting us map multiple CatalogIds
      50                 :             :  * to one DumpableObject, which is useful for blobs.
      51                 :             :  *
      52                 :             :  * It turns out to be convenient to also use this data structure to map
      53                 :             :  * CatalogIds to owning extensions, if any.  Since extension membership
      54                 :             :  * data is read before creating most DumpableObjects, either one of dobj
      55                 :             :  * and ext could be NULL.
      56                 :             :  */
      57                 :             : typedef struct _catalogIdMapEntry
      58                 :             : {
      59                 :             :     CatalogId   catId;          /* the indexed CatalogId */
      60                 :             :     uint32      status;         /* hash status */
      61                 :             :     uint32      hashval;        /* hash code for the CatalogId */
      62                 :             :     DumpableObject *dobj;       /* the associated DumpableObject, if any */
      63                 :             :     ExtensionInfo *ext;         /* owning extension, if any */
      64                 :             : } CatalogIdMapEntry;
      65                 :             : 
      66                 :             : #define SH_PREFIX       catalogid
      67                 :             : #define SH_ELEMENT_TYPE CatalogIdMapEntry
      68                 :             : #define SH_KEY_TYPE     CatalogId
      69                 :             : #define SH_KEY          catId
      70                 :             : #define SH_HASH_KEY(tb, key)    hash_bytes((const unsigned char *) &(key), sizeof(CatalogId))
      71                 :             : #define SH_EQUAL(tb, a, b)      ((a).oid == (b).oid && (a).tableoid == (b).tableoid)
      72                 :             : #define SH_STORE_HASH
      73                 :             : #define SH_GET_HASH(tb, a) (a)->hashval
      74                 :             : #define SH_SCOPE        static inline
      75                 :             : #define SH_RAW_ALLOCATOR    pg_malloc0
      76                 :             : #define SH_DECLARE
      77                 :             : #define SH_DEFINE
      78                 :             : #include "lib/simplehash.h"
      79                 :             : 
      80                 :             : #define CATALOGIDHASH_INITIAL_SIZE  10000
      81                 :             : 
      82                 :             : static catalogid_hash *catalogIdHash = NULL;
      83                 :             : 
      84                 :             : static void flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
      85                 :             :                           InhInfo *inhinfo, int numInherits);
      86                 :             : static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables);
      87                 :             : static void flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo,
      88                 :             :                          int numTables);
      89                 :             : static int  strInArray(const char *pattern, char **arr, int arr_size);
      90                 :             : static IndxInfo *findIndexByOid(Oid oid);
      91                 :             : 
      92                 :             : 
      93                 :             : /*
      94                 :             :  * getSchemaData
      95                 :             :  *    Collect information about all potentially dumpable objects
      96                 :             :  */
      97                 :             : TableInfo *
      98                 :         194 : getSchemaData(Archive *fout, int *numTablesPtr)
      99                 :             : {
     100                 :             :     TableInfo  *tblinfo;
     101                 :             :     ExtensionInfo *extinfo;
     102                 :             :     InhInfo    *inhinfo;
     103                 :             :     int         numTables;
     104                 :             :     int         numExtensions;
     105                 :             :     int         numInherits;
     106                 :             : 
     107                 :             :     /*
     108                 :             :      * We must read extensions and extension membership info first, because
     109                 :             :      * extension membership needs to be consultable during decisions about
     110                 :             :      * whether other objects are to be dumped.
     111                 :             :      */
     112                 :         194 :     pg_log_info("reading extensions");
     113                 :         194 :     extinfo = getExtensions(fout, &numExtensions);
     114                 :             : 
     115                 :         194 :     pg_log_info("identifying extension members");
     116                 :         194 :     getExtensionMembership(fout, extinfo, numExtensions);
     117                 :             : 
     118                 :         194 :     pg_log_info("reading schemas");
     119                 :         194 :     getNamespaces(fout);
     120                 :             : 
     121                 :             :     /*
     122                 :             :      * getTables should be done as soon as possible, so as to minimize the
     123                 :             :      * window between starting our transaction and acquiring per-table locks.
     124                 :             :      * However, we have to do getNamespaces first because the tables get
     125                 :             :      * linked to their containing namespaces during getTables.
     126                 :             :      */
     127                 :         194 :     pg_log_info("reading user-defined tables");
     128                 :         194 :     tblinfo = getTables(fout, &numTables);
     129                 :             : 
     130                 :         193 :     getOwnedSeqs(fout, tblinfo, numTables);
     131                 :             : 
     132                 :         193 :     pg_log_info("reading user-defined functions");
     133                 :         193 :     getFuncs(fout);
     134                 :             : 
     135                 :             :     /* this must be after getTables and getFuncs */
     136                 :         193 :     pg_log_info("reading user-defined types");
     137                 :         193 :     getTypes(fout);
     138                 :             : 
     139                 :             :     /* this must be after getFuncs, too */
     140                 :         193 :     pg_log_info("reading procedural languages");
     141                 :         193 :     getProcLangs(fout);
     142                 :             : 
     143                 :         193 :     pg_log_info("reading user-defined aggregate functions");
     144                 :         193 :     getAggregates(fout);
     145                 :             : 
     146                 :         193 :     pg_log_info("reading user-defined operators");
     147                 :         193 :     getOperators(fout);
     148                 :             : 
     149                 :         193 :     pg_log_info("reading user-defined access methods");
     150                 :         193 :     getAccessMethods(fout);
     151                 :             : 
     152                 :         193 :     pg_log_info("reading user-defined operator classes");
     153                 :         193 :     getOpclasses(fout);
     154                 :             : 
     155                 :         193 :     pg_log_info("reading user-defined operator families");
     156                 :         193 :     getOpfamilies(fout);
     157                 :             : 
     158                 :         193 :     pg_log_info("reading user-defined text search parsers");
     159                 :         193 :     getTSParsers(fout);
     160                 :             : 
     161                 :         193 :     pg_log_info("reading user-defined text search templates");
     162                 :         193 :     getTSTemplates(fout);
     163                 :             : 
     164                 :         193 :     pg_log_info("reading user-defined text search dictionaries");
     165                 :         193 :     getTSDictionaries(fout);
     166                 :             : 
     167                 :         193 :     pg_log_info("reading user-defined text search configurations");
     168                 :         193 :     getTSConfigurations(fout);
     169                 :             : 
     170                 :         193 :     pg_log_info("reading user-defined foreign-data wrappers");
     171                 :         193 :     getForeignDataWrappers(fout);
     172                 :             : 
     173                 :         193 :     pg_log_info("reading user-defined foreign servers");
     174                 :         193 :     getForeignServers(fout);
     175                 :             : 
     176                 :         193 :     pg_log_info("reading default privileges");
     177                 :         193 :     getDefaultACLs(fout);
     178                 :             : 
     179                 :         193 :     pg_log_info("reading user-defined collations");
     180                 :         193 :     getCollations(fout);
     181                 :             : 
     182                 :         193 :     pg_log_info("reading user-defined conversions");
     183                 :         193 :     getConversions(fout);
     184                 :             : 
     185                 :         193 :     pg_log_info("reading type casts");
     186                 :         193 :     getCasts(fout);
     187                 :             : 
     188                 :         193 :     pg_log_info("reading transforms");
     189                 :         193 :     getTransforms(fout);
     190                 :             : 
     191                 :         193 :     pg_log_info("reading table inheritance information");
     192                 :         193 :     inhinfo = getInherits(fout, &numInherits);
     193                 :             : 
     194                 :         193 :     pg_log_info("reading event triggers");
     195                 :         193 :     getEventTriggers(fout);
     196                 :             : 
     197                 :             :     /* Identify extension configuration tables that should be dumped */
     198                 :         193 :     pg_log_info("finding extension tables");
     199                 :         193 :     processExtensionTables(fout, extinfo, numExtensions);
     200                 :             : 
     201                 :             :     /* Link tables to parents, mark parents of target tables interesting */
     202                 :         193 :     pg_log_info("finding inheritance relationships");
     203                 :         193 :     flagInhTables(fout, tblinfo, numTables, inhinfo, numInherits);
     204                 :             : 
     205                 :         193 :     pg_log_info("reading column info for interesting tables");
     206                 :         193 :     getTableAttrs(fout, tblinfo, numTables);
     207                 :             : 
     208                 :         193 :     pg_log_info("flagging inherited columns in subtables");
     209                 :         193 :     flagInhAttrs(fout, fout->dopt, tblinfo, numTables);
     210                 :             : 
     211                 :         193 :     pg_log_info("reading partitioning data");
     212                 :         193 :     getPartitioningInfo(fout);
     213                 :             : 
     214                 :         193 :     pg_log_info("reading indexes");
     215                 :         193 :     getIndexes(fout, tblinfo, numTables);
     216                 :             : 
     217                 :         193 :     pg_log_info("flagging indexes in partitioned tables");
     218                 :         193 :     flagInhIndexes(fout, tblinfo, numTables);
     219                 :             : 
     220                 :         193 :     pg_log_info("reading extended statistics");
     221                 :         193 :     getExtendedStatistics(fout);
     222                 :             : 
     223                 :         193 :     pg_log_info("reading constraints");
     224                 :         193 :     getConstraints(fout, tblinfo, numTables);
     225                 :             : 
     226                 :         193 :     pg_log_info("reading triggers");
     227                 :         193 :     getTriggers(fout, tblinfo, numTables);
     228                 :             : 
     229                 :         193 :     pg_log_info("reading rewrite rules");
     230                 :         193 :     getRules(fout);
     231                 :             : 
     232                 :         193 :     pg_log_info("reading policies");
     233                 :         193 :     getPolicies(fout, tblinfo, numTables);
     234                 :             : 
     235                 :         193 :     pg_log_info("reading publications");
     236                 :         193 :     getPublications(fout);
     237                 :             : 
     238                 :         193 :     pg_log_info("reading publication membership of tables");
     239                 :         193 :     getPublicationTables(fout, tblinfo, numTables);
     240                 :             : 
     241                 :         193 :     pg_log_info("reading publication membership of schemas");
     242                 :         193 :     getPublicationNamespaces(fout);
     243                 :             : 
     244                 :         193 :     pg_log_info("reading subscriptions");
     245                 :         193 :     getSubscriptions(fout);
     246                 :             : 
     247                 :         193 :     pg_log_info("reading subscription membership of relations");
     248                 :         193 :     getSubscriptionRelations(fout);
     249                 :             : 
     250                 :         193 :     free(inhinfo);              /* not needed any longer */
     251                 :             : 
     252                 :         193 :     *numTablesPtr = numTables;
     253                 :         193 :     return tblinfo;
     254                 :             : }
     255                 :             : 
     256                 :             : /*
     257                 :             :  * flagInhTables -
     258                 :             :  *   Fill in parent link fields of tables for which we need that information,
     259                 :             :  *   mark parents of target tables as interesting, and create
     260                 :             :  *   TableAttachInfo objects for partitioned tables with appropriate
     261                 :             :  *   dependency links.
     262                 :             :  *
     263                 :             :  * Note that only direct ancestors of targets are marked interesting.
     264                 :             :  * This is sufficient; we don't much care whether they inherited their
     265                 :             :  * attributes or not.
     266                 :             :  *
     267                 :             :  * modifies tblinfo
     268                 :             :  */
     269                 :             : static void
     270                 :         193 : flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
     271                 :             :               InhInfo *inhinfo, int numInherits)
     272                 :             : {
     273                 :         193 :     TableInfo  *child = NULL;
     274                 :         193 :     TableInfo  *parent = NULL;
     275                 :             :     int         i,
     276                 :             :                 j;
     277                 :             : 
     278                 :             :     /*
     279                 :             :      * Set up links from child tables to their parents.
     280                 :             :      *
     281                 :             :      * We used to attempt to skip this work for tables that are not to be
     282                 :             :      * dumped; but the optimizable cases are rare in practice, and setting up
     283                 :             :      * these links in bulk is cheaper than the old way.  (Note in particular
     284                 :             :      * that it's very rare for a child to have more than one parent.)
     285                 :             :      */
     286         [ +  + ]:        3821 :     for (i = 0; i < numInherits; i++)
     287                 :             :     {
     288                 :             :         /*
     289                 :             :          * Skip a hashtable lookup if it's same table as last time.  This is
     290                 :             :          * unlikely for the child, but less so for the parent.  (Maybe we
     291                 :             :          * should ask the backend for a sorted array to make it more likely?
     292                 :             :          * Not clear the sorting effort would be repaid, though.)
     293                 :             :          */
     294         [ +  + ]:        3628 :         if (child == NULL ||
     295         [ +  + ]:        2762 :             child->dobj.catId.oid != inhinfo[i].inhrelid)
     296                 :             :         {
     297                 :        3510 :             child = findTableByOid(inhinfo[i].inhrelid);
     298                 :             : 
     299                 :             :             /*
     300                 :             :              * If we find no TableInfo, assume the pg_inherits entry is for a
     301                 :             :              * partitioned index, which we don't need to track.
     302                 :             :              */
     303         [ +  + ]:        3510 :             if (child == NULL)
     304                 :         795 :                 continue;
     305                 :             :         }
     306         [ +  + ]:        2833 :         if (parent == NULL ||
     307         [ +  + ]:        2759 :             parent->dobj.catId.oid != inhinfo[i].inhparent)
     308                 :             :         {
     309                 :        1718 :             parent = findTableByOid(inhinfo[i].inhparent);
     310         [ -  + ]:        1718 :             if (parent == NULL)
     311                 :           0 :                 pg_fatal("failed sanity check, parent OID %u of table \"%s\" (OID %u) not found",
     312                 :             :                          inhinfo[i].inhparent,
     313                 :             :                          child->dobj.name,
     314                 :             :                          child->dobj.catId.oid);
     315                 :             :         }
     316                 :             :         /* Add this parent to the child's list of parents. */
     317         [ +  + ]:        2833 :         if (child->numParents > 0)
     318                 :         118 :             child->parents = pg_realloc_array(child->parents,
     319                 :             :                                               TableInfo *,
     320                 :             :                                               child->numParents + 1);
     321                 :             :         else
     322                 :        2715 :             child->parents = pg_malloc_array(TableInfo *, 1);
     323                 :        2833 :         child->parents[child->numParents++] = parent;
     324                 :             :     }
     325                 :             : 
     326                 :             :     /*
     327                 :             :      * Now consider all child tables and mark parents interesting as needed.
     328                 :             :      */
     329         [ +  + ]:       52309 :     for (i = 0; i < numTables; i++)
     330                 :             :     {
     331                 :             :         /*
     332                 :             :          * If needed, mark the parents as interesting for getTableAttrs and
     333                 :             :          * getIndexes.  We only need this for direct parents of dumpable
     334                 :             :          * tables.
     335                 :             :          */
     336         [ +  + ]:       52116 :         if (tblinfo[i].dobj.dump)
     337                 :             :         {
     338                 :       33321 :             int         numParents = tblinfo[i].numParents;
     339                 :       33321 :             TableInfo **parents = tblinfo[i].parents;
     340                 :             : 
     341         [ +  + ]:       35453 :             for (j = 0; j < numParents; j++)
     342                 :        2132 :                 parents[j]->interesting = true;
     343                 :             :         }
     344                 :             : 
     345                 :             :         /* Create TableAttachInfo object if needed */
     346         [ +  + ]:       52116 :         if ((tblinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
     347         [ +  + ]:        7319 :             tblinfo[i].ispartition)
     348                 :             :         {
     349                 :             :             TableAttachInfo *attachinfo;
     350                 :             : 
     351                 :             :             /* With partitions there can only be one parent */
     352         [ -  + ]:        1457 :             if (tblinfo[i].numParents != 1)
     353                 :           0 :                 pg_fatal("invalid number of parents %d for table \"%s\"",
     354                 :             :                          tblinfo[i].numParents,
     355                 :             :                          tblinfo[i].dobj.name);
     356                 :             : 
     357                 :        1457 :             attachinfo = palloc_object(TableAttachInfo);
     358                 :        1457 :             attachinfo->dobj.objType = DO_TABLE_ATTACH;
     359                 :        1457 :             attachinfo->dobj.catId.tableoid = 0;
     360                 :        1457 :             attachinfo->dobj.catId.oid = 0;
     361                 :        1457 :             AssignDumpId(&attachinfo->dobj);
     362                 :        1457 :             attachinfo->dobj.name = pg_strdup(tblinfo[i].dobj.name);
     363                 :        1457 :             attachinfo->dobj.namespace = tblinfo[i].dobj.namespace;
     364                 :        1457 :             attachinfo->parentTbl = tblinfo[i].parents[0];
     365                 :        1457 :             attachinfo->partitionTbl = &tblinfo[i];
     366                 :             : 
     367                 :             :             /*
     368                 :             :              * We must state the DO_TABLE_ATTACH object's dependencies
     369                 :             :              * explicitly, since it will not match anything in pg_depend.
     370                 :             :              *
     371                 :             :              * Give it dependencies on both the partition table and the parent
     372                 :             :              * table, so that it will not be executed till both of those
     373                 :             :              * exist.  (There's no need to care what order those are created
     374                 :             :              * in.)
     375                 :             :              */
     376                 :        1457 :             addObjectDependency(&attachinfo->dobj, tblinfo[i].dobj.dumpId);
     377                 :        1457 :             addObjectDependency(&attachinfo->dobj, tblinfo[i].parents[0]->dobj.dumpId);
     378                 :             :         }
     379                 :             :     }
     380                 :         193 : }
     381                 :             : 
     382                 :             : /*
     383                 :             :  * flagInhIndexes -
     384                 :             :  *   Create IndexAttachInfo objects for partitioned indexes, and add
     385                 :             :  *   appropriate dependency links.
     386                 :             :  */
     387                 :             : static void
     388                 :         193 : flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
     389                 :             : {
     390                 :             :     int         i,
     391                 :             :                 j;
     392                 :             : 
     393         [ +  + ]:       52309 :     for (i = 0; i < numTables; i++)
     394                 :             :     {
     395   [ +  +  -  + ]:       52116 :         if (!tblinfo[i].ispartition || tblinfo[i].numParents == 0)
     396                 :       50160 :             continue;
     397                 :             : 
     398                 :             :         Assert(tblinfo[i].numParents == 1);
     399                 :             : 
     400         [ +  + ]:        2641 :         for (j = 0; j < tblinfo[i].numIndexes; j++)
     401                 :             :         {
     402                 :         685 :             IndxInfo   *index = &(tblinfo[i].indexes[j]);
     403                 :             :             IndxInfo   *parentidx;
     404                 :             :             IndexAttachInfo *attachinfo;
     405                 :             : 
     406         [ +  + ]:         685 :             if (index->parentidx == 0)
     407                 :          60 :                 continue;
     408                 :             : 
     409                 :         625 :             parentidx = findIndexByOid(index->parentidx);
     410         [ -  + ]:         625 :             if (parentidx == NULL)
     411                 :           0 :                 continue;
     412                 :             : 
     413                 :         625 :             attachinfo = pg_malloc_object(IndexAttachInfo);
     414                 :             : 
     415                 :         625 :             attachinfo->dobj.objType = DO_INDEX_ATTACH;
     416                 :         625 :             attachinfo->dobj.catId.tableoid = 0;
     417                 :         625 :             attachinfo->dobj.catId.oid = 0;
     418                 :         625 :             AssignDumpId(&attachinfo->dobj);
     419                 :         625 :             attachinfo->dobj.name = pg_strdup(index->dobj.name);
     420                 :         625 :             attachinfo->dobj.namespace = index->indextable->dobj.namespace;
     421                 :         625 :             attachinfo->parentIdx = parentidx;
     422                 :         625 :             attachinfo->partitionIdx = index;
     423                 :             : 
     424                 :             :             /*
     425                 :             :              * We must state the DO_INDEX_ATTACH object's dependencies
     426                 :             :              * explicitly, since it will not match anything in pg_depend.
     427                 :             :              *
     428                 :             :              * Give it dependencies on both the partition index and the parent
     429                 :             :              * index, so that it will not be executed till both of those
     430                 :             :              * exist.  (There's no need to care what order those are created
     431                 :             :              * in.)
     432                 :             :              *
     433                 :             :              * In addition, give it dependencies on the indexes' underlying
     434                 :             :              * tables.  This does nothing of great value so far as serial
     435                 :             :              * restore ordering goes, but it ensures that a parallel restore
     436                 :             :              * will not try to run the ATTACH concurrently with other
     437                 :             :              * operations on those tables.
     438                 :             :              */
     439                 :         625 :             addObjectDependency(&attachinfo->dobj, index->dobj.dumpId);
     440                 :         625 :             addObjectDependency(&attachinfo->dobj, parentidx->dobj.dumpId);
     441                 :         625 :             addObjectDependency(&attachinfo->dobj,
     442                 :         625 :                                 index->indextable->dobj.dumpId);
     443                 :         625 :             addObjectDependency(&attachinfo->dobj,
     444                 :         625 :                                 parentidx->indextable->dobj.dumpId);
     445                 :             : 
     446                 :             :             /* keep track of the list of partitions in the parent index */
     447                 :         625 :             simple_ptr_list_append(&parentidx->partattaches, &attachinfo->dobj);
     448                 :             :         }
     449                 :             :     }
     450                 :         193 : }
     451                 :             : 
     452                 :             : /*
     453                 :             :  * flagInhAttrs -
     454                 :             :  *   for each dumpable table in tblinfo, flag its inherited attributes
     455                 :             :  *
     456                 :             :  * What we need to do here is:
     457                 :             :  *
     458                 :             :  * - Detect child columns that inherit NOT NULL bits from their parents, so
     459                 :             :  *   that we needn't specify that again for the child.  For versions 18 and
     460                 :             :  *   up, this is needed when the parent is NOT VALID and the child isn't.
     461                 :             :  *
     462                 :             :  * - Detect child columns that have DEFAULT NULL when their parents had some
     463                 :             :  *   non-null default.  In this case, we make up a dummy AttrDefInfo object so
     464                 :             :  *   that we'll correctly emit the necessary DEFAULT NULL clause; otherwise
     465                 :             :  *   the backend will apply an inherited default to the column.
     466                 :             :  *
     467                 :             :  * - Detect child columns that have a generation expression and all their
     468                 :             :  *   parents also have the same generation expression, and if so suppress the
     469                 :             :  *   child's expression.  The child will inherit the generation expression
     470                 :             :  *   automatically, so there's no need to dump it.  This improves the dump's
     471                 :             :  *   compatibility with pre-v16 servers, which didn't allow the child's
     472                 :             :  *   expression to be given explicitly.  Exceptions: If it's a partition or
     473                 :             :  *   we are in binary upgrade mode, we dump such expressions anyway because
     474                 :             :  *   in those cases inherited tables are recreated standalone first and then
     475                 :             :  *   reattached to the parent.  (See also the logic in dumpTableSchema().)
     476                 :             :  *
     477                 :             :  * modifies tblinfo
     478                 :             :  */
     479                 :             : static void
     480                 :         193 : flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo, int numTables)
     481                 :             : {
     482                 :             :     int         i,
     483                 :             :                 j,
     484                 :             :                 k;
     485                 :             : 
     486                 :             :     /*
     487                 :             :      * We scan the tables in OID order, since that's how tblinfo[] is sorted.
     488                 :             :      * Hence we will typically visit parents before their children --- but
     489                 :             :      * that is *not* guaranteed.  Thus this loop must be careful that it does
     490                 :             :      * not alter table properties in a way that could change decisions made at
     491                 :             :      * child tables during other iterations.
     492                 :             :      */
     493         [ +  + ]:       52309 :     for (i = 0; i < numTables; i++)
     494                 :             :     {
     495                 :       52116 :         TableInfo  *tbinfo = &(tblinfo[i]);
     496                 :             :         int         numParents;
     497                 :             :         TableInfo **parents;
     498                 :             : 
     499                 :             :         /* Some kinds never have parents */
     500         [ +  + ]:       52116 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
     501         [ +  + ]:       51469 :             tbinfo->relkind == RELKIND_VIEW ||
     502         [ +  + ]:       21528 :             tbinfo->relkind == RELKIND_MATVIEW)
     503                 :       31083 :             continue;
     504                 :             : 
     505                 :             :         /* Don't bother computing anything for non-target tables, either */
     506         [ +  + ]:       21033 :         if (!tbinfo->dobj.dump)
     507                 :        4146 :             continue;
     508                 :             : 
     509                 :       16887 :         numParents = tbinfo->numParents;
     510                 :       16887 :         parents = tbinfo->parents;
     511                 :             : 
     512         [ +  + ]:       16887 :         if (numParents == 0)
     513                 :       14846 :             continue;           /* nothing to see here, move along */
     514                 :             : 
     515                 :             :         /* For each column, search for matching column names in parent(s) */
     516         [ +  + ]:        7052 :         for (j = 0; j < tbinfo->numatts; j++)
     517                 :             :         {
     518                 :             :             bool        foundNotNull;   /* Attr was NOT NULL in a parent */
     519                 :             :             bool        foundDefault;   /* Found a default in a parent */
     520                 :             :             bool        foundSameGenerated; /* Found matching GENERATED */
     521                 :             :             bool        foundDiffGenerated; /* Found non-matching GENERATED */
     522                 :        5011 :             bool        allNotNullsInvalid = true;  /* is NOT NULL NOT VALID
     523                 :             :                                                      * on all parents? */
     524                 :             : 
     525                 :             :             /* no point in examining dropped columns */
     526         [ +  + ]:        5011 :             if (tbinfo->attisdropped[j])
     527                 :         305 :                 continue;
     528                 :             : 
     529                 :        4706 :             foundNotNull = false;
     530                 :        4706 :             foundDefault = false;
     531                 :        4706 :             foundSameGenerated = false;
     532                 :        4706 :             foundDiffGenerated = false;
     533         [ +  + ]:        9628 :             for (k = 0; k < numParents; k++)
     534                 :             :             {
     535                 :        4922 :                 TableInfo  *parent = parents[k];
     536                 :             :                 int         inhAttrInd;
     537                 :             : 
     538                 :        4922 :                 inhAttrInd = strInArray(tbinfo->attnames[j],
     539                 :             :                                         parent->attnames,
     540                 :             :                                         parent->numatts);
     541         [ +  + ]:        4922 :                 if (inhAttrInd >= 0)
     542                 :             :                 {
     543                 :        4682 :                     AttrDefInfo *parentDef = parent->attrdefs[inhAttrInd];
     544                 :             : 
     545                 :             :                     /*
     546                 :             :                      * Account for each parent having a not-null constraint.
     547                 :             :                      * In versions 18 and later, we don't need this (and those
     548                 :             :                      * didn't have NO INHERIT.)
     549                 :             :                      */
     550         [ -  + ]:        4682 :                     if (fout->remoteVersion < 180000 &&
     551         [ #  # ]:           0 :                         parent->notnull_constrs[inhAttrInd] != NULL)
     552                 :           0 :                         foundNotNull = true;
     553                 :             : 
     554                 :             :                     /*
     555                 :             :                      * Keep track of whether all the parents that have a
     556                 :             :                      * not-null constraint on this column have it as NOT
     557                 :             :                      * VALID; if they all are, arrange to have it printed for
     558                 :             :                      * this column.  If at least one parent has it as valid,
     559                 :             :                      * there's no need.
     560                 :             :                      */
     561         [ +  - ]:        4682 :                     if (fout->remoteVersion >= 180000 &&
     562         [ +  + ]:        4682 :                         parent->notnull_constrs[inhAttrInd] &&
     563         [ +  - ]:         963 :                         !parent->notnull_invalid[inhAttrInd])
     564                 :         963 :                         allNotNullsInvalid = false;
     565                 :             : 
     566                 :        9890 :                     foundDefault |= (parentDef != NULL &&
     567   [ +  +  +  + ]:        5158 :                                      strcmp(parentDef->adef_expr, "NULL") != 0 &&
     568         [ +  + ]:         476 :                                      !parent->attgenerated[inhAttrInd]);
     569         [ +  + ]:        4682 :                     if (parent->attgenerated[inhAttrInd])
     570                 :             :                     {
     571                 :             :                         /* these pointer nullness checks are just paranoia */
     572         [ +  + ]:         304 :                         if (parentDef != NULL &&
     573         [ +  - ]:         276 :                             tbinfo->attrdefs[j] != NULL &&
     574                 :         276 :                             strcmp(parentDef->adef_expr,
     575         [ +  + ]:         276 :                                    tbinfo->attrdefs[j]->adef_expr) == 0)
     576                 :         246 :                             foundSameGenerated = true;
     577                 :             :                         else
     578                 :          58 :                             foundDiffGenerated = true;
     579                 :             :                     }
     580                 :             :                 }
     581                 :             :             }
     582                 :             : 
     583                 :             :             /*
     584                 :             :              * In versions < 18, for lack of a better system, we arbitrarily
     585                 :             :              * decide that a not-null constraint is not locally defined if at
     586                 :             :              * least one of the parents has it.
     587                 :             :              */
     588   [ -  +  -  - ]:        4706 :             if (fout->remoteVersion < 180000 && foundNotNull)
     589                 :           0 :                 tbinfo->notnull_islocal[j] = false;
     590                 :             : 
     591                 :             :             /*
     592                 :             :              * For versions >18, we must print the not-null constraint locally
     593                 :             :              * for this table even if it isn't really locally defined, but is
     594                 :             :              * valid for the child and no parent has it as valid.
     595                 :             :              */
     596   [ +  -  +  + ]:        4706 :             if (fout->remoteVersion >= 180000 && allNotNullsInvalid)
     597                 :        3748 :                 tbinfo->notnull_islocal[j] = true;
     598                 :             : 
     599                 :             :             /*
     600                 :             :              * Manufacture a DEFAULT NULL clause if necessary.  This breaks
     601                 :             :              * the advice given above to avoid changing state that might get
     602                 :             :              * inspected in other loop iterations.  We prevent trouble by
     603                 :             :              * having the foundDefault test above check whether adef_expr is
     604                 :             :              * "NULL", so that it will reach the same conclusion before or
     605                 :             :              * after this is done.
     606                 :             :              */
     607   [ +  +  +  + ]:        4706 :             if (foundDefault && tbinfo->attrdefs[j] == NULL)
     608                 :             :             {
     609                 :             :                 AttrDefInfo *attrDef;
     610                 :             : 
     611                 :          40 :                 attrDef = pg_malloc_object(AttrDefInfo);
     612                 :          40 :                 attrDef->dobj.objType = DO_ATTRDEF;
     613                 :          40 :                 attrDef->dobj.catId.tableoid = 0;
     614                 :          40 :                 attrDef->dobj.catId.oid = 0;
     615                 :          40 :                 AssignDumpId(&attrDef->dobj);
     616                 :          40 :                 attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
     617                 :          40 :                 attrDef->dobj.namespace = tbinfo->dobj.namespace;
     618                 :          40 :                 attrDef->dobj.dump = tbinfo->dobj.dump;
     619                 :             : 
     620                 :          40 :                 attrDef->adtable = tbinfo;
     621                 :          40 :                 attrDef->adnum = j + 1;
     622                 :          40 :                 attrDef->adef_expr = pg_strdup("NULL");
     623                 :             : 
     624                 :             :                 /* Will column be dumped explicitly? */
     625         [ +  - ]:          40 :                 if (shouldPrintColumn(dopt, tbinfo, j))
     626                 :             :                 {
     627                 :          40 :                     attrDef->separate = false;
     628                 :             :                     /* No dependency needed: NULL cannot have dependencies */
     629                 :             :                 }
     630                 :             :                 else
     631                 :             :                 {
     632                 :             :                     /* column will be suppressed, print default separately */
     633                 :           0 :                     attrDef->separate = true;
     634                 :             :                     /* ensure it comes out after the table */
     635                 :           0 :                     addObjectDependency(&attrDef->dobj,
     636                 :             :                                         tbinfo->dobj.dumpId);
     637                 :             :                 }
     638                 :             : 
     639                 :          40 :                 tbinfo->attrdefs[j] = attrDef;
     640                 :             :             }
     641                 :             : 
     642                 :             :             /* No need to dump generation expression if it's inheritable */
     643   [ +  +  +  - ]:        4706 :             if (foundSameGenerated && !foundDiffGenerated &&
     644   [ +  +  +  + ]:         246 :                 !tbinfo->ispartition && !dopt->binary_upgrade)
     645                 :         164 :                 tbinfo->attrdefs[j]->dobj.dump = DUMP_COMPONENT_NONE;
     646                 :             :         }
     647                 :             :     }
     648                 :         193 : }
     649                 :             : 
     650                 :             : /*
     651                 :             :  * AssignDumpId
     652                 :             :  *      Given a newly-created dumpable object, assign a dump ID,
     653                 :             :  *      and enter the object into the lookup tables.
     654                 :             :  *
     655                 :             :  * The caller is expected to have filled in objType and catId,
     656                 :             :  * but not any of the other standard fields of a DumpableObject.
     657                 :             :  */
     658                 :             : void
     659                 :      733187 : AssignDumpId(DumpableObject *dobj)
     660                 :             : {
     661                 :      733187 :     dobj->dumpId = ++lastDumpId;
     662                 :      733187 :     dobj->name = NULL;           /* must be set later */
     663                 :      733187 :     dobj->namespace = NULL;      /* may be set later */
     664                 :      733187 :     dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
     665                 :      733187 :     dobj->dump_contains = DUMP_COMPONENT_ALL;    /* default assumption */
     666                 :             :     /* All objects have definitions; we may set more components bits later */
     667                 :      733187 :     dobj->components = DUMP_COMPONENT_DEFINITION;
     668                 :      733187 :     dobj->ext_member = false;    /* default assumption */
     669                 :      733187 :     dobj->depends_on_ext = false;    /* default assumption */
     670                 :      733187 :     dobj->dependencies = NULL;
     671                 :      733187 :     dobj->nDeps = 0;
     672                 :      733187 :     dobj->allocDeps = 0;
     673                 :             : 
     674                 :             :     /* Add object to dumpIdMap[], enlarging that array if need be */
     675         [ +  + ]:      734167 :     while (dobj->dumpId >= allocedDumpIds)
     676                 :             :     {
     677                 :             :         int         newAlloc;
     678                 :             : 
     679         [ +  + ]:         980 :         if (allocedDumpIds <= 0)
     680                 :             :         {
     681                 :         194 :             newAlloc = 256;
     682                 :         194 :             dumpIdMap = pg_malloc_array(DumpableObject *, newAlloc);
     683                 :             :         }
     684                 :             :         else
     685                 :             :         {
     686                 :         786 :             newAlloc = allocedDumpIds * 2;
     687                 :         786 :             dumpIdMap = pg_realloc_array(dumpIdMap, DumpableObject *, newAlloc);
     688                 :             :         }
     689                 :         980 :         memset(dumpIdMap + allocedDumpIds, 0,
     690                 :         980 :                (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
     691                 :         980 :         allocedDumpIds = newAlloc;
     692                 :             :     }
     693                 :      733187 :     dumpIdMap[dobj->dumpId] = dobj;
     694                 :             : 
     695                 :             :     /* If it has a valid CatalogId, enter it into the hash table */
     696         [ +  + ]:      733187 :     if (OidIsValid(dobj->catId.tableoid))
     697                 :             :     {
     698                 :             :         CatalogIdMapEntry *entry;
     699                 :             :         bool        found;
     700                 :             : 
     701                 :             :         /* Initialize CatalogId hash table if not done yet */
     702         [ +  + ]:      713430 :         if (catalogIdHash == NULL)
     703                 :         194 :             catalogIdHash = catalogid_create(CATALOGIDHASH_INITIAL_SIZE, NULL);
     704                 :             : 
     705                 :      713430 :         entry = catalogid_insert(catalogIdHash, dobj->catId, &found);
     706         [ +  + ]:      713430 :         if (!found)
     707                 :             :         {
     708                 :      712505 :             entry->dobj = NULL;
     709                 :      712505 :             entry->ext = NULL;
     710                 :             :         }
     711                 :             :         Assert(entry->dobj == NULL);
     712                 :      713430 :         entry->dobj = dobj;
     713                 :             :     }
     714                 :      733187 : }
     715                 :             : 
     716                 :             : /*
     717                 :             :  * recordAdditionalCatalogID
     718                 :             :  *    Record an additional catalog ID for the given DumpableObject
     719                 :             :  */
     720                 :             : void
     721                 :          14 : recordAdditionalCatalogID(CatalogId catId, DumpableObject *dobj)
     722                 :             : {
     723                 :             :     CatalogIdMapEntry *entry;
     724                 :             :     bool        found;
     725                 :             : 
     726                 :             :     /* CatalogId hash table must exist, if we have a DumpableObject */
     727                 :             :     Assert(catalogIdHash != NULL);
     728                 :             : 
     729                 :             :     /* Add reference to CatalogId hash */
     730                 :          14 :     entry = catalogid_insert(catalogIdHash, catId, &found);
     731         [ +  - ]:          14 :     if (!found)
     732                 :             :     {
     733                 :          14 :         entry->dobj = NULL;
     734                 :          14 :         entry->ext = NULL;
     735                 :             :     }
     736                 :             :     Assert(entry->dobj == NULL);
     737                 :          14 :     entry->dobj = dobj;
     738                 :          14 : }
     739                 :             : 
     740                 :             : /*
     741                 :             :  * Assign a DumpId that's not tied to a DumpableObject.
     742                 :             :  *
     743                 :             :  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
     744                 :             :  * participate in the sorting logic.
     745                 :             :  */
     746                 :             : DumpId
     747                 :       13694 : createDumpId(void)
     748                 :             : {
     749                 :       13694 :     return ++lastDumpId;
     750                 :             : }
     751                 :             : 
     752                 :             : /*
     753                 :             :  * Return the largest DumpId so far assigned
     754                 :             :  */
     755                 :             : DumpId
     756                 :        1318 : getMaxDumpId(void)
     757                 :             : {
     758                 :        1318 :     return lastDumpId;
     759                 :             : }
     760                 :             : 
     761                 :             : /*
     762                 :             :  * Find a DumpableObject by dump ID
     763                 :             :  *
     764                 :             :  * Returns NULL for invalid ID
     765                 :             :  */
     766                 :             : DumpableObject *
     767                 :    23285599 : findObjectByDumpId(DumpId dumpId)
     768                 :             : {
     769   [ +  -  -  + ]:    23285599 :     if (dumpId <= 0 || dumpId >= allocedDumpIds)
     770                 :           0 :         return NULL;            /* out of range? */
     771                 :    23285599 :     return dumpIdMap[dumpId];
     772                 :             : }
     773                 :             : 
     774                 :             : /*
     775                 :             :  * Find a DumpableObject by catalog ID
     776                 :             :  *
     777                 :             :  * Returns NULL for unknown ID
     778                 :             :  */
     779                 :             : DumpableObject *
     780                 :     3935920 : findObjectByCatalogId(CatalogId catalogId)
     781                 :             : {
     782                 :             :     CatalogIdMapEntry *entry;
     783                 :             : 
     784         [ -  + ]:     3935920 :     if (catalogIdHash == NULL)
     785                 :           0 :         return NULL;            /* no objects exist yet */
     786                 :             : 
     787                 :     3935920 :     entry = catalogid_lookup(catalogIdHash, catalogId);
     788         [ +  + ]:     3935920 :     if (entry == NULL)
     789                 :      704663 :         return NULL;
     790                 :     3231257 :     return entry->dobj;
     791                 :             : }
     792                 :             : 
     793                 :             : /*
     794                 :             :  * Build an array of pointers to all known dumpable objects
     795                 :             :  *
     796                 :             :  * This simply creates a modifiable copy of the internal map.
     797                 :             :  */
     798                 :             : void
     799                 :         200 : getDumpableObjects(DumpableObject ***objs, int *numObjs)
     800                 :             : {
     801                 :             :     int         i,
     802                 :             :                 j;
     803                 :             : 
     804                 :         200 :     *objs = pg_malloc_array(DumpableObject *, allocedDumpIds);
     805                 :         200 :     j = 0;
     806         [ +  + ]:      892928 :     for (i = 1; i < allocedDumpIds; i++)
     807                 :             :     {
     808         [ +  + ]:      892728 :         if (dumpIdMap[i])
     809                 :      759327 :             (*objs)[j++] = dumpIdMap[i];
     810                 :             :     }
     811                 :         200 :     *numObjs = j;
     812                 :         200 : }
     813                 :             : 
     814                 :             : /*
     815                 :             :  * Add a dependency link to a DumpableObject
     816                 :             :  *
     817                 :             :  * Note: duplicate dependencies are currently not eliminated
     818                 :             :  */
     819                 :             : void
     820                 :     1153811 : addObjectDependency(DumpableObject *dobj, DumpId refId)
     821                 :             : {
     822         [ +  + ]:     1153811 :     if (dobj->nDeps >= dobj->allocDeps)
     823                 :             :     {
     824         [ +  + ]:      197188 :         if (dobj->allocDeps <= 0)
     825                 :             :         {
     826                 :      187814 :             dobj->allocDeps = 16;
     827                 :      187814 :             dobj->dependencies = pg_malloc_array(DumpId, dobj->allocDeps);
     828                 :             :         }
     829                 :             :         else
     830                 :             :         {
     831                 :        9374 :             dobj->allocDeps *= 2;
     832                 :        9374 :             dobj->dependencies = pg_realloc_array(dobj->dependencies,
     833                 :             :                                                   DumpId, dobj->allocDeps);
     834                 :             :         }
     835                 :             :     }
     836                 :     1153811 :     dobj->dependencies[dobj->nDeps++] = refId;
     837                 :     1153811 : }
     838                 :             : 
     839                 :             : /*
     840                 :             :  * Remove a dependency link from a DumpableObject
     841                 :             :  *
     842                 :             :  * If there are multiple links, all are removed
     843                 :             :  */
     844                 :             : void
     845                 :       33632 : removeObjectDependency(DumpableObject *dobj, DumpId refId)
     846                 :             : {
     847                 :             :     int         i;
     848                 :       33632 :     int         j = 0;
     849                 :             : 
     850         [ +  + ]:      750489 :     for (i = 0; i < dobj->nDeps; i++)
     851                 :             :     {
     852         [ +  + ]:      716857 :         if (dobj->dependencies[i] != refId)
     853                 :      681726 :             dobj->dependencies[j++] = dobj->dependencies[i];
     854                 :             :     }
     855                 :       33632 :     dobj->nDeps = j;
     856                 :       33632 : }
     857                 :             : 
     858                 :             : 
     859                 :             : /*
     860                 :             :  * findTableByOid
     861                 :             :  *    finds the DumpableObject for the table with the given oid
     862                 :             :  *    returns NULL if not found
     863                 :             :  */
     864                 :             : TableInfo *
     865                 :       90116 : findTableByOid(Oid oid)
     866                 :             : {
     867                 :             :     CatalogId   catId;
     868                 :             :     DumpableObject *dobj;
     869                 :             : 
     870                 :       90116 :     catId.tableoid = RelationRelationId;
     871                 :       90116 :     catId.oid = oid;
     872                 :       90116 :     dobj = findObjectByCatalogId(catId);
     873                 :             :     Assert(dobj == NULL || dobj->objType == DO_TABLE);
     874                 :       90116 :     return (TableInfo *) dobj;
     875                 :             : }
     876                 :             : 
     877                 :             : /*
     878                 :             :  * findIndexByOid
     879                 :             :  *    finds the DumpableObject for the index with the given oid
     880                 :             :  *    returns NULL if not found
     881                 :             :  */
     882                 :             : static IndxInfo *
     883                 :         625 : findIndexByOid(Oid oid)
     884                 :             : {
     885                 :             :     CatalogId   catId;
     886                 :             :     DumpableObject *dobj;
     887                 :             : 
     888                 :         625 :     catId.tableoid = RelationRelationId;
     889                 :         625 :     catId.oid = oid;
     890                 :         625 :     dobj = findObjectByCatalogId(catId);
     891                 :             :     Assert(dobj == NULL || dobj->objType == DO_INDEX);
     892                 :         625 :     return (IndxInfo *) dobj;
     893                 :             : }
     894                 :             : 
     895                 :             : /*
     896                 :             :  * findTypeByOid
     897                 :             :  *    finds the DumpableObject for the type with the given oid
     898                 :             :  *    returns NULL if not found
     899                 :             :  */
     900                 :             : TypeInfo *
     901                 :     1486335 : findTypeByOid(Oid oid)
     902                 :             : {
     903                 :             :     CatalogId   catId;
     904                 :             :     DumpableObject *dobj;
     905                 :             : 
     906                 :     1486335 :     catId.tableoid = TypeRelationId;
     907                 :     1486335 :     catId.oid = oid;
     908                 :     1486335 :     dobj = findObjectByCatalogId(catId);
     909                 :             :     Assert(dobj == NULL ||
     910                 :             :            dobj->objType == DO_TYPE || dobj->objType == DO_DUMMY_TYPE);
     911                 :     1486335 :     return (TypeInfo *) dobj;
     912                 :             : }
     913                 :             : 
     914                 :             : /*
     915                 :             :  * findFuncByOid
     916                 :             :  *    finds the DumpableObject for the function with the given oid
     917                 :             :  *    returns NULL if not found
     918                 :             :  */
     919                 :             : FuncInfo *
     920                 :         267 : findFuncByOid(Oid oid)
     921                 :             : {
     922                 :             :     CatalogId   catId;
     923                 :             :     DumpableObject *dobj;
     924                 :             : 
     925                 :         267 :     catId.tableoid = ProcedureRelationId;
     926                 :         267 :     catId.oid = oid;
     927                 :         267 :     dobj = findObjectByCatalogId(catId);
     928                 :             :     Assert(dobj == NULL || dobj->objType == DO_FUNC);
     929                 :         267 :     return (FuncInfo *) dobj;
     930                 :             : }
     931                 :             : 
     932                 :             : /*
     933                 :             :  * findOprByOid
     934                 :             :  *    finds the DumpableObject for the operator with the given oid
     935                 :             :  *    returns NULL if not found
     936                 :             :  */
     937                 :             : OprInfo *
     938                 :        2860 : findOprByOid(Oid oid)
     939                 :             : {
     940                 :             :     CatalogId   catId;
     941                 :             :     DumpableObject *dobj;
     942                 :             : 
     943                 :        2860 :     catId.tableoid = OperatorRelationId;
     944                 :        2860 :     catId.oid = oid;
     945                 :        2860 :     dobj = findObjectByCatalogId(catId);
     946                 :             :     Assert(dobj == NULL || dobj->objType == DO_OPERATOR);
     947                 :        2860 :     return (OprInfo *) dobj;
     948                 :             : }
     949                 :             : 
     950                 :             : /*
     951                 :             :  * findAccessMethodByOid
     952                 :             :  *    finds the DumpableObject for the access method with the given oid
     953                 :             :  *    returns NULL if not found
     954                 :             :  */
     955                 :             : AccessMethodInfo *
     956                 :       53346 : findAccessMethodByOid(Oid oid)
     957                 :             : {
     958                 :             :     CatalogId   catId;
     959                 :             :     DumpableObject *dobj;
     960                 :             : 
     961                 :       53346 :     catId.tableoid = AccessMethodRelationId;
     962                 :       53346 :     catId.oid = oid;
     963                 :       53346 :     dobj = findObjectByCatalogId(catId);
     964                 :             :     Assert(dobj == NULL || dobj->objType == DO_ACCESS_METHOD);
     965                 :       53346 :     return (AccessMethodInfo *) dobj;
     966                 :             : }
     967                 :             : 
     968                 :             : /*
     969                 :             :  * findCollationByOid
     970                 :             :  *    finds the DumpableObject for the collation with the given oid
     971                 :             :  *    returns NULL if not found
     972                 :             :  */
     973                 :             : CollInfo *
     974                 :         276 : findCollationByOid(Oid oid)
     975                 :             : {
     976                 :             :     CatalogId   catId;
     977                 :             :     DumpableObject *dobj;
     978                 :             : 
     979                 :         276 :     catId.tableoid = CollationRelationId;
     980                 :         276 :     catId.oid = oid;
     981                 :         276 :     dobj = findObjectByCatalogId(catId);
     982                 :             :     Assert(dobj == NULL || dobj->objType == DO_COLLATION);
     983                 :         276 :     return (CollInfo *) dobj;
     984                 :             : }
     985                 :             : 
     986                 :             : /*
     987                 :             :  * findNamespaceByOid
     988                 :             :  *    finds the DumpableObject for the namespace with the given oid
     989                 :             :  *    returns NULL if not found
     990                 :             :  */
     991                 :             : NamespaceInfo *
     992                 :      622775 : findNamespaceByOid(Oid oid)
     993                 :             : {
     994                 :             :     CatalogId   catId;
     995                 :             :     DumpableObject *dobj;
     996                 :             : 
     997                 :      622775 :     catId.tableoid = NamespaceRelationId;
     998                 :      622775 :     catId.oid = oid;
     999                 :      622775 :     dobj = findObjectByCatalogId(catId);
    1000                 :             :     Assert(dobj == NULL || dobj->objType == DO_NAMESPACE);
    1001                 :      622775 :     return (NamespaceInfo *) dobj;
    1002                 :             : }
    1003                 :             : 
    1004                 :             : /*
    1005                 :             :  * findExtensionByOid
    1006                 :             :  *    finds the DumpableObject for the extension with the given oid
    1007                 :             :  *    returns NULL if not found
    1008                 :             :  */
    1009                 :             : ExtensionInfo *
    1010                 :         225 : findExtensionByOid(Oid oid)
    1011                 :             : {
    1012                 :             :     CatalogId   catId;
    1013                 :             :     DumpableObject *dobj;
    1014                 :             : 
    1015                 :         225 :     catId.tableoid = ExtensionRelationId;
    1016                 :         225 :     catId.oid = oid;
    1017                 :         225 :     dobj = findObjectByCatalogId(catId);
    1018                 :             :     Assert(dobj == NULL || dobj->objType == DO_EXTENSION);
    1019                 :         225 :     return (ExtensionInfo *) dobj;
    1020                 :             : }
    1021                 :             : 
    1022                 :             : /*
    1023                 :             :  * findPublicationByOid
    1024                 :             :  *    finds the DumpableObject for the publication with the given oid
    1025                 :             :  *    returns NULL if not found
    1026                 :             :  */
    1027                 :             : PublicationInfo *
    1028                 :         502 : findPublicationByOid(Oid oid)
    1029                 :             : {
    1030                 :             :     CatalogId   catId;
    1031                 :             :     DumpableObject *dobj;
    1032                 :             : 
    1033                 :         502 :     catId.tableoid = PublicationRelationId;
    1034                 :         502 :     catId.oid = oid;
    1035                 :         502 :     dobj = findObjectByCatalogId(catId);
    1036                 :             :     Assert(dobj == NULL || dobj->objType == DO_PUBLICATION);
    1037                 :         502 :     return (PublicationInfo *) dobj;
    1038                 :             : }
    1039                 :             : 
    1040                 :             : /*
    1041                 :             :  * findSubscriptionByOid
    1042                 :             :  *    finds the DumpableObject for the subscription with the given oid
    1043                 :             :  *    returns NULL if not found
    1044                 :             :  */
    1045                 :             : SubscriptionInfo *
    1046                 :           2 : findSubscriptionByOid(Oid oid)
    1047                 :             : {
    1048                 :             :     CatalogId   catId;
    1049                 :             :     DumpableObject *dobj;
    1050                 :             : 
    1051                 :           2 :     catId.tableoid = SubscriptionRelationId;
    1052                 :           2 :     catId.oid = oid;
    1053                 :           2 :     dobj = findObjectByCatalogId(catId);
    1054                 :             :     Assert(dobj == NULL || dobj->objType == DO_SUBSCRIPTION);
    1055                 :           2 :     return (SubscriptionInfo *) dobj;
    1056                 :             : }
    1057                 :             : 
    1058                 :             : 
    1059                 :             : /*
    1060                 :             :  * recordExtensionMembership
    1061                 :             :  *    Record that the object identified by the given catalog ID
    1062                 :             :  *    belongs to the given extension
    1063                 :             :  */
    1064                 :             : void
    1065                 :        1382 : recordExtensionMembership(CatalogId catId, ExtensionInfo *ext)
    1066                 :             : {
    1067                 :             :     CatalogIdMapEntry *entry;
    1068                 :             :     bool        found;
    1069                 :             : 
    1070                 :             :     /* CatalogId hash table must exist, if we have an ExtensionInfo */
    1071                 :             :     Assert(catalogIdHash != NULL);
    1072                 :             : 
    1073                 :             :     /* Add reference to CatalogId hash */
    1074                 :        1382 :     entry = catalogid_insert(catalogIdHash, catId, &found);
    1075         [ +  - ]:        1382 :     if (!found)
    1076                 :             :     {
    1077                 :        1382 :         entry->dobj = NULL;
    1078                 :        1382 :         entry->ext = NULL;
    1079                 :             :     }
    1080                 :             :     Assert(entry->ext == NULL);
    1081                 :        1382 :     entry->ext = ext;
    1082                 :        1382 : }
    1083                 :             : 
    1084                 :             : /*
    1085                 :             :  * findOwningExtension
    1086                 :             :  *    return owning extension for specified catalog ID, or NULL if none
    1087                 :             :  */
    1088                 :             : ExtensionInfo *
    1089                 :      622881 : findOwningExtension(CatalogId catalogId)
    1090                 :             : {
    1091                 :             :     CatalogIdMapEntry *entry;
    1092                 :             : 
    1093         [ -  + ]:      622881 :     if (catalogIdHash == NULL)
    1094                 :           0 :         return NULL;            /* no objects exist yet */
    1095                 :             : 
    1096                 :      622881 :     entry = catalogid_lookup(catalogIdHash, catalogId);
    1097         [ -  + ]:      622881 :     if (entry == NULL)
    1098                 :           0 :         return NULL;
    1099                 :      622881 :     return entry->ext;
    1100                 :             : }
    1101                 :             : 
    1102                 :             : 
    1103                 :             : /*
    1104                 :             :  * parseOidArray
    1105                 :             :  *    parse a string of unsigned numbers separated by spaces
    1106                 :             :  *    into an array of OIDs
    1107                 :             :  *
    1108                 :             :  * The result is a malloc'd array.
    1109                 :             :  *
    1110                 :             :  * If arraysize >= 0, we insist that the input contain exactly that many
    1111                 :             :  * OIDs, and the allocated array is of that length too.  If arraysize < 0,
    1112                 :             :  * we dynamically size the array to have one more entry than the input
    1113                 :             :  * provides, and fill the extra entry with zero.
    1114                 :             :  */
    1115                 :             : Oid *
    1116                 :        4202 : parseOidArray(const char *str, int arraysize)
    1117                 :             : {
    1118                 :             :     Oid        *array;
    1119                 :             :     int         allocsize,
    1120                 :             :                 argNum,
    1121                 :             :                 templen;
    1122                 :             :     char        temp[32];
    1123                 :             : 
    1124         [ +  + ]:        4202 :     if (arraysize >= 0)
    1125                 :        4197 :         allocsize = arraysize;
    1126                 :             :     else
    1127                 :             :     {
    1128                 :             :         /*
    1129                 :             :          * Make enough room for input + one extra entry (could be more than
    1130                 :             :          * enough, if there are redundant spaces in the input).
    1131                 :             :          */
    1132                 :           5 :         allocsize = 2;
    1133         [ +  + ]:          15 :         for (const char *s1 = str; *s1; s1++)
    1134                 :             :         {
    1135         [ -  + ]:          10 :             if (*s1 == ' ')
    1136                 :           0 :                 allocsize++;
    1137                 :             :         }
    1138                 :             :     }
    1139                 :        4202 :     array = pg_malloc_array(Oid, allocsize);
    1140                 :        4202 :     argNum = 0;
    1141                 :        4202 :     templen = 0;
    1142                 :        4202 :     for (const char *s1 = str;; s1++)
    1143                 :       19560 :     {
    1144                 :       23762 :         char        s = *s1;
    1145                 :             : 
    1146   [ +  +  +  + ]:       23762 :         if (s == ' ' || s == '\0')
    1147                 :             :         {
    1148         [ +  - ]:        6764 :             if (templen > 0)
    1149                 :             :             {
    1150   [ +  +  -  + ]:        6764 :                 if (arraysize >= 0 && argNum >= arraysize)
    1151                 :           0 :                     pg_fatal("could not parse numeric array \"%s\": too many numbers", str);
    1152                 :        6764 :                 temp[templen] = '\0';
    1153                 :        6764 :                 array[argNum++] = atooid(temp);
    1154                 :        6764 :                 templen = 0;
    1155                 :             :             }
    1156         [ +  + ]:        6764 :             if (s == '\0')
    1157                 :        4202 :                 break;
    1158                 :             :         }
    1159                 :             :         else
    1160                 :             :         {
    1161         [ +  - ]:       16998 :             if (!isdigit((unsigned char) s) ||
    1162         [ -  + ]:       16998 :                 templen >= sizeof(temp) - 1)
    1163                 :           0 :                 pg_fatal("could not parse numeric array \"%s\": invalid character in number", str);
    1164                 :       16998 :             temp[templen++] = s;
    1165                 :             :         }
    1166                 :             :     }
    1167                 :             : 
    1168   [ +  +  -  + ]:        4202 :     if (arraysize >= 0 && argNum != arraysize)
    1169                 :           0 :         pg_fatal("could not parse numeric array \"%s\": too few numbers", str);
    1170                 :             : 
    1171         [ +  + ]:        4207 :     while (argNum < allocsize)
    1172                 :           5 :         array[argNum++] = InvalidOid;
    1173                 :             : 
    1174                 :        4202 :     return array;
    1175                 :             : }
    1176                 :             : 
    1177                 :             : 
    1178                 :             : /*
    1179                 :             :  * parseIntArray
    1180                 :             :  *    parse a string of possibly-signed numbers separated by spaces
    1181                 :             :  *    into an array of ints
    1182                 :             :  *
    1183                 :             :  * This is exactly like parseOidArray, but for integers.
    1184                 :             :  */
    1185                 :             : int *
    1186                 :        2743 : parseIntArray(const char *str, int arraysize)
    1187                 :             : {
    1188                 :             :     int        *array;
    1189                 :             :     int         allocsize,
    1190                 :             :                 argNum,
    1191                 :             :                 templen;
    1192                 :             :     char        temp[32];
    1193                 :             : 
    1194         [ +  - ]:        2743 :     if (arraysize >= 0)
    1195                 :        2743 :         allocsize = arraysize;
    1196                 :             :     else
    1197                 :             :     {
    1198                 :             :         /*
    1199                 :             :          * Make enough room for input + one extra entry (could be more than
    1200                 :             :          * enough, if there are redundant spaces in the input).
    1201                 :             :          */
    1202                 :           0 :         allocsize = 2;
    1203         [ #  # ]:           0 :         for (const char *s1 = str; *s1; s1++)
    1204                 :             :         {
    1205         [ #  # ]:           0 :             if (*s1 == ' ')
    1206                 :           0 :                 allocsize++;
    1207                 :             :         }
    1208                 :             :     }
    1209                 :        2743 :     array = pg_malloc_array(int, allocsize);
    1210                 :        2743 :     argNum = 0;
    1211                 :        2743 :     templen = 0;
    1212                 :        2743 :     for (const char *s1 = str;; s1++)
    1213                 :        6269 :     {
    1214                 :        9012 :         char        s = *s1;
    1215                 :             : 
    1216   [ +  +  +  + ]:        9012 :         if (s == ' ' || s == '\0')
    1217                 :             :         {
    1218         [ +  - ]:        4376 :             if (templen > 0)
    1219                 :             :             {
    1220   [ +  -  -  + ]:        4376 :                 if (arraysize >= 0 && argNum >= arraysize)
    1221                 :           0 :                     pg_fatal("could not parse numeric array \"%s\": too many numbers", str);
    1222                 :        4376 :                 temp[templen] = '\0';
    1223                 :        4376 :                 array[argNum++] = atoi(temp);
    1224                 :        4376 :                 templen = 0;
    1225                 :             :             }
    1226         [ +  + ]:        4376 :             if (s == '\0')
    1227                 :        2743 :                 break;
    1228                 :             :         }
    1229                 :             :         else
    1230                 :             :         {
    1231   [ -  +  -  - ]:        4636 :             if (!(isdigit((unsigned char) s) || s == '-') ||
    1232         [ -  + ]:        4636 :                 templen >= sizeof(temp) - 1)
    1233                 :           0 :                 pg_fatal("could not parse numeric array \"%s\": invalid character in number", str);
    1234                 :        4636 :             temp[templen++] = s;
    1235                 :             :         }
    1236                 :             :     }
    1237                 :             : 
    1238   [ +  -  -  + ]:        2743 :     if (arraysize >= 0 && argNum != arraysize)
    1239                 :           0 :         pg_fatal("could not parse numeric array \"%s\": too few numbers", str);
    1240                 :             : 
    1241         [ -  + ]:        2743 :     while (argNum < allocsize)
    1242                 :           0 :         array[argNum++] = 0;
    1243                 :             : 
    1244                 :        2743 :     return array;
    1245                 :             : }
    1246                 :             : 
    1247                 :             : 
    1248                 :             : /*
    1249                 :             :  * strInArray:
    1250                 :             :  *    takes in a string and a string array and the number of elements in the
    1251                 :             :  * string array.
    1252                 :             :  *    returns the index if the string is somewhere in the array, -1 otherwise
    1253                 :             :  */
    1254                 :             : 
    1255                 :             : static int
    1256                 :        4922 : strInArray(const char *pattern, char **arr, int arr_size)
    1257                 :             : {
    1258                 :             :     int         i;
    1259                 :             : 
    1260         [ +  + ]:        9626 :     for (i = 0; i < arr_size; i++)
    1261                 :             :     {
    1262         [ +  + ]:        9386 :         if (strcmp(pattern, arr[i]) == 0)
    1263                 :        4682 :             return i;
    1264                 :             :     }
    1265                 :         240 :     return -1;
    1266                 :             : }
        

Generated by: LCOV version 2.0-1