LCOV - code coverage report
Current view: top level - src/bin/pg_dump - common.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 381 396 96.2 %
Date: 2025-08-09 08:18:06 Functions: 28 28 100.0 %
Legend: Lines: hit not hit

          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-2025, 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         364 : 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         364 :     pg_log_info("reading extensions");
     113         364 :     extinfo = getExtensions(fout, &numExtensions);
     114             : 
     115         364 :     pg_log_info("identifying extension members");
     116         364 :     getExtensionMembership(fout, extinfo, numExtensions);
     117             : 
     118         364 :     pg_log_info("reading schemas");
     119         364 :     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         364 :     pg_log_info("reading user-defined tables");
     128         364 :     tblinfo = getTables(fout, &numTables);
     129             : 
     130         362 :     getOwnedSeqs(fout, tblinfo, numTables);
     131             : 
     132         362 :     pg_log_info("reading user-defined functions");
     133         362 :     getFuncs(fout);
     134             : 
     135             :     /* this must be after getTables and getFuncs */
     136         362 :     pg_log_info("reading user-defined types");
     137         362 :     getTypes(fout);
     138             : 
     139             :     /* this must be after getFuncs, too */
     140         362 :     pg_log_info("reading procedural languages");
     141         362 :     getProcLangs(fout);
     142             : 
     143         362 :     pg_log_info("reading user-defined aggregate functions");
     144         362 :     getAggregates(fout);
     145             : 
     146         362 :     pg_log_info("reading user-defined operators");
     147         362 :     getOperators(fout);
     148             : 
     149         362 :     pg_log_info("reading user-defined access methods");
     150         362 :     getAccessMethods(fout);
     151             : 
     152         362 :     pg_log_info("reading user-defined operator classes");
     153         362 :     getOpclasses(fout);
     154             : 
     155         362 :     pg_log_info("reading user-defined operator families");
     156         362 :     getOpfamilies(fout);
     157             : 
     158         362 :     pg_log_info("reading user-defined text search parsers");
     159         362 :     getTSParsers(fout);
     160             : 
     161         362 :     pg_log_info("reading user-defined text search templates");
     162         362 :     getTSTemplates(fout);
     163             : 
     164         362 :     pg_log_info("reading user-defined text search dictionaries");
     165         362 :     getTSDictionaries(fout);
     166             : 
     167         362 :     pg_log_info("reading user-defined text search configurations");
     168         362 :     getTSConfigurations(fout);
     169             : 
     170         362 :     pg_log_info("reading user-defined foreign-data wrappers");
     171         362 :     getForeignDataWrappers(fout);
     172             : 
     173         362 :     pg_log_info("reading user-defined foreign servers");
     174         362 :     getForeignServers(fout);
     175             : 
     176         362 :     pg_log_info("reading default privileges");
     177         362 :     getDefaultACLs(fout);
     178             : 
     179         362 :     pg_log_info("reading user-defined collations");
     180         362 :     getCollations(fout);
     181             : 
     182         362 :     pg_log_info("reading user-defined conversions");
     183         362 :     getConversions(fout);
     184             : 
     185         362 :     pg_log_info("reading type casts");
     186         362 :     getCasts(fout);
     187             : 
     188         362 :     pg_log_info("reading transforms");
     189         362 :     getTransforms(fout);
     190             : 
     191         362 :     pg_log_info("reading table inheritance information");
     192         362 :     inhinfo = getInherits(fout, &numInherits);
     193             : 
     194         362 :     pg_log_info("reading event triggers");
     195         362 :     getEventTriggers(fout);
     196             : 
     197             :     /* Identify extension configuration tables that should be dumped */
     198         362 :     pg_log_info("finding extension tables");
     199         362 :     processExtensionTables(fout, extinfo, numExtensions);
     200             : 
     201             :     /* Link tables to parents, mark parents of target tables interesting */
     202         362 :     pg_log_info("finding inheritance relationships");
     203         362 :     flagInhTables(fout, tblinfo, numTables, inhinfo, numInherits);
     204             : 
     205         362 :     pg_log_info("reading column info for interesting tables");
     206         362 :     getTableAttrs(fout, tblinfo, numTables);
     207             : 
     208         362 :     pg_log_info("flagging inherited columns in subtables");
     209         362 :     flagInhAttrs(fout, fout->dopt, tblinfo, numTables);
     210             : 
     211         362 :     pg_log_info("reading partitioning data");
     212         362 :     getPartitioningInfo(fout);
     213             : 
     214         362 :     pg_log_info("reading indexes");
     215         362 :     getIndexes(fout, tblinfo, numTables);
     216             : 
     217         362 :     pg_log_info("flagging indexes in partitioned tables");
     218         362 :     flagInhIndexes(fout, tblinfo, numTables);
     219             : 
     220         362 :     pg_log_info("reading extended statistics");
     221         362 :     getExtendedStatistics(fout);
     222             : 
     223         362 :     pg_log_info("reading constraints");
     224         362 :     getConstraints(fout, tblinfo, numTables);
     225             : 
     226         362 :     pg_log_info("reading triggers");
     227         362 :     getTriggers(fout, tblinfo, numTables);
     228             : 
     229         362 :     pg_log_info("reading rewrite rules");
     230         362 :     getRules(fout);
     231             : 
     232         362 :     pg_log_info("reading policies");
     233         362 :     getPolicies(fout, tblinfo, numTables);
     234             : 
     235         362 :     pg_log_info("reading publications");
     236         362 :     getPublications(fout);
     237             : 
     238         362 :     pg_log_info("reading publication membership of tables");
     239         362 :     getPublicationTables(fout, tblinfo, numTables);
     240             : 
     241         362 :     pg_log_info("reading publication membership of schemas");
     242         362 :     getPublicationNamespaces(fout);
     243             : 
     244         362 :     pg_log_info("reading subscriptions");
     245         362 :     getSubscriptions(fout);
     246             : 
     247         362 :     pg_log_info("reading subscription membership of tables");
     248         362 :     getSubscriptionTables(fout);
     249             : 
     250         362 :     free(inhinfo);              /* not needed any longer */
     251             : 
     252         362 :     *numTablesPtr = numTables;
     253         362 :     return tblinfo;
     254             : }
     255             : 
     256             : /* flagInhTables -
     257             :  *   Fill in parent link fields of tables for which we need that information,
     258             :  *   mark parents of target tables as interesting, and create
     259             :  *   TableAttachInfo objects for partitioned tables with appropriate
     260             :  *   dependency links.
     261             :  *
     262             :  * Note that only direct ancestors of targets are marked interesting.
     263             :  * This is sufficient; we don't much care whether they inherited their
     264             :  * attributes or not.
     265             :  *
     266             :  * modifies tblinfo
     267             :  */
     268             : static void
     269         362 : flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
     270             :               InhInfo *inhinfo, int numInherits)
     271             : {
     272         362 :     TableInfo  *child = NULL;
     273         362 :     TableInfo  *parent = NULL;
     274             :     int         i,
     275             :                 j;
     276             : 
     277             :     /*
     278             :      * Set up links from child tables to their parents.
     279             :      *
     280             :      * We used to attempt to skip this work for tables that are not to be
     281             :      * dumped; but the optimizable cases are rare in practice, and setting up
     282             :      * these links in bulk is cheaper than the old way.  (Note in particular
     283             :      * that it's very rare for a child to have more than one parent.)
     284             :      */
     285        7036 :     for (i = 0; i < numInherits; i++)
     286             :     {
     287             :         /*
     288             :          * Skip a hashtable lookup if it's same table as last time.  This is
     289             :          * unlikely for the child, but less so for the parent.  (Maybe we
     290             :          * should ask the backend for a sorted array to make it more likely?
     291             :          * Not clear the sorting effort would be repaid, though.)
     292             :          */
     293        6674 :         if (child == NULL ||
     294        5076 :             child->dobj.catId.oid != inhinfo[i].inhrelid)
     295             :         {
     296        6438 :             child = findTableByOid(inhinfo[i].inhrelid);
     297             : 
     298             :             /*
     299             :              * If we find no TableInfo, assume the pg_inherits entry is for a
     300             :              * partitioned index, which we don't need to track.
     301             :              */
     302        6438 :             if (child == NULL)
     303        1464 :                 continue;
     304             :         }
     305        5210 :         if (parent == NULL ||
     306        5062 :             parent->dobj.catId.oid != inhinfo[i].inhparent)
     307             :         {
     308        3122 :             parent = findTableByOid(inhinfo[i].inhparent);
     309        3122 :             if (parent == NULL)
     310           0 :                 pg_fatal("failed sanity check, parent OID %u of table \"%s\" (OID %u) not found",
     311             :                          inhinfo[i].inhparent,
     312             :                          child->dobj.name,
     313             :                          child->dobj.catId.oid);
     314             :         }
     315             :         /* Add this parent to the child's list of parents. */
     316        5210 :         if (child->numParents > 0)
     317         236 :             child->parents = pg_realloc_array(child->parents,
     318             :                                               TableInfo *,
     319             :                                               child->numParents + 1);
     320             :         else
     321        4974 :             child->parents = pg_malloc_array(TableInfo *, 1);
     322        5210 :         child->parents[child->numParents++] = parent;
     323             :     }
     324             : 
     325             :     /*
     326             :      * Now consider all child tables and mark parents interesting as needed.
     327             :      */
     328       96100 :     for (i = 0; i < numTables; i++)
     329             :     {
     330             :         /*
     331             :          * If needed, mark the parents as interesting for getTableAttrs and
     332             :          * getIndexes.  We only need this for direct parents of dumpable
     333             :          * tables.
     334             :          */
     335       95738 :         if (tblinfo[i].dobj.dump)
     336             :         {
     337       60528 :             int         numParents = tblinfo[i].numParents;
     338       60528 :             TableInfo **parents = tblinfo[i].parents;
     339             : 
     340       64442 :             for (j = 0; j < numParents; j++)
     341        3914 :                 parents[j]->interesting = true;
     342             :         }
     343             : 
     344             :         /* Create TableAttachInfo object if needed */
     345       95738 :         if ((tblinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
     346       14094 :             tblinfo[i].ispartition)
     347             :         {
     348             :             TableAttachInfo *attachinfo;
     349             : 
     350             :             /* With partitions there can only be one parent */
     351        2656 :             if (tblinfo[i].numParents != 1)
     352           0 :                 pg_fatal("invalid number of parents %d for table \"%s\"",
     353             :                          tblinfo[i].numParents,
     354             :                          tblinfo[i].dobj.name);
     355             : 
     356        2656 :             attachinfo = (TableAttachInfo *) palloc(sizeof(TableAttachInfo));
     357        2656 :             attachinfo->dobj.objType = DO_TABLE_ATTACH;
     358        2656 :             attachinfo->dobj.catId.tableoid = 0;
     359        2656 :             attachinfo->dobj.catId.oid = 0;
     360        2656 :             AssignDumpId(&attachinfo->dobj);
     361        2656 :             attachinfo->dobj.name = pg_strdup(tblinfo[i].dobj.name);
     362        2656 :             attachinfo->dobj.namespace = tblinfo[i].dobj.namespace;
     363        2656 :             attachinfo->parentTbl = tblinfo[i].parents[0];
     364        2656 :             attachinfo->partitionTbl = &tblinfo[i];
     365             : 
     366             :             /*
     367             :              * We must state the DO_TABLE_ATTACH object's dependencies
     368             :              * explicitly, since it will not match anything in pg_depend.
     369             :              *
     370             :              * Give it dependencies on both the partition table and the parent
     371             :              * table, so that it will not be executed till both of those
     372             :              * exist.  (There's no need to care what order those are created
     373             :              * in.)
     374             :              */
     375        2656 :             addObjectDependency(&attachinfo->dobj, tblinfo[i].dobj.dumpId);
     376        2656 :             addObjectDependency(&attachinfo->dobj, tblinfo[i].parents[0]->dobj.dumpId);
     377             :         }
     378             :     }
     379         362 : }
     380             : 
     381             : /*
     382             :  * flagInhIndexes -
     383             :  *   Create IndexAttachInfo objects for partitioned indexes, and add
     384             :  *   appropriate dependency links.
     385             :  */
     386             : static void
     387         362 : flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
     388             : {
     389             :     int         i,
     390             :                 j;
     391             : 
     392       96100 :     for (i = 0; i < numTables; i++)
     393             :     {
     394       95738 :         if (!tblinfo[i].ispartition || tblinfo[i].numParents == 0)
     395       92172 :             continue;
     396             : 
     397             :         Assert(tblinfo[i].numParents == 1);
     398             : 
     399        4852 :         for (j = 0; j < tblinfo[i].numIndexes; j++)
     400             :         {
     401        1286 :             IndxInfo   *index = &(tblinfo[i].indexes[j]);
     402             :             IndxInfo   *parentidx;
     403             :             IndexAttachInfo *attachinfo;
     404             : 
     405        1286 :             if (index->parentidx == 0)
     406         110 :                 continue;
     407             : 
     408        1176 :             parentidx = findIndexByOid(index->parentidx);
     409        1176 :             if (parentidx == NULL)
     410           0 :                 continue;
     411             : 
     412        1176 :             attachinfo = pg_malloc_object(IndexAttachInfo);
     413             : 
     414        1176 :             attachinfo->dobj.objType = DO_INDEX_ATTACH;
     415        1176 :             attachinfo->dobj.catId.tableoid = 0;
     416        1176 :             attachinfo->dobj.catId.oid = 0;
     417        1176 :             AssignDumpId(&attachinfo->dobj);
     418        1176 :             attachinfo->dobj.name = pg_strdup(index->dobj.name);
     419        1176 :             attachinfo->dobj.namespace = index->indextable->dobj.namespace;
     420        1176 :             attachinfo->parentIdx = parentidx;
     421        1176 :             attachinfo->partitionIdx = index;
     422             : 
     423             :             /*
     424             :              * We must state the DO_INDEX_ATTACH object's dependencies
     425             :              * explicitly, since it will not match anything in pg_depend.
     426             :              *
     427             :              * Give it dependencies on both the partition index and the parent
     428             :              * index, so that it will not be executed till both of those
     429             :              * exist.  (There's no need to care what order those are created
     430             :              * in.)
     431             :              *
     432             :              * In addition, give it dependencies on the indexes' underlying
     433             :              * tables.  This does nothing of great value so far as serial
     434             :              * restore ordering goes, but it ensures that a parallel restore
     435             :              * will not try to run the ATTACH concurrently with other
     436             :              * operations on those tables.
     437             :              */
     438        1176 :             addObjectDependency(&attachinfo->dobj, index->dobj.dumpId);
     439        1176 :             addObjectDependency(&attachinfo->dobj, parentidx->dobj.dumpId);
     440        1176 :             addObjectDependency(&attachinfo->dobj,
     441        1176 :                                 index->indextable->dobj.dumpId);
     442        1176 :             addObjectDependency(&attachinfo->dobj,
     443        1176 :                                 parentidx->indextable->dobj.dumpId);
     444             : 
     445             :             /* keep track of the list of partitions in the parent index */
     446        1176 :             simple_ptr_list_append(&parentidx->partattaches, &attachinfo->dobj);
     447             :         }
     448             :     }
     449         362 : }
     450             : 
     451             : /* flagInhAttrs -
     452             :  *   for each dumpable table in tblinfo, flag its inherited attributes
     453             :  *
     454             :  * What we need to do here is:
     455             :  *
     456             :  * - Detect child columns that inherit NOT NULL bits from their parents, so
     457             :  *   that we needn't specify that again for the child.  For versions 18 and
     458             :  *   up, this is needed when the parent is NOT VALID and the child isn't.
     459             :  *
     460             :  * - Detect child columns that have DEFAULT NULL when their parents had some
     461             :  *   non-null default.  In this case, we make up a dummy AttrDefInfo object so
     462             :  *   that we'll correctly emit the necessary DEFAULT NULL clause; otherwise
     463             :  *   the backend will apply an inherited default to the column.
     464             :  *
     465             :  * - Detect child columns that have a generation expression and all their
     466             :  *   parents also have the same generation expression, and if so suppress the
     467             :  *   child's expression.  The child will inherit the generation expression
     468             :  *   automatically, so there's no need to dump it.  This improves the dump's
     469             :  *   compatibility with pre-v16 servers, which didn't allow the child's
     470             :  *   expression to be given explicitly.  Exceptions: If it's a partition or
     471             :  *   we are in binary upgrade mode, we dump such expressions anyway because
     472             :  *   in those cases inherited tables are recreated standalone first and then
     473             :  *   reattached to the parent.  (See also the logic in dumpTableSchema().)
     474             :  *
     475             :  * modifies tblinfo
     476             :  */
     477             : static void
     478         362 : flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo, int numTables)
     479             : {
     480             :     int         i,
     481             :                 j,
     482             :                 k;
     483             : 
     484             :     /*
     485             :      * We scan the tables in OID order, since that's how tblinfo[] is sorted.
     486             :      * Hence we will typically visit parents before their children --- but
     487             :      * that is *not* guaranteed.  Thus this loop must be careful that it does
     488             :      * not alter table properties in a way that could change decisions made at
     489             :      * child tables during other iterations.
     490             :      */
     491       96100 :     for (i = 0; i < numTables; i++)
     492             :     {
     493       95738 :         TableInfo  *tbinfo = &(tblinfo[i]);
     494             :         int         numParents;
     495             :         TableInfo **parents;
     496             : 
     497             :         /* Some kinds never have parents */
     498       95738 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
     499       94444 :             tbinfo->relkind == RELKIND_VIEW ||
     500       40782 :             tbinfo->relkind == RELKIND_MATVIEW)
     501       56028 :             continue;
     502             : 
     503             :         /* Don't bother computing anything for non-target tables, either */
     504       39710 :         if (!tbinfo->dobj.dump)
     505        7904 :             continue;
     506             : 
     507       31806 :         numParents = tbinfo->numParents;
     508       31806 :         parents = tbinfo->parents;
     509             : 
     510       31806 :         if (numParents == 0)
     511       28074 :             continue;           /* nothing to see here, move along */
     512             : 
     513             :         /* For each column, search for matching column names in parent(s) */
     514       13156 :         for (j = 0; j < tbinfo->numatts; j++)
     515             :         {
     516             :             bool        foundNotNull;   /* Attr was NOT NULL in a parent */
     517             :             bool        foundDefault;   /* Found a default in a parent */
     518             :             bool        foundSameGenerated; /* Found matching GENERATED */
     519             :             bool        foundDiffGenerated; /* Found non-matching GENERATED */
     520        9424 :             bool        allNotNullsInvalid = true;  /* is NOT NULL NOT VALID
     521             :                                                      * on all parents? */
     522             : 
     523             :             /* no point in examining dropped columns */
     524        9424 :             if (tbinfo->attisdropped[j])
     525         610 :                 continue;
     526             : 
     527        8814 :             foundNotNull = false;
     528        8814 :             foundDefault = false;
     529        8814 :             foundSameGenerated = false;
     530        8814 :             foundDiffGenerated = false;
     531       18060 :             for (k = 0; k < numParents; k++)
     532             :             {
     533        9246 :                 TableInfo  *parent = parents[k];
     534             :                 int         inhAttrInd;
     535             : 
     536        9246 :                 inhAttrInd = strInArray(tbinfo->attnames[j],
     537             :                                         parent->attnames,
     538             :                                         parent->numatts);
     539        9246 :                 if (inhAttrInd >= 0)
     540             :                 {
     541        8766 :                     AttrDefInfo *parentDef = parent->attrdefs[inhAttrInd];
     542             : 
     543             :                     /*
     544             :                      * Account for each parent having a not-null constraint.
     545             :                      * In versions 18 and later, we don't need this (and those
     546             :                      * didn't have NO INHERIT.)
     547             :                      */
     548        8766 :                     if (fout->remoteVersion < 180000 &&
     549           0 :                         parent->notnull_constrs[inhAttrInd] != NULL)
     550           0 :                         foundNotNull = true;
     551             : 
     552             :                     /*
     553             :                      * Keep track of whether all the parents that have a
     554             :                      * not-null constraint on this column have it as NOT
     555             :                      * VALID; if they all are, arrange to have it printed for
     556             :                      * this column.  If at least one parent has it as valid,
     557             :                      * there's no need.
     558             :                      */
     559        8766 :                     if (fout->remoteVersion >= 180000 &&
     560        8766 :                         parent->notnull_constrs[inhAttrInd] &&
     561        1800 :                         !parent->notnull_invalid[inhAttrInd])
     562        1800 :                         allNotNullsInvalid = false;
     563             : 
     564       18560 :                     foundDefault |= (parentDef != NULL &&
     565        9694 :                                      strcmp(parentDef->adef_expr, "NULL") != 0 &&
     566         928 :                                      !parent->attgenerated[inhAttrInd]);
     567        8766 :                     if (parent->attgenerated[inhAttrInd])
     568             :                     {
     569             :                         /* these pointer nullness checks are just paranoia */
     570         568 :                         if (parentDef != NULL &&
     571         520 :                             tbinfo->attrdefs[j] != NULL &&
     572         520 :                             strcmp(parentDef->adef_expr,
     573         520 :                                    tbinfo->attrdefs[j]->adef_expr) == 0)
     574         460 :                             foundSameGenerated = true;
     575             :                         else
     576         108 :                             foundDiffGenerated = true;
     577             :                     }
     578             :                 }
     579             :             }
     580             : 
     581             :             /*
     582             :              * In versions < 18, for lack of a better system, we arbitrarily
     583             :              * decide that a not-null constraint is not locally defined if at
     584             :              * least one of the parents has it.
     585             :              */
     586        8814 :             if (fout->remoteVersion < 180000 && foundNotNull)
     587           0 :                 tbinfo->notnull_islocal[j] = false;
     588             : 
     589             :             /*
     590             :              * For versions >18, we must print the not-null constraint locally
     591             :              * for this table even if it isn't really locally defined, but is
     592             :              * valid for the child and no parent has it as valid.
     593             :              */
     594        8814 :             if (fout->remoteVersion >= 180000 && allNotNullsInvalid)
     595        7024 :                 tbinfo->notnull_islocal[j] = true;
     596             : 
     597             :             /*
     598             :              * Manufacture a DEFAULT NULL clause if necessary.  This breaks
     599             :              * the advice given above to avoid changing state that might get
     600             :              * inspected in other loop iterations.  We prevent trouble by
     601             :              * having the foundDefault test above check whether adef_expr is
     602             :              * "NULL", so that it will reach the same conclusion before or
     603             :              * after this is done.
     604             :              */
     605        8814 :             if (foundDefault && tbinfo->attrdefs[j] == NULL)
     606             :             {
     607             :                 AttrDefInfo *attrDef;
     608             : 
     609          80 :                 attrDef = pg_malloc_object(AttrDefInfo);
     610          80 :                 attrDef->dobj.objType = DO_ATTRDEF;
     611          80 :                 attrDef->dobj.catId.tableoid = 0;
     612          80 :                 attrDef->dobj.catId.oid = 0;
     613          80 :                 AssignDumpId(&attrDef->dobj);
     614          80 :                 attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
     615          80 :                 attrDef->dobj.namespace = tbinfo->dobj.namespace;
     616          80 :                 attrDef->dobj.dump = tbinfo->dobj.dump;
     617             : 
     618          80 :                 attrDef->adtable = tbinfo;
     619          80 :                 attrDef->adnum = j + 1;
     620          80 :                 attrDef->adef_expr = pg_strdup("NULL");
     621             : 
     622             :                 /* Will column be dumped explicitly? */
     623          80 :                 if (shouldPrintColumn(dopt, tbinfo, j))
     624             :                 {
     625          80 :                     attrDef->separate = false;
     626             :                     /* No dependency needed: NULL cannot have dependencies */
     627             :                 }
     628             :                 else
     629             :                 {
     630             :                     /* column will be suppressed, print default separately */
     631           0 :                     attrDef->separate = true;
     632             :                     /* ensure it comes out after the table */
     633           0 :                     addObjectDependency(&attrDef->dobj,
     634             :                                         tbinfo->dobj.dumpId);
     635             :                 }
     636             : 
     637          80 :                 tbinfo->attrdefs[j] = attrDef;
     638             :             }
     639             : 
     640             :             /* No need to dump generation expression if it's inheritable */
     641        8814 :             if (foundSameGenerated && !foundDiffGenerated &&
     642         460 :                 !tbinfo->ispartition && !dopt->binary_upgrade)
     643         336 :                 tbinfo->attrdefs[j]->dobj.dump = DUMP_COMPONENT_NONE;
     644             :         }
     645             :     }
     646         362 : }
     647             : 
     648             : /*
     649             :  * AssignDumpId
     650             :  *      Given a newly-created dumpable object, assign a dump ID,
     651             :  *      and enter the object into the lookup tables.
     652             :  *
     653             :  * The caller is expected to have filled in objType and catId,
     654             :  * but not any of the other standard fields of a DumpableObject.
     655             :  */
     656             : void
     657     1347012 : AssignDumpId(DumpableObject *dobj)
     658             : {
     659     1347012 :     dobj->dumpId = ++lastDumpId;
     660     1347012 :     dobj->name = NULL;           /* must be set later */
     661     1347012 :     dobj->namespace = NULL;      /* may be set later */
     662     1347012 :     dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
     663     1347012 :     dobj->dump_contains = DUMP_COMPONENT_ALL;    /* default assumption */
     664             :     /* All objects have definitions; we may set more components bits later */
     665     1347012 :     dobj->components = DUMP_COMPONENT_DEFINITION;
     666     1347012 :     dobj->ext_member = false;    /* default assumption */
     667     1347012 :     dobj->depends_on_ext = false;    /* default assumption */
     668     1347012 :     dobj->dependencies = NULL;
     669     1347012 :     dobj->nDeps = 0;
     670     1347012 :     dobj->allocDeps = 0;
     671             : 
     672             :     /* Add object to dumpIdMap[], enlarging that array if need be */
     673     1348852 :     while (dobj->dumpId >= allocedDumpIds)
     674             :     {
     675             :         int         newAlloc;
     676             : 
     677        1840 :         if (allocedDumpIds <= 0)
     678             :         {
     679         364 :             newAlloc = 256;
     680         364 :             dumpIdMap = pg_malloc_array(DumpableObject *, newAlloc);
     681             :         }
     682             :         else
     683             :         {
     684        1476 :             newAlloc = allocedDumpIds * 2;
     685        1476 :             dumpIdMap = pg_realloc_array(dumpIdMap, DumpableObject *, newAlloc);
     686             :         }
     687        1840 :         memset(dumpIdMap + allocedDumpIds, 0,
     688        1840 :                (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
     689        1840 :         allocedDumpIds = newAlloc;
     690             :     }
     691     1347012 :     dumpIdMap[dobj->dumpId] = dobj;
     692             : 
     693             :     /* If it has a valid CatalogId, enter it into the hash table */
     694     1347012 :     if (OidIsValid(dobj->catId.tableoid))
     695             :     {
     696             :         CatalogIdMapEntry *entry;
     697             :         bool        found;
     698             : 
     699             :         /* Initialize CatalogId hash table if not done yet */
     700     1309062 :         if (catalogIdHash == NULL)
     701         364 :             catalogIdHash = catalogid_create(CATALOGIDHASH_INITIAL_SIZE, NULL);
     702             : 
     703     1309062 :         entry = catalogid_insert(catalogIdHash, dobj->catId, &found);
     704     1309062 :         if (!found)
     705             :         {
     706     1307284 :             entry->dobj = NULL;
     707     1307284 :             entry->ext = NULL;
     708             :         }
     709             :         Assert(entry->dobj == NULL);
     710     1309062 :         entry->dobj = dobj;
     711             :     }
     712     1347012 : }
     713             : 
     714             : /*
     715             :  * recordAdditionalCatalogID
     716             :  *    Record an additional catalog ID for the given DumpableObject
     717             :  */
     718             : void
     719          20 : recordAdditionalCatalogID(CatalogId catId, DumpableObject *dobj)
     720             : {
     721             :     CatalogIdMapEntry *entry;
     722             :     bool        found;
     723             : 
     724             :     /* CatalogId hash table must exist, if we have a DumpableObject */
     725             :     Assert(catalogIdHash != NULL);
     726             : 
     727             :     /* Add reference to CatalogId hash */
     728          20 :     entry = catalogid_insert(catalogIdHash, catId, &found);
     729          20 :     if (!found)
     730             :     {
     731          20 :         entry->dobj = NULL;
     732          20 :         entry->ext = NULL;
     733             :     }
     734             :     Assert(entry->dobj == NULL);
     735          20 :     entry->dobj = dobj;
     736          20 : }
     737             : 
     738             : /*
     739             :  * Assign a DumpId that's not tied to a DumpableObject.
     740             :  *
     741             :  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
     742             :  * participate in the sorting logic.
     743             :  */
     744             : DumpId
     745       26576 : createDumpId(void)
     746             : {
     747       26576 :     return ++lastDumpId;
     748             : }
     749             : 
     750             : /*
     751             :  * Return the largest DumpId so far assigned
     752             :  */
     753             : DumpId
     754        2534 : getMaxDumpId(void)
     755             : {
     756        2534 :     return lastDumpId;
     757             : }
     758             : 
     759             : /*
     760             :  * Find a DumpableObject by dump ID
     761             :  *
     762             :  * Returns NULL for invalid ID
     763             :  */
     764             : DumpableObject *
     765    43797266 : findObjectByDumpId(DumpId dumpId)
     766             : {
     767    43797266 :     if (dumpId <= 0 || dumpId >= allocedDumpIds)
     768           0 :         return NULL;            /* out of range? */
     769    43797266 :     return dumpIdMap[dumpId];
     770             : }
     771             : 
     772             : /*
     773             :  * Find a DumpableObject by catalog ID
     774             :  *
     775             :  * Returns NULL for unknown ID
     776             :  */
     777             : DumpableObject *
     778     7285470 : findObjectByCatalogId(CatalogId catalogId)
     779             : {
     780             :     CatalogIdMapEntry *entry;
     781             : 
     782     7285470 :     if (catalogIdHash == NULL)
     783           0 :         return NULL;            /* no objects exist yet */
     784             : 
     785     7285470 :     entry = catalogid_lookup(catalogIdHash, catalogId);
     786     7285470 :     if (entry == NULL)
     787     1309328 :         return NULL;
     788     5976142 :     return entry->dobj;
     789             : }
     790             : 
     791             : /*
     792             :  * Build an array of pointers to all known dumpable objects
     793             :  *
     794             :  * This simply creates a modifiable copy of the internal map.
     795             :  */
     796             : void
     797         376 : getDumpableObjects(DumpableObject ***objs, int *numObjs)
     798             : {
     799             :     int         i,
     800             :                 j;
     801             : 
     802         376 :     *objs = pg_malloc_array(DumpableObject *, allocedDumpIds);
     803         376 :     j = 0;
     804     1687552 :     for (i = 1; i < allocedDumpIds; i++)
     805             :     {
     806     1687176 :         if (dumpIdMap[i])
     807     1397880 :             (*objs)[j++] = dumpIdMap[i];
     808             :     }
     809         376 :     *numObjs = j;
     810         376 : }
     811             : 
     812             : /*
     813             :  * Add a dependency link to a DumpableObject
     814             :  *
     815             :  * Note: duplicate dependencies are currently not eliminated
     816             :  */
     817             : void
     818     2122728 : addObjectDependency(DumpableObject *dobj, DumpId refId)
     819             : {
     820     2122728 :     if (dobj->nDeps >= dobj->allocDeps)
     821             :     {
     822      360916 :         if (dobj->allocDeps <= 0)
     823             :         {
     824      343006 :             dobj->allocDeps = 16;
     825      343006 :             dobj->dependencies = pg_malloc_array(DumpId, dobj->allocDeps);
     826             :         }
     827             :         else
     828             :         {
     829       17910 :             dobj->allocDeps *= 2;
     830       17910 :             dobj->dependencies = pg_realloc_array(dobj->dependencies,
     831             :                                                   DumpId, dobj->allocDeps);
     832             :         }
     833             :     }
     834     2122728 :     dobj->dependencies[dobj->nDeps++] = refId;
     835     2122728 : }
     836             : 
     837             : /*
     838             :  * Remove a dependency link from a DumpableObject
     839             :  *
     840             :  * If there are multiple links, all are removed
     841             :  */
     842             : void
     843       60864 : removeObjectDependency(DumpableObject *dobj, DumpId refId)
     844             : {
     845             :     int         i;
     846       60864 :     int         j = 0;
     847             : 
     848     1437642 :     for (i = 0; i < dobj->nDeps; i++)
     849             :     {
     850     1376778 :         if (dobj->dependencies[i] != refId)
     851     1313020 :             dobj->dependencies[j++] = dobj->dependencies[i];
     852             :     }
     853       60864 :     dobj->nDeps = j;
     854       60864 : }
     855             : 
     856             : 
     857             : /*
     858             :  * findTableByOid
     859             :  *    finds the DumpableObject for the table with the given oid
     860             :  *    returns NULL if not found
     861             :  */
     862             : TableInfo *
     863      164034 : findTableByOid(Oid oid)
     864             : {
     865             :     CatalogId   catId;
     866             :     DumpableObject *dobj;
     867             : 
     868      164034 :     catId.tableoid = RelationRelationId;
     869      164034 :     catId.oid = oid;
     870      164034 :     dobj = findObjectByCatalogId(catId);
     871             :     Assert(dobj == NULL || dobj->objType == DO_TABLE);
     872      164034 :     return (TableInfo *) dobj;
     873             : }
     874             : 
     875             : /*
     876             :  * findIndexByOid
     877             :  *    finds the DumpableObject for the index with the given oid
     878             :  *    returns NULL if not found
     879             :  */
     880             : static IndxInfo *
     881        1176 : findIndexByOid(Oid oid)
     882             : {
     883             :     CatalogId   catId;
     884             :     DumpableObject *dobj;
     885             : 
     886        1176 :     catId.tableoid = RelationRelationId;
     887        1176 :     catId.oid = oid;
     888        1176 :     dobj = findObjectByCatalogId(catId);
     889             :     Assert(dobj == NULL || dobj->objType == DO_INDEX);
     890        1176 :     return (IndxInfo *) dobj;
     891             : }
     892             : 
     893             : /*
     894             :  * findTypeByOid
     895             :  *    finds the DumpableObject for the type with the given oid
     896             :  *    returns NULL if not found
     897             :  */
     898             : TypeInfo *
     899     2773696 : findTypeByOid(Oid oid)
     900             : {
     901             :     CatalogId   catId;
     902             :     DumpableObject *dobj;
     903             : 
     904     2773696 :     catId.tableoid = TypeRelationId;
     905     2773696 :     catId.oid = oid;
     906     2773696 :     dobj = findObjectByCatalogId(catId);
     907             :     Assert(dobj == NULL ||
     908             :            dobj->objType == DO_TYPE || dobj->objType == DO_DUMMY_TYPE);
     909     2773696 :     return (TypeInfo *) dobj;
     910             : }
     911             : 
     912             : /*
     913             :  * findFuncByOid
     914             :  *    finds the DumpableObject for the function with the given oid
     915             :  *    returns NULL if not found
     916             :  */
     917             : FuncInfo *
     918         548 : findFuncByOid(Oid oid)
     919             : {
     920             :     CatalogId   catId;
     921             :     DumpableObject *dobj;
     922             : 
     923         548 :     catId.tableoid = ProcedureRelationId;
     924         548 :     catId.oid = oid;
     925         548 :     dobj = findObjectByCatalogId(catId);
     926             :     Assert(dobj == NULL || dobj->objType == DO_FUNC);
     927         548 :     return (FuncInfo *) dobj;
     928             : }
     929             : 
     930             : /*
     931             :  * findOprByOid
     932             :  *    finds the DumpableObject for the operator with the given oid
     933             :  *    returns NULL if not found
     934             :  */
     935             : OprInfo *
     936        5648 : findOprByOid(Oid oid)
     937             : {
     938             :     CatalogId   catId;
     939             :     DumpableObject *dobj;
     940             : 
     941        5648 :     catId.tableoid = OperatorRelationId;
     942        5648 :     catId.oid = oid;
     943        5648 :     dobj = findObjectByCatalogId(catId);
     944             :     Assert(dobj == NULL || dobj->objType == DO_OPERATOR);
     945        5648 :     return (OprInfo *) dobj;
     946             : }
     947             : 
     948             : /*
     949             :  * findAccessMethodByOid
     950             :  *    finds the DumpableObject for the access method with the given oid
     951             :  *    returns NULL if not found
     952             :  */
     953             : AccessMethodInfo *
     954       99592 : findAccessMethodByOid(Oid oid)
     955             : {
     956             :     CatalogId   catId;
     957             :     DumpableObject *dobj;
     958             : 
     959       99592 :     catId.tableoid = AccessMethodRelationId;
     960       99592 :     catId.oid = oid;
     961       99592 :     dobj = findObjectByCatalogId(catId);
     962             :     Assert(dobj == NULL || dobj->objType == DO_ACCESS_METHOD);
     963       99592 :     return (AccessMethodInfo *) dobj;
     964             : }
     965             : 
     966             : /*
     967             :  * findCollationByOid
     968             :  *    finds the DumpableObject for the collation with the given oid
     969             :  *    returns NULL if not found
     970             :  */
     971             : CollInfo *
     972         544 : findCollationByOid(Oid oid)
     973             : {
     974             :     CatalogId   catId;
     975             :     DumpableObject *dobj;
     976             : 
     977         544 :     catId.tableoid = CollationRelationId;
     978         544 :     catId.oid = oid;
     979         544 :     dobj = findObjectByCatalogId(catId);
     980             :     Assert(dobj == NULL || dobj->objType == DO_COLLATION);
     981         544 :     return (CollInfo *) dobj;
     982             : }
     983             : 
     984             : /*
     985             :  * findNamespaceByOid
     986             :  *    finds the DumpableObject for the namespace with the given oid
     987             :  *    returns NULL if not found
     988             :  */
     989             : NamespaceInfo *
     990     1143902 : findNamespaceByOid(Oid oid)
     991             : {
     992             :     CatalogId   catId;
     993             :     DumpableObject *dobj;
     994             : 
     995     1143902 :     catId.tableoid = NamespaceRelationId;
     996     1143902 :     catId.oid = oid;
     997     1143902 :     dobj = findObjectByCatalogId(catId);
     998             :     Assert(dobj == NULL || dobj->objType == DO_NAMESPACE);
     999     1143902 :     return (NamespaceInfo *) dobj;
    1000             : }
    1001             : 
    1002             : /*
    1003             :  * findExtensionByOid
    1004             :  *    finds the DumpableObject for the extension with the given oid
    1005             :  *    returns NULL if not found
    1006             :  */
    1007             : ExtensionInfo *
    1008         414 : findExtensionByOid(Oid oid)
    1009             : {
    1010             :     CatalogId   catId;
    1011             :     DumpableObject *dobj;
    1012             : 
    1013         414 :     catId.tableoid = ExtensionRelationId;
    1014         414 :     catId.oid = oid;
    1015         414 :     dobj = findObjectByCatalogId(catId);
    1016             :     Assert(dobj == NULL || dobj->objType == DO_EXTENSION);
    1017         414 :     return (ExtensionInfo *) dobj;
    1018             : }
    1019             : 
    1020             : /*
    1021             :  * findPublicationByOid
    1022             :  *    finds the DumpableObject for the publication with the given oid
    1023             :  *    returns NULL if not found
    1024             :  */
    1025             : PublicationInfo *
    1026        1004 : findPublicationByOid(Oid oid)
    1027             : {
    1028             :     CatalogId   catId;
    1029             :     DumpableObject *dobj;
    1030             : 
    1031        1004 :     catId.tableoid = PublicationRelationId;
    1032        1004 :     catId.oid = oid;
    1033        1004 :     dobj = findObjectByCatalogId(catId);
    1034             :     Assert(dobj == NULL || dobj->objType == DO_PUBLICATION);
    1035        1004 :     return (PublicationInfo *) dobj;
    1036             : }
    1037             : 
    1038             : /*
    1039             :  * findSubscriptionByOid
    1040             :  *    finds the DumpableObject for the subscription with the given oid
    1041             :  *    returns NULL if not found
    1042             :  */
    1043             : SubscriptionInfo *
    1044           4 : findSubscriptionByOid(Oid oid)
    1045             : {
    1046             :     CatalogId   catId;
    1047             :     DumpableObject *dobj;
    1048             : 
    1049           4 :     catId.tableoid = SubscriptionRelationId;
    1050           4 :     catId.oid = oid;
    1051           4 :     dobj = findObjectByCatalogId(catId);
    1052             :     Assert(dobj == NULL || dobj->objType == DO_SUBSCRIPTION);
    1053           4 :     return (SubscriptionInfo *) dobj;
    1054             : }
    1055             : 
    1056             : 
    1057             : /*
    1058             :  * recordExtensionMembership
    1059             :  *    Record that the object identified by the given catalog ID
    1060             :  *    belongs to the given extension
    1061             :  */
    1062             : void
    1063        2656 : recordExtensionMembership(CatalogId catId, ExtensionInfo *ext)
    1064             : {
    1065             :     CatalogIdMapEntry *entry;
    1066             :     bool        found;
    1067             : 
    1068             :     /* CatalogId hash table must exist, if we have an ExtensionInfo */
    1069             :     Assert(catalogIdHash != NULL);
    1070             : 
    1071             :     /* Add reference to CatalogId hash */
    1072        2656 :     entry = catalogid_insert(catalogIdHash, catId, &found);
    1073        2656 :     if (!found)
    1074             :     {
    1075        2656 :         entry->dobj = NULL;
    1076        2656 :         entry->ext = NULL;
    1077             :     }
    1078             :     Assert(entry->ext == NULL);
    1079        2656 :     entry->ext = ext;
    1080        2656 : }
    1081             : 
    1082             : /*
    1083             :  * findOwningExtension
    1084             :  *    return owning extension for specified catalog ID, or NULL if none
    1085             :  */
    1086             : ExtensionInfo *
    1087     1143066 : findOwningExtension(CatalogId catalogId)
    1088             : {
    1089             :     CatalogIdMapEntry *entry;
    1090             : 
    1091     1143066 :     if (catalogIdHash == NULL)
    1092           0 :         return NULL;            /* no objects exist yet */
    1093             : 
    1094     1143066 :     entry = catalogid_lookup(catalogIdHash, catalogId);
    1095     1143066 :     if (entry == NULL)
    1096           0 :         return NULL;
    1097     1143066 :     return entry->ext;
    1098             : }
    1099             : 
    1100             : 
    1101             : /*
    1102             :  * parseOidArray
    1103             :  *    parse a string of numbers delimited by spaces into a character array
    1104             :  *
    1105             :  * Note: actually this is used for both Oids and potentially-signed
    1106             :  * attribute numbers.  This should cause no trouble, but we could split
    1107             :  * the function into two functions with different argument types if it does.
    1108             :  */
    1109             : 
    1110             : void
    1111       13274 : parseOidArray(const char *str, Oid *array, int arraysize)
    1112             : {
    1113             :     int         j,
    1114             :                 argNum;
    1115             :     char        temp[100];
    1116             :     char        s;
    1117             : 
    1118       13274 :     argNum = 0;
    1119       13274 :     j = 0;
    1120             :     for (;;)
    1121             :     {
    1122       62474 :         s = *str++;
    1123       62474 :         if (s == ' ' || s == '\0')
    1124             :         {
    1125       21286 :             if (j > 0)
    1126             :             {
    1127       21286 :                 if (argNum >= arraysize)
    1128           0 :                     pg_fatal("could not parse numeric array \"%s\": too many numbers", str);
    1129       21286 :                 temp[j] = '\0';
    1130       21286 :                 array[argNum++] = atooid(temp);
    1131       21286 :                 j = 0;
    1132             :             }
    1133       21286 :             if (s == '\0')
    1134       13274 :                 break;
    1135             :         }
    1136             :         else
    1137             :         {
    1138       41188 :             if (!(isdigit((unsigned char) s) || s == '-') ||
    1139       41188 :                 j >= sizeof(temp) - 1)
    1140           0 :                 pg_fatal("could not parse numeric array \"%s\": invalid character in number", str);
    1141       41188 :             temp[j++] = s;
    1142             :         }
    1143             :     }
    1144             : 
    1145       13274 :     while (argNum < arraysize)
    1146           0 :         array[argNum++] = InvalidOid;
    1147       13274 : }
    1148             : 
    1149             : 
    1150             : /*
    1151             :  * strInArray:
    1152             :  *    takes in a string and a string array and the number of elements in the
    1153             :  * string array.
    1154             :  *    returns the index if the string is somewhere in the array, -1 otherwise
    1155             :  */
    1156             : 
    1157             : static int
    1158        9246 : strInArray(const char *pattern, char **arr, int arr_size)
    1159             : {
    1160             :     int         i;
    1161             : 
    1162       18310 :     for (i = 0; i < arr_size; i++)
    1163             :     {
    1164       17830 :         if (strcmp(pattern, arr[i]) == 0)
    1165        8766 :             return i;
    1166             :     }
    1167         480 :     return -1;
    1168             : }

Generated by: LCOV version 1.16