LCOV - differential code coverage report
Current view: top level - src/bin/pg_dump - common.c (source / functions) Coverage Total Hit UNC LBC UIC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 96.6 % 381 368 2 5 6 3 181 45 139 9 183 1 41
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 25 25 24 1 21 4
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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-2023, 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_class_d.h"
      21                 : #include "catalog/pg_collation_d.h"
      22                 : #include "catalog/pg_extension_d.h"
      23                 : #include "catalog/pg_namespace_d.h"
      24                 : #include "catalog/pg_operator_d.h"
      25                 : #include "catalog/pg_proc_d.h"
      26                 : #include "catalog/pg_publication_d.h"
      27                 : #include "catalog/pg_type_d.h"
      28                 : #include "common/hashfn.h"
      29                 : #include "fe_utils/string_utils.h"
      30                 : #include "pg_backup_archiver.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                 :  *
      50                 :  * It turns out to be convenient to also use this data structure to map
      51                 :  * CatalogIds to owning extensions, if any.  Since extension membership
      52                 :  * data is read before creating most DumpableObjects, either one of dobj
      53                 :  * and ext could be NULL.
      54                 :  */
      55                 : typedef struct _catalogIdMapEntry
      56                 : {
      57                 :     CatalogId   catId;          /* the indexed CatalogId */
      58                 :     uint32      status;         /* hash status */
      59                 :     uint32      hashval;        /* hash code for the CatalogId */
      60                 :     DumpableObject *dobj;       /* the associated DumpableObject, if any */
      61                 :     ExtensionInfo *ext;         /* owning extension, if any */
      62                 : } CatalogIdMapEntry;
      63                 : 
      64                 : #define SH_PREFIX       catalogid
      65                 : #define SH_ELEMENT_TYPE CatalogIdMapEntry
      66                 : #define SH_KEY_TYPE     CatalogId
      67                 : #define SH_KEY          catId
      68                 : #define SH_HASH_KEY(tb, key)    hash_bytes((const unsigned char *) &(key), sizeof(CatalogId))
      69                 : #define SH_EQUAL(tb, a, b)      ((a).oid == (b).oid && (a).tableoid == (b).tableoid)
      70                 : #define SH_STORE_HASH
      71                 : #define SH_GET_HASH(tb, a) (a)->hashval
      72                 : #define SH_SCOPE        static inline
      73                 : #define SH_RAW_ALLOCATOR    pg_malloc0
      74                 : #define SH_DECLARE
      75                 : #define SH_DEFINE
      76                 : #include "lib/simplehash.h"
      77                 : 
      78                 : #define CATALOGIDHASH_INITIAL_SIZE  10000
      79                 : 
      80                 : static catalogid_hash *catalogIdHash = NULL;
      81                 : 
      82                 : static void flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
      83                 :                           InhInfo *inhinfo, int numInherits);
      84                 : static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables);
      85                 : static void flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo,
      86                 :                          int numTables);
      87                 : static int  strInArray(const char *pattern, char **arr, int arr_size);
      88                 : static IndxInfo *findIndexByOid(Oid oid);
      89                 : 
      90                 : 
      91                 : /*
      92                 :  * getSchemaData
      93                 :  *    Collect information about all potentially dumpable objects
      94                 :  */
      95 ECB             : TableInfo *
      96 GIC         119 : getSchemaData(Archive *fout, int *numTablesPtr)
      97                 : {
      98                 :     TableInfo  *tblinfo;
      99                 :     ExtensionInfo *extinfo;
     100                 :     InhInfo    *inhinfo;
     101                 :     int         numTables;
     102                 :     int         numTypes;
     103                 :     int         numFuncs;
     104                 :     int         numOperators;
     105                 :     int         numCollations;
     106                 :     int         numNamespaces;
     107                 :     int         numExtensions;
     108                 :     int         numPublications;
     109                 :     int         numAggregates;
     110                 :     int         numInherits;
     111                 :     int         numRules;
     112                 :     int         numProcLangs;
     113                 :     int         numCasts;
     114                 :     int         numTransforms;
     115                 :     int         numAccessMethods;
     116                 :     int         numOpclasses;
     117                 :     int         numOpfamilies;
     118                 :     int         numConversions;
     119                 :     int         numTSParsers;
     120                 :     int         numTSTemplates;
     121                 :     int         numTSDicts;
     122                 :     int         numTSConfigs;
     123                 :     int         numForeignDataWrappers;
     124                 :     int         numForeignServers;
     125                 :     int         numDefaultACLs;
     126                 :     int         numEventTriggers;
     127                 : 
     128                 :     /*
     129                 :      * We must read extensions and extension membership info first, because
     130                 :      * extension membership needs to be consultable during decisions about
     131                 :      * whether other objects are to be dumped.
     132 ECB             :      */
     133 CBC         119 :     pg_log_info("reading extensions");
     134 GIC         119 :     extinfo = getExtensions(fout, &numExtensions);
     135 ECB             : 
     136 CBC         119 :     pg_log_info("identifying extension members");
     137 GIC         119 :     getExtensionMembership(fout, extinfo, numExtensions);
     138 ECB             : 
     139 CBC         119 :     pg_log_info("reading schemas");
     140 GIC         119 :     (void) getNamespaces(fout, &numNamespaces);
     141                 : 
     142                 :     /*
     143                 :      * getTables should be done as soon as possible, so as to minimize the
     144                 :      * window between starting our transaction and acquiring per-table locks.
     145                 :      * However, we have to do getNamespaces first because the tables get
     146                 :      * linked to their containing namespaces during getTables.
     147 ECB             :      */
     148 CBC         119 :     pg_log_info("reading user-defined tables");
     149 GIC         119 :     tblinfo = getTables(fout, &numTables);
     150 ECB             : 
     151 GIC         118 :     getOwnedSeqs(fout, tblinfo, numTables);
     152 ECB             : 
     153 CBC         118 :     pg_log_info("reading user-defined functions");
     154 GIC         118 :     (void) getFuncs(fout, &numFuncs);
     155                 : 
     156 ECB             :     /* this must be after getTables and getFuncs */
     157 CBC         118 :     pg_log_info("reading user-defined types");
     158 GIC         118 :     (void) getTypes(fout, &numTypes);
     159                 : 
     160 ECB             :     /* this must be after getFuncs, too */
     161 CBC         118 :     pg_log_info("reading procedural languages");
     162 GIC         118 :     getProcLangs(fout, &numProcLangs);
     163 ECB             : 
     164 CBC         118 :     pg_log_info("reading user-defined aggregate functions");
     165 GIC         118 :     getAggregates(fout, &numAggregates);
     166 ECB             : 
     167 CBC         118 :     pg_log_info("reading user-defined operators");
     168 GIC         118 :     (void) getOperators(fout, &numOperators);
     169 ECB             : 
     170 CBC         118 :     pg_log_info("reading user-defined access methods");
     171 GIC         118 :     getAccessMethods(fout, &numAccessMethods);
     172 ECB             : 
     173 CBC         118 :     pg_log_info("reading user-defined operator classes");
     174 GIC         118 :     getOpclasses(fout, &numOpclasses);
     175 ECB             : 
     176 CBC         118 :     pg_log_info("reading user-defined operator families");
     177 GIC         118 :     getOpfamilies(fout, &numOpfamilies);
     178 ECB             : 
     179 CBC         118 :     pg_log_info("reading user-defined text search parsers");
     180 GIC         118 :     getTSParsers(fout, &numTSParsers);
     181 ECB             : 
     182 CBC         118 :     pg_log_info("reading user-defined text search templates");
     183 GIC         118 :     getTSTemplates(fout, &numTSTemplates);
     184 ECB             : 
     185 CBC         118 :     pg_log_info("reading user-defined text search dictionaries");
     186 GIC         118 :     getTSDictionaries(fout, &numTSDicts);
     187 ECB             : 
     188 CBC         118 :     pg_log_info("reading user-defined text search configurations");
     189 GIC         118 :     getTSConfigurations(fout, &numTSConfigs);
     190 ECB             : 
     191 CBC         118 :     pg_log_info("reading user-defined foreign-data wrappers");
     192 GIC         118 :     getForeignDataWrappers(fout, &numForeignDataWrappers);
     193 ECB             : 
     194 CBC         118 :     pg_log_info("reading user-defined foreign servers");
     195 GIC         118 :     getForeignServers(fout, &numForeignServers);
     196 ECB             : 
     197 CBC         118 :     pg_log_info("reading default privileges");
     198 GIC         118 :     getDefaultACLs(fout, &numDefaultACLs);
     199 ECB             : 
     200 CBC         118 :     pg_log_info("reading user-defined collations");
     201 GIC         118 :     (void) getCollations(fout, &numCollations);
     202 ECB             : 
     203 CBC         118 :     pg_log_info("reading user-defined conversions");
     204 GIC         118 :     getConversions(fout, &numConversions);
     205 ECB             : 
     206 CBC         118 :     pg_log_info("reading type casts");
     207 GIC         118 :     getCasts(fout, &numCasts);
     208 ECB             : 
     209 CBC         118 :     pg_log_info("reading transforms");
     210 GIC         118 :     getTransforms(fout, &numTransforms);
     211 ECB             : 
     212 CBC         118 :     pg_log_info("reading table inheritance information");
     213 GIC         118 :     inhinfo = getInherits(fout, &numInherits);
     214 ECB             : 
     215 CBC         118 :     pg_log_info("reading event triggers");
     216 GIC         118 :     getEventTriggers(fout, &numEventTriggers);
     217                 : 
     218 ECB             :     /* Identify extension configuration tables that should be dumped */
     219 CBC         118 :     pg_log_info("finding extension tables");
     220 GIC         118 :     processExtensionTables(fout, extinfo, numExtensions);
     221                 : 
     222 ECB             :     /* Link tables to parents, mark parents of target tables interesting */
     223 CBC         118 :     pg_log_info("finding inheritance relationships");
     224 GIC         118 :     flagInhTables(fout, tblinfo, numTables, inhinfo, numInherits);
     225 ECB             : 
     226 CBC         118 :     pg_log_info("reading column info for interesting tables");
     227 GIC         118 :     getTableAttrs(fout, tblinfo, numTables);
     228 ECB             : 
     229 CBC         118 :     pg_log_info("flagging inherited columns in subtables");
     230 GNC         118 :     flagInhAttrs(fout, fout->dopt, tblinfo, numTables);
     231 ECB             : 
     232 CBC         118 :     pg_log_info("reading partitioning data");
     233 GIC         118 :     getPartitioningInfo(fout);
     234 ECB             : 
     235 CBC         118 :     pg_log_info("reading indexes");
     236 GIC         118 :     getIndexes(fout, tblinfo, numTables);
     237 ECB             : 
     238 CBC         118 :     pg_log_info("flagging indexes in partitioned tables");
     239 GIC         118 :     flagInhIndexes(fout, tblinfo, numTables);
     240 ECB             : 
     241 CBC         118 :     pg_log_info("reading extended statistics");
     242 GIC         118 :     getExtendedStatistics(fout);
     243 ECB             : 
     244 CBC         118 :     pg_log_info("reading constraints");
     245 GIC         118 :     getConstraints(fout, tblinfo, numTables);
     246 ECB             : 
     247 CBC         118 :     pg_log_info("reading triggers");
     248 GIC         118 :     getTriggers(fout, tblinfo, numTables);
     249 ECB             : 
     250 CBC         118 :     pg_log_info("reading rewrite rules");
     251 GIC         118 :     getRules(fout, &numRules);
     252 ECB             : 
     253 CBC         118 :     pg_log_info("reading policies");
     254 GIC         118 :     getPolicies(fout, tblinfo, numTables);
     255 ECB             : 
     256 CBC         118 :     pg_log_info("reading publications");
     257 GIC         118 :     (void) getPublications(fout, &numPublications);
     258 ECB             : 
     259 CBC         118 :     pg_log_info("reading publication membership of tables");
     260 GIC         118 :     getPublicationTables(fout, tblinfo, numTables);
     261 ECB             : 
     262 CBC         118 :     pg_log_info("reading publication membership of schemas");
     263 GIC         118 :     getPublicationNamespaces(fout);
     264 ECB             : 
     265 CBC         118 :     pg_log_info("reading subscriptions");
     266 GIC         118 :     getSubscriptions(fout);
     267 ECB             : 
     268 GIC         118 :     free(inhinfo);              /* not needed any longer */
     269 ECB             : 
     270 CBC         118 :     *numTablesPtr = numTables;
     271 GIC         118 :     return tblinfo;
     272                 : }
     273                 : 
     274                 : /* flagInhTables -
     275                 :  *   Fill in parent link fields of tables for which we need that information,
     276                 :  *   mark parents of target tables as interesting, and create
     277                 :  *   TableAttachInfo objects for partitioned tables with appropriate
     278                 :  *   dependency links.
     279                 :  *
     280                 :  * Note that only direct ancestors of targets are marked interesting.
     281                 :  * This is sufficient; we don't much care whether they inherited their
     282                 :  * attributes or not.
     283                 :  *
     284                 :  * modifies tblinfo
     285                 :  */
     286 ECB             : static void
     287 GIC         118 : flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
     288                 :               InhInfo *inhinfo, int numInherits)
     289 ECB             : {
     290 GNC         118 :     TableInfo  *child = NULL;
     291             118 :     TableInfo  *parent = NULL;
     292 ECB             :     int         i,
     293                 :                 j;
     294                 : 
     295                 :     /*
     296                 :      * Set up links from child tables to their parents.
     297                 :      *
     298                 :      * We used to attempt to skip this work for tables that are not to be
     299                 :      * dumped; but the optimizable cases are rare in practice, and setting up
     300                 :      * these links in bulk is cheaper than the old way.  (Note in particular
     301                 :      * that it's very rare for a child to have more than one parent.)
     302                 :      */
     303 GNC        2272 :     for (i = 0; i < numInherits; i++)
     304                 :     {
     305                 :         /*
     306                 :          * Skip a hashtable lookup if it's same table as last time.  This is
     307                 :          * unlikely for the child, but less so for the parent.  (Maybe we
     308                 :          * should ask the backend for a sorted array to make it more likely?
     309                 :          * Not clear the sorting effort would be repaid, though.)
     310                 :          */
     311            2154 :         if (child == NULL ||
     312            1543 :             child->dobj.catId.oid != inhinfo[i].inhrelid)
     313                 :         {
     314            2129 :             child = findTableByOid(inhinfo[i].inhrelid);
     315                 : 
     316                 :             /*
     317                 :              * If we find no TableInfo, assume the pg_inherits entry is for a
     318                 :              * partitioned index, which we don't need to track.
     319                 :              */
     320            2129 :             if (child == NULL)
     321             607 :                 continue;
     322                 :         }
     323            1547 :         if (parent == NULL ||
     324            1495 :             parent->dobj.catId.oid != inhinfo[i].inhparent)
     325                 :         {
     326             960 :             parent = findTableByOid(inhinfo[i].inhparent);
     327             960 :             if (parent == NULL)
     328 UNC           0 :                 pg_fatal("failed sanity check, parent OID %u of table \"%s\" (OID %u) not found",
     329                 :                          inhinfo[i].inhparent,
     330                 :                          child->dobj.name,
     331                 :                          child->dobj.catId.oid);
     332                 :         }
     333                 :         /* Add this parent to the child's list of parents. */
     334 GNC        1547 :         if (child->numParents > 0)
     335              25 :             child->parents = pg_realloc_array(child->parents,
     336                 :                                               TableInfo *,
     337                 :                                               child->numParents + 1);
     338                 :         else
     339            1522 :             child->parents = pg_malloc_array(TableInfo *, 1);
     340            1547 :         child->parents[child->numParents++] = parent;
     341                 :     }
     342                 : 
     343                 :     /*
     344                 :      * Now consider all child tables and mark parents interesting as needed.
     345                 :      */
     346 GIC       30474 :     for (i = 0; i < numTables; i++)
     347                 :     {
     348                 :         /*
     349 ECB             :          * If needed, mark the parents as interesting for getTableAttrs and
     350                 :          * getIndexes.  We only need this for direct parents of dumpable
     351                 :          * tables.
     352 EUB             :          */
     353 GNC       30356 :         if (tblinfo[i].dobj.dump)
     354                 :         {
     355 GIC       20412 :             int         numParents = tblinfo[i].numParents;
     356           20412 :             TableInfo **parents = tblinfo[i].parents;
     357                 : 
     358 CBC       21915 :             for (j = 0; j < numParents; j++)
     359            1503 :                 parents[j]->interesting = true;
     360                 :         }
     361                 : 
     362                 :         /* Create TableAttachInfo object if needed */
     363 GNC       30356 :         if ((tblinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
     364            5139 :             tblinfo[i].ispartition)
     365 ECB             :         {
     366                 :             TableAttachInfo *attachinfo;
     367                 : 
     368                 :             /* With partitions there can only be one parent */
     369 GIC        1166 :             if (tblinfo[i].numParents != 1)
     370 UIC           0 :                 pg_fatal("invalid number of parents %d for table \"%s\"",
     371 ECB             :                          tblinfo[i].numParents,
     372                 :                          tblinfo[i].dobj.name);
     373                 : 
     374 GIC        1166 :             attachinfo = (TableAttachInfo *) palloc(sizeof(TableAttachInfo));
     375            1166 :             attachinfo->dobj.objType = DO_TABLE_ATTACH;
     376            1166 :             attachinfo->dobj.catId.tableoid = 0;
     377            1166 :             attachinfo->dobj.catId.oid = 0;
     378 CBC        1166 :             AssignDumpId(&attachinfo->dobj);
     379 GIC        1166 :             attachinfo->dobj.name = pg_strdup(tblinfo[i].dobj.name);
     380 CBC        1166 :             attachinfo->dobj.namespace = tblinfo[i].dobj.namespace;
     381            1166 :             attachinfo->parentTbl = tblinfo[i].parents[0];
     382 GIC        1166 :             attachinfo->partitionTbl = &tblinfo[i];
     383 ECB             : 
     384                 :             /*
     385                 :              * We must state the DO_TABLE_ATTACH object's dependencies
     386                 :              * explicitly, since it will not match anything in pg_depend.
     387                 :              *
     388                 :              * Give it dependencies on both the partition table and the parent
     389                 :              * table, so that it will not be executed till both of those
     390                 :              * exist.  (There's no need to care what order those are created
     391                 :              * in.)
     392                 :              */
     393 GIC        1166 :             addObjectDependency(&attachinfo->dobj, tblinfo[i].dobj.dumpId);
     394 CBC        1166 :             addObjectDependency(&attachinfo->dobj, tblinfo[i].parents[0]->dobj.dumpId);
     395 EUB             :         }
     396                 :     }
     397 GIC         118 : }
     398                 : 
     399 ECB             : /*
     400                 :  * flagInhIndexes -
     401                 :  *   Create IndexAttachInfo objects for partitioned indexes, and add
     402                 :  *   appropriate dependency links.
     403                 :  */
     404                 : static void
     405 CBC         118 : flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
     406 ECB             : {
     407                 :     int         i,
     408                 :                 j;
     409                 : 
     410 GIC       30474 :     for (i = 0; i < numTables; i++)
     411                 :     {
     412           30356 :         if (!tblinfo[i].ispartition || tblinfo[i].numParents == 0)
     413           29164 :             continue;
     414                 : 
     415            1192 :         Assert(tblinfo[i].numParents == 1);
     416                 : 
     417            1809 :         for (j = 0; j < tblinfo[i].numIndexes; j++)
     418 ECB             :         {
     419 CBC         617 :             IndxInfo   *index = &(tblinfo[i].indexes[j]);
     420                 :             IndxInfo   *parentidx;
     421                 :             IndexAttachInfo *attachinfo;
     422 ECB             : 
     423 GIC         617 :             if (index->parentidx == 0)
     424              50 :                 continue;
     425                 : 
     426             567 :             parentidx = findIndexByOid(index->parentidx);
     427             567 :             if (parentidx == NULL)
     428 UIC           0 :                 continue;
     429                 : 
     430 GNC         567 :             attachinfo = pg_malloc_object(IndexAttachInfo);
     431                 : 
     432 GIC         567 :             attachinfo->dobj.objType = DO_INDEX_ATTACH;
     433             567 :             attachinfo->dobj.catId.tableoid = 0;
     434             567 :             attachinfo->dobj.catId.oid = 0;
     435 CBC         567 :             AssignDumpId(&attachinfo->dobj);
     436 GIC         567 :             attachinfo->dobj.name = pg_strdup(index->dobj.name);
     437 CBC         567 :             attachinfo->dobj.namespace = index->indextable->dobj.namespace;
     438             567 :             attachinfo->parentIdx = parentidx;
     439 GIC         567 :             attachinfo->partitionIdx = index;
     440 ECB             : 
     441                 :             /*
     442                 :              * We must state the DO_INDEX_ATTACH object's dependencies
     443                 :              * explicitly, since it will not match anything in pg_depend.
     444                 :              *
     445                 :              * Give it dependencies on both the partition index and the parent
     446                 :              * index, so that it will not be executed till both of those
     447                 :              * exist.  (There's no need to care what order those are created
     448                 :              * in.)
     449                 :              *
     450                 :              * In addition, give it dependencies on the indexes' underlying
     451                 :              * tables.  This does nothing of great value so far as serial
     452                 :              * restore ordering goes, but it ensures that a parallel restore
     453 EUB             :              * will not try to run the ATTACH concurrently with other
     454                 :              * operations on those tables.
     455 ECB             :              */
     456 GIC         567 :             addObjectDependency(&attachinfo->dobj, index->dobj.dumpId);
     457 CBC         567 :             addObjectDependency(&attachinfo->dobj, parentidx->dobj.dumpId);
     458             567 :             addObjectDependency(&attachinfo->dobj,
     459             567 :                                 index->indextable->dobj.dumpId);
     460             567 :             addObjectDependency(&attachinfo->dobj,
     461             567 :                                 parentidx->indextable->dobj.dumpId);
     462 ECB             : 
     463                 :             /* keep track of the list of partitions in the parent index */
     464 CBC         567 :             simple_ptr_list_append(&parentidx->partattaches, &attachinfo->dobj);
     465                 :         }
     466                 :     }
     467 GIC         118 : }
     468                 : 
     469                 : /* flagInhAttrs -
     470                 :  *   for each dumpable table in tblinfo, flag its inherited attributes
     471                 :  *
     472                 :  * What we need to do here is:
     473                 :  *
     474                 :  * - Detect child columns that inherit NOT NULL bits from their parents, so
     475                 :  *   that we needn't specify that again for the child. (Versions >= 16 no
     476                 :  *   longer need this.)
     477                 :  *
     478                 :  * - Detect child columns that have DEFAULT NULL when their parents had some
     479                 :  *   non-null default.  In this case, we make up a dummy AttrDefInfo object so
     480                 :  *   that we'll correctly emit the necessary DEFAULT NULL clause; otherwise
     481                 :  *   the backend will apply an inherited default to the column.
     482 ECB             :  *
     483                 :  * - Detect child columns that have a generation expression and all their
     484                 :  *   parents also have the same generation expression, and if so suppress the
     485                 :  *   child's expression.  The child will inherit the generation expression
     486                 :  *   automatically, so there's no need to dump it.  This improves the dump's
     487                 :  *   compatibility with pre-v16 servers, which didn't allow the child's
     488                 :  *   expression to be given explicitly.  Exceptions: If it's a partition or
     489                 :  *   we are in binary upgrade mode, we dump such expressions anyway because
     490                 :  *   in those cases inherited tables are recreated standalone first and then
     491                 :  *   reattached to the parent.  (See also the logic in dumpTableSchema().)
     492                 :  *
     493                 :  * modifies tblinfo
     494                 :  */
     495                 : static void
     496 GNC         118 : flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo, int numTables)
     497                 : {
     498                 :     int         i,
     499                 :                 j,
     500                 :                 k;
     501                 : 
     502                 :     /*
     503                 :      * We scan the tables in OID order, since that's how tblinfo[] is sorted.
     504                 :      * Hence we will typically visit parents before their children --- but
     505                 :      * that is *not* guaranteed.  Thus this loop must be careful that it does
     506                 :      * not alter table properties in a way that could change decisions made at
     507                 :      * child tables during other iterations.
     508                 :      */
     509 GIC       30474 :     for (i = 0; i < numTables; i++)
     510                 :     {
     511           30356 :         TableInfo  *tbinfo = &(tblinfo[i]);
     512                 :         int         numParents;
     513                 :         TableInfo **parents;
     514                 : 
     515                 :         /* Some kinds never have parents */
     516           30356 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
     517           29911 :             tbinfo->relkind == RELKIND_VIEW ||
     518           12993 :             tbinfo->relkind == RELKIND_MATVIEW)
     519           17763 :             continue;
     520                 : 
     521                 :         /* Don't bother computing anything for non-target tables, either */
     522           12593 :         if (!tbinfo->dobj.dump)
     523            1425 :             continue;
     524                 : 
     525           11168 :         numParents = tbinfo->numParents;
     526           11168 :         parents = tbinfo->parents;
     527                 : 
     528           11168 :         if (numParents == 0)
     529            9690 :             continue;           /* nothing to see here, move along */
     530 ECB             : 
     531                 :         /* For each column, search for matching column names in parent(s) */
     532 GIC        5485 :         for (j = 0; j < tbinfo->numatts; j++)
     533                 :         {
     534                 :             bool        foundNotNull;   /* Attr was NOT NULL in a parent */
     535                 :             bool        foundDefault;   /* Found a default in a parent */
     536                 :             bool        foundSameGenerated; /* Found matching GENERATED */
     537                 :             bool        foundDiffGenerated; /* Found non-matching GENERATED */
     538                 : 
     539                 :             /* no point in examining dropped columns */
     540            4007 :             if (tbinfo->attisdropped[j])
     541             305 :                 continue;
     542                 : 
     543            3702 :             foundNotNull = false;
     544 CBC        3702 :             foundDefault = false;
     545 GNC        3702 :             foundSameGenerated = false;
     546            3702 :             foundDiffGenerated = false;
     547 CBC        7524 :             for (k = 0; k < numParents; k++)
     548                 :             {
     549 GIC        3822 :                 TableInfo  *parent = parents[k];
     550                 :                 int         inhAttrInd;
     551                 : 
     552 CBC        3822 :                 inhAttrInd = strInArray(tbinfo->attnames[j],
     553 ECB             :                                         parent->attnames,
     554                 :                                         parent->numatts);
     555 CBC        3822 :                 if (inhAttrInd >= 0)
     556                 :                 {
     557 GNC        3637 :                     AttrDefInfo *parentDef = parent->attrdefs[inhAttrInd];
     558                 : 
     559 GIC        3637 :                     foundNotNull |= parent->notnull[inhAttrInd];
     560 GNC        7654 :                     foundDefault |= (parentDef != NULL &&
     561            3967 :                                      strcmp(parentDef->adef_expr, "NULL") != 0 &&
     562             330 :                                      !parent->attgenerated[inhAttrInd]);
     563            3637 :                     if (parent->attgenerated[inhAttrInd])
     564                 :                     {
     565                 :                         /* these pointer nullness checks are just paranoia */
     566             128 :                         if (parentDef != NULL &&
     567             122 :                             tbinfo->attrdefs[j] != NULL &&
     568             122 :                             strcmp(parentDef->adef_expr,
     569             122 :                                    tbinfo->attrdefs[j]->adef_expr) == 0)
     570              97 :                             foundSameGenerated = true;
     571                 :                         else
     572              31 :                             foundDiffGenerated = true;
     573                 :                     }
     574                 :                 }
     575 ECB             :             }
     576                 : 
     577                 :             /* In versions < 16, remember if we found inherited NOT NULL */
     578 GNC        3702 :             if (fout->remoteVersion < 160000)
     579 UNC           0 :                 tbinfo->localNotNull[j] = !foundNotNull;
     580 ECB             : 
     581                 :             /*
     582                 :              * Manufacture a DEFAULT NULL clause if necessary.  This breaks
     583                 :              * the advice given above to avoid changing state that might get
     584                 :              * inspected in other loop iterations.  We prevent trouble by
     585                 :              * having the foundDefault test above check whether adef_expr is
     586                 :              * "NULL", so that it will reach the same conclusion before or
     587                 :              * after this is done.
     588                 :              */
     589 GIC        3702 :             if (foundDefault && tbinfo->attrdefs[j] == NULL)
     590 ECB             :             {
     591                 :                 AttrDefInfo *attrDef;
     592                 : 
     593 GNC          40 :                 attrDef = pg_malloc_object(AttrDefInfo);
     594 GIC          40 :                 attrDef->dobj.objType = DO_ATTRDEF;
     595              40 :                 attrDef->dobj.catId.tableoid = 0;
     596              40 :                 attrDef->dobj.catId.oid = 0;
     597              40 :                 AssignDumpId(&attrDef->dobj);
     598 CBC          40 :                 attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
     599              40 :                 attrDef->dobj.namespace = tbinfo->dobj.namespace;
     600 GIC          40 :                 attrDef->dobj.dump = tbinfo->dobj.dump;
     601 ECB             : 
     602 CBC          40 :                 attrDef->adtable = tbinfo;
     603              40 :                 attrDef->adnum = j + 1;
     604              40 :                 attrDef->adef_expr = pg_strdup("NULL");
     605 ECB             : 
     606                 :                 /* Will column be dumped explicitly? */
     607 CBC          40 :                 if (shouldPrintColumn(dopt, tbinfo, j))
     608                 :                 {
     609 GIC          40 :                     attrDef->separate = false;
     610 ECB             :                     /* No dependency needed: NULL cannot have dependencies */
     611                 :                 }
     612                 :                 else
     613                 :                 {
     614                 :                     /* column will be suppressed, print default separately */
     615 LBC           0 :                     attrDef->separate = true;
     616                 :                     /* ensure it comes out after the table */
     617               0 :                     addObjectDependency(&attrDef->dobj,
     618 ECB             :                                         tbinfo->dobj.dumpId);
     619                 :                 }
     620                 : 
     621 CBC          40 :                 tbinfo->attrdefs[j] = attrDef;
     622                 :             }
     623                 : 
     624                 :             /* No need to dump generation expression if it's inheritable */
     625 GNC        3702 :             if (foundSameGenerated && !foundDiffGenerated &&
     626              97 :                 !tbinfo->ispartition && !dopt->binary_upgrade)
     627              86 :                 tbinfo->attrdefs[j]->dobj.dump = DUMP_COMPONENT_NONE;
     628 ECB             :         }
     629                 :     }
     630 GIC         118 : }
     631 ECB             : 
     632                 : /*
     633                 :  * AssignDumpId
     634                 :  *      Given a newly-created dumpable object, assign a dump ID,
     635                 :  *      and enter the object into the lookup tables.
     636                 :  *
     637                 :  * The caller is expected to have filled in objType and catId,
     638 EUB             :  * but not any of the other standard fields of a DumpableObject.
     639                 :  */
     640                 : void
     641 GIC      510276 : AssignDumpId(DumpableObject *dobj)
     642                 : {
     643          510276 :     dobj->dumpId = ++lastDumpId;
     644          510276 :     dobj->name = NULL;           /* must be set later */
     645          510276 :     dobj->namespace = NULL;      /* may be set later */
     646          510276 :     dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
     647          510276 :     dobj->dump_contains = DUMP_COMPONENT_ALL;    /* default assumption */
     648 ECB             :     /* All objects have definitions; we may set more components bits later */
     649 GIC      510276 :     dobj->components = DUMP_COMPONENT_DEFINITION;
     650          510276 :     dobj->ext_member = false;    /* default assumption */
     651          510276 :     dobj->depends_on_ext = false;    /* default assumption */
     652 CBC      510276 :     dobj->dependencies = NULL;
     653          510276 :     dobj->nDeps = 0;
     654          510276 :     dobj->allocDeps = 0;
     655 ECB             : 
     656                 :     /* Add object to dumpIdMap[], enlarging that array if need be */
     657 CBC      510923 :     while (dobj->dumpId >= allocedDumpIds)
     658 ECB             :     {
     659                 :         int         newAlloc;
     660                 : 
     661 CBC         647 :         if (allocedDumpIds <= 0)
     662 ECB             :         {
     663 CBC         119 :             newAlloc = 256;
     664 GNC         119 :             dumpIdMap = pg_malloc_array(DumpableObject *, newAlloc);
     665 ECB             :         }
     666                 :         else
     667                 :         {
     668 GIC         528 :             newAlloc = allocedDumpIds * 2;
     669 GNC         528 :             dumpIdMap = pg_realloc_array(dumpIdMap, DumpableObject *, newAlloc);
     670                 :         }
     671 GIC         647 :         memset(dumpIdMap + allocedDumpIds, 0,
     672 GBC         647 :                (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
     673 GIC         647 :         allocedDumpIds = newAlloc;
     674 EUB             :     }
     675 GIC      510276 :     dumpIdMap[dobj->dumpId] = dobj;
     676                 : 
     677                 :     /* If it has a valid CatalogId, enter it into the hash table */
     678 CBC      510276 :     if (OidIsValid(dobj->catId.tableoid))
     679                 :     {
     680                 :         CatalogIdMapEntry *entry;
     681                 :         bool        found;
     682 ECB             : 
     683                 :         /* Initialize CatalogId hash table if not done yet */
     684 CBC      498767 :         if (catalogIdHash == NULL)
     685 GIC         119 :             catalogIdHash = catalogid_create(CATALOGIDHASH_INITIAL_SIZE, NULL);
     686                 : 
     687 CBC      498767 :         entry = catalogid_insert(catalogIdHash, dobj->catId, &found);
     688 GIC      498767 :         if (!found)
     689                 :         {
     690          498295 :             entry->dobj = NULL;
     691          498295 :             entry->ext = NULL;
     692                 :         }
     693          498767 :         Assert(entry->dobj == NULL);
     694          498767 :         entry->dobj = dobj;
     695                 :     }
     696          510276 : }
     697                 : 
     698 ECB             : /*
     699                 :  * Assign a DumpId that's not tied to a DumpableObject.
     700                 :  *
     701                 :  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
     702                 :  * participate in the sorting logic.
     703                 :  */
     704                 : DumpId
     705 GIC        3626 : createDumpId(void)
     706 ECB             : {
     707 CBC        3626 :     return ++lastDumpId;
     708 ECB             : }
     709                 : 
     710                 : /*
     711                 :  * Return the largest DumpId so far assigned
     712                 :  */
     713                 : DumpId
     714 CBC         898 : getMaxDumpId(void)
     715                 : {
     716 GIC         898 :     return lastDumpId;
     717                 : }
     718 ECB             : 
     719                 : /*
     720                 :  * Find a DumpableObject by dump ID
     721                 :  *
     722                 :  * Returns NULL for invalid ID
     723                 :  */
     724                 : DumpableObject *
     725 CBC    17510433 : findObjectByDumpId(DumpId dumpId)
     726 ECB             : {
     727 GIC    17510433 :     if (dumpId <= 0 || dumpId >= allocedDumpIds)
     728 LBC           0 :         return NULL;            /* out of range? */
     729 CBC    17510433 :     return dumpIdMap[dumpId];
     730 ECB             : }
     731                 : 
     732                 : /*
     733                 :  * Find a DumpableObject by catalog ID
     734                 :  *
     735                 :  * Returns NULL for unknown ID
     736                 :  */
     737                 : DumpableObject *
     738 GIC     1545284 : findObjectByCatalogId(CatalogId catalogId)
     739                 : {
     740                 :     CatalogIdMapEntry *entry;
     741 ECB             : 
     742 CBC     1545284 :     if (catalogIdHash == NULL)
     743 UIC           0 :         return NULL;            /* no objects exist yet */
     744 ECB             : 
     745 CBC     1545284 :     entry = catalogid_lookup(catalogIdHash, catalogId);
     746 GIC     1545284 :     if (entry == NULL)
     747 CBC      410718 :         return NULL;
     748         1134566 :     return entry->dobj;
     749                 : }
     750 ECB             : 
     751                 : /*
     752                 :  * Build an array of pointers to all known dumpable objects
     753                 :  *
     754                 :  * This simply creates a modifiable copy of the internal map.
     755                 :  */
     756                 : void
     757 GIC         124 : getDumpableObjects(DumpableObject ***objs, int *numObjs)
     758                 : {
     759                 :     int         i,
     760                 :                 j;
     761                 : 
     762 GNC         124 :     *objs = pg_malloc_array(DumpableObject *, allocedDumpIds);
     763 CBC         124 :     j = 0;
     764 GIC      770048 :     for (i = 1; i < allocedDumpIds; i++)
     765                 :     {
     766          769924 :         if (dumpIdMap[i])
     767          535191 :             (*objs)[j++] = dumpIdMap[i];
     768                 :     }
     769             124 :     *numObjs = j;
     770 CBC         124 : }
     771                 : 
     772 ECB             : /*
     773                 :  * Add a dependency link to a DumpableObject
     774                 :  *
     775                 :  * Note: duplicate dependencies are currently not eliminated
     776                 :  */
     777                 : void
     778 GIC      762922 : addObjectDependency(DumpableObject *dobj, DumpId refId)
     779                 : {
     780          762922 :     if (dobj->nDeps >= dobj->allocDeps)
     781 ECB             :     {
     782 GIC      113381 :         if (dobj->allocDeps <= 0)
     783 ECB             :         {
     784 GBC      110466 :             dobj->allocDeps = 16;
     785 GNC      110466 :             dobj->dependencies = pg_malloc_array(DumpId, dobj->allocDeps);
     786                 :         }
     787                 :         else
     788                 :         {
     789 GIC        2915 :             dobj->allocDeps *= 2;
     790 GNC        2915 :             dobj->dependencies = pg_realloc_array(dobj->dependencies,
     791                 :                                                   DumpId, dobj->allocDeps);
     792 ECB             :         }
     793                 :     }
     794 GIC      762922 :     dobj->dependencies[dobj->nDeps++] = refId;
     795          762922 : }
     796 ECB             : 
     797 EUB             : /*
     798                 :  * Remove a dependency link from a DumpableObject
     799 ECB             :  *
     800                 :  * If there are multiple links, all are removed
     801                 :  */
     802                 : void
     803 GIC       19405 : removeObjectDependency(DumpableObject *dobj, DumpId refId)
     804                 : {
     805                 :     int         i;
     806           19405 :     int         j = 0;
     807                 : 
     808           90523 :     for (i = 0; i < dobj->nDeps; i++)
     809                 :     {
     810           71118 :         if (dobj->dependencies[i] != refId)
     811 CBC       50666 :             dobj->dependencies[j++] = dobj->dependencies[i];
     812                 :     }
     813 GIC       19405 :     dobj->nDeps = j;
     814           19405 : }
     815                 : 
     816 ECB             : 
     817                 : /*
     818                 :  * findTableByOid
     819                 :  *    finds the DumpableObject for the table with the given oid
     820                 :  *    returns NULL if not found
     821                 :  */
     822                 : TableInfo *
     823 CBC       52146 : findTableByOid(Oid oid)
     824 ECB             : {
     825                 :     CatalogId   catId;
     826                 :     DumpableObject *dobj;
     827                 : 
     828 GIC       52146 :     catId.tableoid = RelationRelationId;
     829           52146 :     catId.oid = oid;
     830           52146 :     dobj = findObjectByCatalogId(catId);
     831           52146 :     Assert(dobj == NULL || dobj->objType == DO_TABLE);
     832 CBC       52146 :     return (TableInfo *) dobj;
     833                 : }
     834 ECB             : 
     835                 : /*
     836                 :  * findIndexByOid
     837                 :  *    finds the DumpableObject for the index with the given oid
     838                 :  *    returns NULL if not found
     839                 :  */
     840                 : static IndxInfo *
     841 GIC         567 : findIndexByOid(Oid oid)
     842                 : {
     843 ECB             :     CatalogId   catId;
     844                 :     DumpableObject *dobj;
     845                 : 
     846 GIC         567 :     catId.tableoid = RelationRelationId;
     847             567 :     catId.oid = oid;
     848 CBC         567 :     dobj = findObjectByCatalogId(catId);
     849             567 :     Assert(dobj == NULL || dobj->objType == DO_INDEX);
     850 GIC         567 :     return (IndxInfo *) dobj;
     851                 : }
     852                 : 
     853                 : /*
     854                 :  * findTypeByOid
     855                 :  *    finds the DumpableObject for the type with the given oid
     856                 :  *    returns NULL if not found
     857 ECB             :  */
     858                 : TypeInfo *
     859 GIC       55269 : findTypeByOid(Oid oid)
     860 ECB             : {
     861                 :     CatalogId   catId;
     862                 :     DumpableObject *dobj;
     863                 : 
     864 CBC       55269 :     catId.tableoid = TypeRelationId;
     865           55269 :     catId.oid = oid;
     866 GIC       55269 :     dobj = findObjectByCatalogId(catId);
     867 CBC       55269 :     Assert(dobj == NULL ||
     868 ECB             :            dobj->objType == DO_TYPE || dobj->objType == DO_DUMMY_TYPE);
     869 GIC       55269 :     return (TypeInfo *) dobj;
     870                 : }
     871                 : 
     872                 : /*
     873                 :  * findFuncByOid
     874                 :  *    finds the DumpableObject for the function with the given oid
     875                 :  *    returns NULL if not found
     876                 :  */
     877 ECB             : FuncInfo *
     878 GIC         278 : findFuncByOid(Oid oid)
     879                 : {
     880                 :     CatalogId   catId;
     881                 :     DumpableObject *dobj;
     882 ECB             : 
     883 CBC         278 :     catId.tableoid = ProcedureRelationId;
     884             278 :     catId.oid = oid;
     885             278 :     dobj = findObjectByCatalogId(catId);
     886             278 :     Assert(dobj == NULL || dobj->objType == DO_FUNC);
     887 GIC         278 :     return (FuncInfo *) dobj;
     888                 : }
     889                 : 
     890                 : /*
     891                 :  * findOprByOid
     892                 :  *    finds the DumpableObject for the operator with the given oid
     893                 :  *    returns NULL if not found
     894                 :  */
     895 ECB             : OprInfo *
     896 GIC          25 : findOprByOid(Oid oid)
     897                 : {
     898                 :     CatalogId   catId;
     899                 :     DumpableObject *dobj;
     900 ECB             : 
     901 CBC          25 :     catId.tableoid = OperatorRelationId;
     902              25 :     catId.oid = oid;
     903              25 :     dobj = findObjectByCatalogId(catId);
     904              25 :     Assert(dobj == NULL || dobj->objType == DO_OPERATOR);
     905 GIC          25 :     return (OprInfo *) dobj;
     906                 : }
     907                 : 
     908                 : /*
     909                 :  * findCollationByOid
     910                 :  *    finds the DumpableObject for the collation with the given oid
     911                 :  *    returns NULL if not found
     912                 :  */
     913 ECB             : CollInfo *
     914 GIC          82 : findCollationByOid(Oid oid)
     915                 : {
     916                 :     CatalogId   catId;
     917                 :     DumpableObject *dobj;
     918 ECB             : 
     919 CBC          82 :     catId.tableoid = CollationRelationId;
     920              82 :     catId.oid = oid;
     921              82 :     dobj = findObjectByCatalogId(catId);
     922 GIC          82 :     Assert(dobj == NULL || dobj->objType == DO_COLLATION);
     923 CBC          82 :     return (CollInfo *) dobj;
     924                 : }
     925                 : 
     926                 : /*
     927                 :  * findNamespaceByOid
     928                 :  *    finds the DumpableObject for the namespace with the given oid
     929                 :  *    returns NULL if not found
     930                 :  */
     931                 : NamespaceInfo *
     932          446460 : findNamespaceByOid(Oid oid)
     933                 : {
     934                 :     CatalogId   catId;
     935                 :     DumpableObject *dobj;
     936                 : 
     937          446460 :     catId.tableoid = NamespaceRelationId;
     938          446460 :     catId.oid = oid;
     939          446460 :     dobj = findObjectByCatalogId(catId);
     940          446460 :     Assert(dobj == NULL || dobj->objType == DO_NAMESPACE);
     941          446460 :     return (NamespaceInfo *) dobj;
     942                 : }
     943                 : 
     944                 : /*
     945                 :  * findExtensionByOid
     946                 :  *    finds the DumpableObject for the extension with the given oid
     947                 :  *    returns NULL if not found
     948                 :  */
     949                 : ExtensionInfo *
     950             141 : findExtensionByOid(Oid oid)
     951                 : {
     952                 :     CatalogId   catId;
     953                 :     DumpableObject *dobj;
     954                 : 
     955             141 :     catId.tableoid = ExtensionRelationId;
     956             141 :     catId.oid = oid;
     957             141 :     dobj = findObjectByCatalogId(catId);
     958             141 :     Assert(dobj == NULL || dobj->objType == DO_EXTENSION);
     959             141 :     return (ExtensionInfo *) dobj;
     960                 : }
     961                 : 
     962                 : /*
     963                 :  * findPublicationByOid
     964                 :  *    finds the DumpableObject for the publication with the given oid
     965                 :  *    returns NULL if not found
     966                 :  */
     967                 : PublicationInfo *
     968             405 : findPublicationByOid(Oid oid)
     969                 : {
     970                 :     CatalogId   catId;
     971                 :     DumpableObject *dobj;
     972                 : 
     973             405 :     catId.tableoid = PublicationRelationId;
     974             405 :     catId.oid = oid;
     975             405 :     dobj = findObjectByCatalogId(catId);
     976             405 :     Assert(dobj == NULL || dobj->objType == DO_PUBLICATION);
     977             405 :     return (PublicationInfo *) dobj;
     978                 : }
     979                 : 
     980                 : 
     981                 : /*
     982                 :  * recordExtensionMembership
     983                 :  *    Record that the object identified by the given catalog ID
     984                 :  *    belongs to the given extension
     985                 :  */
     986 ECB             : void
     987 GIC         806 : recordExtensionMembership(CatalogId catId, ExtensionInfo *ext)
     988                 : {
     989                 :     CatalogIdMapEntry *entry;
     990                 :     bool        found;
     991 ECB             : 
     992                 :     /* CatalogId hash table must exist, if we have an ExtensionInfo */
     993 CBC         806 :     Assert(catalogIdHash != NULL);
     994 ECB             : 
     995                 :     /* Add reference to CatalogId hash */
     996 GIC         806 :     entry = catalogid_insert(catalogIdHash, catId, &found);
     997             806 :     if (!found)
     998                 :     {
     999             806 :         entry->dobj = NULL;
    1000             806 :         entry->ext = NULL;
    1001                 :     }
    1002             806 :     Assert(entry->ext == NULL);
    1003             806 :     entry->ext = ext;
    1004 CBC         806 : }
    1005                 : 
    1006                 : /*
    1007                 :  * findOwningExtension
    1008                 :  *    return owning extension for specified catalog ID, or NULL if none
    1009 ECB             :  */
    1010                 : ExtensionInfo *
    1011 CBC      445511 : findOwningExtension(CatalogId catalogId)
    1012 ECB             : {
    1013                 :     CatalogIdMapEntry *entry;
    1014                 : 
    1015 GIC      445511 :     if (catalogIdHash == NULL)
    1016 UIC           0 :         return NULL;            /* no objects exist yet */
    1017                 : 
    1018 GIC      445511 :     entry = catalogid_lookup(catalogIdHash, catalogId);
    1019          445511 :     if (entry == NULL)
    1020 UIC           0 :         return NULL;
    1021 GIC      445511 :     return entry->ext;
    1022 ECB             : }
    1023                 : 
    1024                 : 
    1025                 : /*
    1026                 :  * parseOidArray
    1027 EUB             :  *    parse a string of numbers delimited by spaces into a character array
    1028 ECB             :  *
    1029                 :  * Note: actually this is used for both Oids and potentially-signed
    1030                 :  * attribute numbers.  This should cause no trouble, but we could split
    1031                 :  * the function into two functions with different argument types if it does.
    1032                 :  */
    1033                 : 
    1034                 : void
    1035 GIC        4619 : parseOidArray(const char *str, Oid *array, int arraysize)
    1036                 : {
    1037                 :     int         j,
    1038                 :                 argNum;
    1039                 :     char        temp[100];
    1040                 :     char        s;
    1041                 : 
    1042 CBC        4619 :     argNum = 0;
    1043 GIC        4619 :     j = 0;
    1044                 :     for (;;)
    1045                 :     {
    1046           21735 :         s = *str++;
    1047           21735 :         if (s == ' ' || s == '\0')
    1048                 :         {
    1049 CBC        7366 :             if (j > 0)
    1050 ECB             :             {
    1051 GIC        7366 :                 if (argNum >= arraysize)
    1052 UIC           0 :                     pg_fatal("could not parse numeric array \"%s\": too many numbers", str);
    1053 CBC        7366 :                 temp[j] = '\0';
    1054            7366 :                 array[argNum++] = atooid(temp);
    1055 GIC        7366 :                 j = 0;
    1056 ECB             :             }
    1057 GIC        7366 :             if (s == '\0')
    1058 CBC        4619 :                 break;
    1059 EUB             :         }
    1060 ECB             :         else
    1061                 :         {
    1062 CBC       14369 :             if (!(isdigit((unsigned char) s) || s == '-') ||
    1063 GIC       14369 :                 j >= sizeof(temp) - 1)
    1064 LBC           0 :                 pg_fatal("could not parse numeric array \"%s\": invalid character in number", str);
    1065 CBC       14369 :             temp[j++] = s;
    1066                 :         }
    1067                 :     }
    1068                 : 
    1069            4619 :     while (argNum < arraysize)
    1070 LBC           0 :         array[argNum++] = InvalidOid;
    1071 GBC        4619 : }
    1072 ECB             : 
    1073                 : 
    1074                 : /*
    1075                 :  * strInArray:
    1076                 :  *    takes in a string and a string array and the number of elements in the
    1077 EUB             :  * string array.
    1078 ECB             :  *    returns the index if the string is somewhere in the array, -1 otherwise
    1079                 :  */
    1080                 : 
    1081                 : static int
    1082 GIC        3822 : strInArray(const char *pattern, char **arr, int arr_size)
    1083                 : {
    1084                 :     int         i;
    1085                 : 
    1086            7771 :     for (i = 0; i < arr_size; i++)
    1087                 :     {
    1088            7586 :         if (strcmp(pattern, arr[i]) == 0)
    1089 CBC        3637 :             return i;
    1090                 :     }
    1091 GIC         185 :     return -1;
    1092                 : }
        

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