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

Generated by: LCOV version 2.0-1