LCOV - code coverage report
Current view: top level - src/bin/pg_dump - common.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 517 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 28 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-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            0 : getSchemaData(Archive *fout, int *numTablesPtr)
      99              : {
     100            0 :         TableInfo  *tblinfo;
     101            0 :         ExtensionInfo *extinfo;
     102            0 :         InhInfo    *inhinfo;
     103            0 :         int                     numTables;
     104            0 :         int                     numExtensions;
     105            0 :         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            0 :         pg_log_info("reading extensions");
     113            0 :         extinfo = getExtensions(fout, &numExtensions);
     114              : 
     115            0 :         pg_log_info("identifying extension members");
     116            0 :         getExtensionMembership(fout, extinfo, numExtensions);
     117              : 
     118            0 :         pg_log_info("reading schemas");
     119            0 :         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            0 :         pg_log_info("reading user-defined tables");
     128            0 :         tblinfo = getTables(fout, &numTables);
     129              : 
     130            0 :         getOwnedSeqs(fout, tblinfo, numTables);
     131              : 
     132            0 :         pg_log_info("reading user-defined functions");
     133            0 :         getFuncs(fout);
     134              : 
     135              :         /* this must be after getTables and getFuncs */
     136            0 :         pg_log_info("reading user-defined types");
     137            0 :         getTypes(fout);
     138              : 
     139              :         /* this must be after getFuncs, too */
     140            0 :         pg_log_info("reading procedural languages");
     141            0 :         getProcLangs(fout);
     142              : 
     143            0 :         pg_log_info("reading user-defined aggregate functions");
     144            0 :         getAggregates(fout);
     145              : 
     146            0 :         pg_log_info("reading user-defined operators");
     147            0 :         getOperators(fout);
     148              : 
     149            0 :         pg_log_info("reading user-defined access methods");
     150            0 :         getAccessMethods(fout);
     151              : 
     152            0 :         pg_log_info("reading user-defined operator classes");
     153            0 :         getOpclasses(fout);
     154              : 
     155            0 :         pg_log_info("reading user-defined operator families");
     156            0 :         getOpfamilies(fout);
     157              : 
     158            0 :         pg_log_info("reading user-defined text search parsers");
     159            0 :         getTSParsers(fout);
     160              : 
     161            0 :         pg_log_info("reading user-defined text search templates");
     162            0 :         getTSTemplates(fout);
     163              : 
     164            0 :         pg_log_info("reading user-defined text search dictionaries");
     165            0 :         getTSDictionaries(fout);
     166              : 
     167            0 :         pg_log_info("reading user-defined text search configurations");
     168            0 :         getTSConfigurations(fout);
     169              : 
     170            0 :         pg_log_info("reading user-defined foreign-data wrappers");
     171            0 :         getForeignDataWrappers(fout);
     172              : 
     173            0 :         pg_log_info("reading user-defined foreign servers");
     174            0 :         getForeignServers(fout);
     175              : 
     176            0 :         pg_log_info("reading default privileges");
     177            0 :         getDefaultACLs(fout);
     178              : 
     179            0 :         pg_log_info("reading user-defined collations");
     180            0 :         getCollations(fout);
     181              : 
     182            0 :         pg_log_info("reading user-defined conversions");
     183            0 :         getConversions(fout);
     184              : 
     185            0 :         pg_log_info("reading type casts");
     186            0 :         getCasts(fout);
     187              : 
     188            0 :         pg_log_info("reading transforms");
     189            0 :         getTransforms(fout);
     190              : 
     191            0 :         pg_log_info("reading table inheritance information");
     192            0 :         inhinfo = getInherits(fout, &numInherits);
     193              : 
     194            0 :         pg_log_info("reading event triggers");
     195            0 :         getEventTriggers(fout);
     196              : 
     197              :         /* Identify extension configuration tables that should be dumped */
     198            0 :         pg_log_info("finding extension tables");
     199            0 :         processExtensionTables(fout, extinfo, numExtensions);
     200              : 
     201              :         /* Link tables to parents, mark parents of target tables interesting */
     202            0 :         pg_log_info("finding inheritance relationships");
     203            0 :         flagInhTables(fout, tblinfo, numTables, inhinfo, numInherits);
     204              : 
     205            0 :         pg_log_info("reading column info for interesting tables");
     206            0 :         getTableAttrs(fout, tblinfo, numTables);
     207              : 
     208            0 :         pg_log_info("flagging inherited columns in subtables");
     209            0 :         flagInhAttrs(fout, fout->dopt, tblinfo, numTables);
     210              : 
     211            0 :         pg_log_info("reading partitioning data");
     212            0 :         getPartitioningInfo(fout);
     213              : 
     214            0 :         pg_log_info("reading indexes");
     215            0 :         getIndexes(fout, tblinfo, numTables);
     216              : 
     217            0 :         pg_log_info("flagging indexes in partitioned tables");
     218            0 :         flagInhIndexes(fout, tblinfo, numTables);
     219              : 
     220            0 :         pg_log_info("reading extended statistics");
     221            0 :         getExtendedStatistics(fout);
     222              : 
     223            0 :         pg_log_info("reading constraints");
     224            0 :         getConstraints(fout, tblinfo, numTables);
     225              : 
     226            0 :         pg_log_info("reading triggers");
     227            0 :         getTriggers(fout, tblinfo, numTables);
     228              : 
     229            0 :         pg_log_info("reading rewrite rules");
     230            0 :         getRules(fout);
     231              : 
     232            0 :         pg_log_info("reading policies");
     233            0 :         getPolicies(fout, tblinfo, numTables);
     234              : 
     235            0 :         pg_log_info("reading publications");
     236            0 :         getPublications(fout);
     237              : 
     238            0 :         pg_log_info("reading publication membership of tables");
     239            0 :         getPublicationTables(fout, tblinfo, numTables);
     240              : 
     241            0 :         pg_log_info("reading publication membership of schemas");
     242            0 :         getPublicationNamespaces(fout);
     243              : 
     244            0 :         pg_log_info("reading subscriptions");
     245            0 :         getSubscriptions(fout);
     246              : 
     247            0 :         pg_log_info("reading subscription membership of relations");
     248            0 :         getSubscriptionRelations(fout);
     249              : 
     250            0 :         free(inhinfo);                          /* not needed any longer */
     251              : 
     252            0 :         *numTablesPtr = numTables;
     253            0 :         return tblinfo;
     254            0 : }
     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            0 : flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
     270              :                           InhInfo *inhinfo, int numInherits)
     271              : {
     272            0 :         TableInfo  *child = NULL;
     273            0 :         TableInfo  *parent = NULL;
     274            0 :         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            0 :         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            0 :                 if (child == NULL ||
     294            0 :                         child->dobj.catId.oid != inhinfo[i].inhrelid)
     295              :                 {
     296            0 :                         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            0 :                         if (child == NULL)
     303            0 :                                 continue;
     304            0 :                 }
     305            0 :                 if (parent == NULL ||
     306            0 :                         parent->dobj.catId.oid != inhinfo[i].inhparent)
     307              :                 {
     308            0 :                         parent = findTableByOid(inhinfo[i].inhparent);
     309            0 :                         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            0 :                 }
     315              :                 /* Add this parent to the child's list of parents. */
     316            0 :                 if (child->numParents > 0)
     317            0 :                         child->parents = pg_realloc_array(child->parents,
     318              :                                                                                           TableInfo *,
     319              :                                                                                           child->numParents + 1);
     320              :                 else
     321            0 :                         child->parents = pg_malloc_array(TableInfo *, 1);
     322            0 :                 child->parents[child->numParents++] = parent;
     323            0 :         }
     324              : 
     325              :         /*
     326              :          * Now consider all child tables and mark parents interesting as needed.
     327              :          */
     328            0 :         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            0 :                 if (tblinfo[i].dobj.dump)
     336              :                 {
     337            0 :                         int                     numParents = tblinfo[i].numParents;
     338            0 :                         TableInfo **parents = tblinfo[i].parents;
     339              : 
     340            0 :                         for (j = 0; j < numParents; j++)
     341            0 :                                 parents[j]->interesting = true;
     342            0 :                 }
     343              : 
     344              :                 /* Create TableAttachInfo object if needed */
     345            0 :                 if ((tblinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
     346            0 :                         tblinfo[i].ispartition)
     347              :                 {
     348            0 :                         TableAttachInfo *attachinfo;
     349              : 
     350              :                         /* With partitions there can only be one parent */
     351            0 :                         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            0 :                         attachinfo = palloc_object(TableAttachInfo);
     357            0 :                         attachinfo->dobj.objType = DO_TABLE_ATTACH;
     358            0 :                         attachinfo->dobj.catId.tableoid = 0;
     359            0 :                         attachinfo->dobj.catId.oid = 0;
     360            0 :                         AssignDumpId(&attachinfo->dobj);
     361            0 :                         attachinfo->dobj.name = pg_strdup(tblinfo[i].dobj.name);
     362            0 :                         attachinfo->dobj.namespace = tblinfo[i].dobj.namespace;
     363            0 :                         attachinfo->parentTbl = tblinfo[i].parents[0];
     364            0 :                         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            0 :                         addObjectDependency(&attachinfo->dobj, tblinfo[i].dobj.dumpId);
     376            0 :                         addObjectDependency(&attachinfo->dobj, tblinfo[i].parents[0]->dobj.dumpId);
     377            0 :                 }
     378            0 :         }
     379            0 : }
     380              : 
     381              : /*
     382              :  * flagInhIndexes -
     383              :  *       Create IndexAttachInfo objects for partitioned indexes, and add
     384              :  *       appropriate dependency links.
     385              :  */
     386              : static void
     387            0 : flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
     388              : {
     389            0 :         int                     i,
     390              :                                 j;
     391              : 
     392            0 :         for (i = 0; i < numTables; i++)
     393              :         {
     394            0 :                 if (!tblinfo[i].ispartition || tblinfo[i].numParents == 0)
     395            0 :                         continue;
     396              : 
     397            0 :                 Assert(tblinfo[i].numParents == 1);
     398              : 
     399            0 :                 for (j = 0; j < tblinfo[i].numIndexes; j++)
     400              :                 {
     401            0 :                         IndxInfo   *index = &(tblinfo[i].indexes[j]);
     402            0 :                         IndxInfo   *parentidx;
     403            0 :                         IndexAttachInfo *attachinfo;
     404              : 
     405            0 :                         if (index->parentidx == 0)
     406            0 :                                 continue;
     407              : 
     408            0 :                         parentidx = findIndexByOid(index->parentidx);
     409            0 :                         if (parentidx == NULL)
     410            0 :                                 continue;
     411              : 
     412            0 :                         attachinfo = pg_malloc_object(IndexAttachInfo);
     413              : 
     414            0 :                         attachinfo->dobj.objType = DO_INDEX_ATTACH;
     415            0 :                         attachinfo->dobj.catId.tableoid = 0;
     416            0 :                         attachinfo->dobj.catId.oid = 0;
     417            0 :                         AssignDumpId(&attachinfo->dobj);
     418            0 :                         attachinfo->dobj.name = pg_strdup(index->dobj.name);
     419            0 :                         attachinfo->dobj.namespace = index->indextable->dobj.namespace;
     420            0 :                         attachinfo->parentIdx = parentidx;
     421            0 :                         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            0 :                         addObjectDependency(&attachinfo->dobj, index->dobj.dumpId);
     439            0 :                         addObjectDependency(&attachinfo->dobj, parentidx->dobj.dumpId);
     440            0 :                         addObjectDependency(&attachinfo->dobj,
     441            0 :                                                                 index->indextable->dobj.dumpId);
     442            0 :                         addObjectDependency(&attachinfo->dobj,
     443            0 :                                                                 parentidx->indextable->dobj.dumpId);
     444              : 
     445              :                         /* keep track of the list of partitions in the parent index */
     446            0 :                         simple_ptr_list_append(&parentidx->partattaches, &attachinfo->dobj);
     447            0 :                 }
     448            0 :         }
     449            0 : }
     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            0 : flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo, int numTables)
     479              : {
     480            0 :         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            0 :         for (i = 0; i < numTables; i++)
     492              :         {
     493            0 :                 TableInfo  *tbinfo = &(tblinfo[i]);
     494            0 :                 int                     numParents;
     495            0 :                 TableInfo **parents;
     496              : 
     497              :                 /* Some kinds never have parents */
     498            0 :                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
     499            0 :                         tbinfo->relkind == RELKIND_VIEW ||
     500            0 :                         tbinfo->relkind == RELKIND_MATVIEW)
     501            0 :                         continue;
     502              : 
     503              :                 /* Don't bother computing anything for non-target tables, either */
     504            0 :                 if (!tbinfo->dobj.dump)
     505            0 :                         continue;
     506              : 
     507            0 :                 numParents = tbinfo->numParents;
     508            0 :                 parents = tbinfo->parents;
     509              : 
     510            0 :                 if (numParents == 0)
     511            0 :                         continue;                       /* nothing to see here, move along */
     512              : 
     513              :                 /* For each column, search for matching column names in parent(s) */
     514            0 :                 for (j = 0; j < tbinfo->numatts; j++)
     515              :                 {
     516            0 :                         bool            foundNotNull;   /* Attr was NOT NULL in a parent */
     517            0 :                         bool            foundDefault;   /* Found a default in a parent */
     518            0 :                         bool            foundSameGenerated; /* Found matching GENERATED */
     519            0 :                         bool            foundDiffGenerated; /* Found non-matching GENERATED */
     520            0 :                         bool            allNotNullsInvalid = true;      /* is NOT NULL NOT VALID
     521              :                                                                                                          * on all parents? */
     522              : 
     523              :                         /* no point in examining dropped columns */
     524            0 :                         if (tbinfo->attisdropped[j])
     525            0 :                                 continue;
     526              : 
     527            0 :                         foundNotNull = false;
     528            0 :                         foundDefault = false;
     529            0 :                         foundSameGenerated = false;
     530            0 :                         foundDiffGenerated = false;
     531            0 :                         for (k = 0; k < numParents; k++)
     532              :                         {
     533            0 :                                 TableInfo  *parent = parents[k];
     534            0 :                                 int                     inhAttrInd;
     535              : 
     536            0 :                                 inhAttrInd = strInArray(tbinfo->attnames[j],
     537            0 :                                                                                 parent->attnames,
     538            0 :                                                                                 parent->numatts);
     539            0 :                                 if (inhAttrInd >= 0)
     540              :                                 {
     541            0 :                                         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            0 :                                         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            0 :                                         if (fout->remoteVersion >= 180000 &&
     560            0 :                                                 parent->notnull_constrs[inhAttrInd] &&
     561            0 :                                                 !parent->notnull_invalid[inhAttrInd])
     562            0 :                                                 allNotNullsInvalid = false;
     563              : 
     564            0 :                                         foundDefault |= (parentDef != NULL &&
     565            0 :                                                                          strcmp(parentDef->adef_expr, "NULL") != 0 &&
     566            0 :                                                                          !parent->attgenerated[inhAttrInd]);
     567            0 :                                         if (parent->attgenerated[inhAttrInd])
     568              :                                         {
     569              :                                                 /* these pointer nullness checks are just paranoia */
     570            0 :                                                 if (parentDef != NULL &&
     571            0 :                                                         tbinfo->attrdefs[j] != NULL &&
     572            0 :                                                         strcmp(parentDef->adef_expr,
     573            0 :                                                                    tbinfo->attrdefs[j]->adef_expr) == 0)
     574            0 :                                                         foundSameGenerated = true;
     575              :                                                 else
     576            0 :                                                         foundDiffGenerated = true;
     577            0 :                                         }
     578            0 :                                 }
     579            0 :                         }
     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            0 :                         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            0 :                         if (fout->remoteVersion >= 180000 && allNotNullsInvalid)
     595            0 :                                 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            0 :                         if (foundDefault && tbinfo->attrdefs[j] == NULL)
     606              :                         {
     607            0 :                                 AttrDefInfo *attrDef;
     608              : 
     609            0 :                                 attrDef = pg_malloc_object(AttrDefInfo);
     610            0 :                                 attrDef->dobj.objType = DO_ATTRDEF;
     611            0 :                                 attrDef->dobj.catId.tableoid = 0;
     612            0 :                                 attrDef->dobj.catId.oid = 0;
     613            0 :                                 AssignDumpId(&attrDef->dobj);
     614            0 :                                 attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
     615            0 :                                 attrDef->dobj.namespace = tbinfo->dobj.namespace;
     616            0 :                                 attrDef->dobj.dump = tbinfo->dobj.dump;
     617              : 
     618            0 :                                 attrDef->adtable = tbinfo;
     619            0 :                                 attrDef->adnum = j + 1;
     620            0 :                                 attrDef->adef_expr = pg_strdup("NULL");
     621              : 
     622              :                                 /* Will column be dumped explicitly? */
     623            0 :                                 if (shouldPrintColumn(dopt, tbinfo, j))
     624              :                                 {
     625            0 :                                         attrDef->separate = false;
     626              :                                         /* No dependency needed: NULL cannot have dependencies */
     627            0 :                                 }
     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            0 :                                                                                 tbinfo->dobj.dumpId);
     635              :                                 }
     636              : 
     637            0 :                                 tbinfo->attrdefs[j] = attrDef;
     638            0 :                         }
     639              : 
     640              :                         /* No need to dump generation expression if it's inheritable */
     641            0 :                         if (foundSameGenerated && !foundDiffGenerated &&
     642            0 :                                 !tbinfo->ispartition && !dopt->binary_upgrade)
     643            0 :                                 tbinfo->attrdefs[j]->dobj.dump = DUMP_COMPONENT_NONE;
     644            0 :                 }
     645            0 :         }
     646            0 : }
     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            0 : AssignDumpId(DumpableObject *dobj)
     658              : {
     659            0 :         dobj->dumpId = ++lastDumpId;
     660            0 :         dobj->name = NULL;                   /* must be set later */
     661            0 :         dobj->namespace = NULL;              /* may be set later */
     662            0 :         dobj->dump = DUMP_COMPONENT_ALL;     /* default assumption */
     663            0 :         dobj->dump_contains = DUMP_COMPONENT_ALL;    /* default assumption */
     664              :         /* All objects have definitions; we may set more components bits later */
     665            0 :         dobj->components = DUMP_COMPONENT_DEFINITION;
     666            0 :         dobj->ext_member = false;    /* default assumption */
     667            0 :         dobj->depends_on_ext = false;        /* default assumption */
     668            0 :         dobj->dependencies = NULL;
     669            0 :         dobj->nDeps = 0;
     670            0 :         dobj->allocDeps = 0;
     671              : 
     672              :         /* Add object to dumpIdMap[], enlarging that array if need be */
     673            0 :         while (dobj->dumpId >= allocedDumpIds)
     674              :         {
     675            0 :                 int                     newAlloc;
     676              : 
     677            0 :                 if (allocedDumpIds <= 0)
     678              :                 {
     679            0 :                         newAlloc = 256;
     680            0 :                         dumpIdMap = pg_malloc_array(DumpableObject *, newAlloc);
     681            0 :                 }
     682              :                 else
     683              :                 {
     684            0 :                         newAlloc = allocedDumpIds * 2;
     685            0 :                         dumpIdMap = pg_realloc_array(dumpIdMap, DumpableObject *, newAlloc);
     686              :                 }
     687            0 :                 memset(dumpIdMap + allocedDumpIds, 0,
     688              :                            (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
     689            0 :                 allocedDumpIds = newAlloc;
     690            0 :         }
     691            0 :         dumpIdMap[dobj->dumpId] = dobj;
     692              : 
     693              :         /* If it has a valid CatalogId, enter it into the hash table */
     694            0 :         if (OidIsValid(dobj->catId.tableoid))
     695              :         {
     696            0 :                 CatalogIdMapEntry *entry;
     697            0 :                 bool            found;
     698              : 
     699              :                 /* Initialize CatalogId hash table if not done yet */
     700            0 :                 if (catalogIdHash == NULL)
     701            0 :                         catalogIdHash = catalogid_create(CATALOGIDHASH_INITIAL_SIZE, NULL);
     702              : 
     703            0 :                 entry = catalogid_insert(catalogIdHash, dobj->catId, &found);
     704            0 :                 if (!found)
     705              :                 {
     706            0 :                         entry->dobj = NULL;
     707            0 :                         entry->ext = NULL;
     708            0 :                 }
     709            0 :                 Assert(entry->dobj == NULL);
     710            0 :                 entry->dobj = dobj;
     711            0 :         }
     712            0 : }
     713              : 
     714              : /*
     715              :  * recordAdditionalCatalogID
     716              :  *        Record an additional catalog ID for the given DumpableObject
     717              :  */
     718              : void
     719            0 : recordAdditionalCatalogID(CatalogId catId, DumpableObject *dobj)
     720              : {
     721            0 :         CatalogIdMapEntry *entry;
     722            0 :         bool            found;
     723              : 
     724              :         /* CatalogId hash table must exist, if we have a DumpableObject */
     725            0 :         Assert(catalogIdHash != NULL);
     726              : 
     727              :         /* Add reference to CatalogId hash */
     728            0 :         entry = catalogid_insert(catalogIdHash, catId, &found);
     729            0 :         if (!found)
     730              :         {
     731            0 :                 entry->dobj = NULL;
     732            0 :                 entry->ext = NULL;
     733            0 :         }
     734            0 :         Assert(entry->dobj == NULL);
     735            0 :         entry->dobj = dobj;
     736            0 : }
     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            0 : createDumpId(void)
     746              : {
     747            0 :         return ++lastDumpId;
     748              : }
     749              : 
     750              : /*
     751              :  * Return the largest DumpId so far assigned
     752              :  */
     753              : DumpId
     754            0 : getMaxDumpId(void)
     755              : {
     756            0 :         return lastDumpId;
     757              : }
     758              : 
     759              : /*
     760              :  * Find a DumpableObject by dump ID
     761              :  *
     762              :  * Returns NULL for invalid ID
     763              :  */
     764              : DumpableObject *
     765            0 : findObjectByDumpId(DumpId dumpId)
     766              : {
     767            0 :         if (dumpId <= 0 || dumpId >= allocedDumpIds)
     768            0 :                 return NULL;                    /* out of range? */
     769            0 :         return dumpIdMap[dumpId];
     770            0 : }
     771              : 
     772              : /*
     773              :  * Find a DumpableObject by catalog ID
     774              :  *
     775              :  * Returns NULL for unknown ID
     776              :  */
     777              : DumpableObject *
     778            0 : findObjectByCatalogId(CatalogId catalogId)
     779              : {
     780            0 :         CatalogIdMapEntry *entry;
     781              : 
     782            0 :         if (catalogIdHash == NULL)
     783            0 :                 return NULL;                    /* no objects exist yet */
     784              : 
     785            0 :         entry = catalogid_lookup(catalogIdHash, catalogId);
     786            0 :         if (entry == NULL)
     787            0 :                 return NULL;
     788            0 :         return entry->dobj;
     789            0 : }
     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            0 : getDumpableObjects(DumpableObject ***objs, int *numObjs)
     798              : {
     799            0 :         int                     i,
     800              :                                 j;
     801              : 
     802            0 :         *objs = pg_malloc_array(DumpableObject *, allocedDumpIds);
     803            0 :         j = 0;
     804            0 :         for (i = 1; i < allocedDumpIds; i++)
     805              :         {
     806            0 :                 if (dumpIdMap[i])
     807            0 :                         (*objs)[j++] = dumpIdMap[i];
     808            0 :         }
     809            0 :         *numObjs = j;
     810            0 : }
     811              : 
     812              : /*
     813              :  * Add a dependency link to a DumpableObject
     814              :  *
     815              :  * Note: duplicate dependencies are currently not eliminated
     816              :  */
     817              : void
     818            0 : addObjectDependency(DumpableObject *dobj, DumpId refId)
     819              : {
     820            0 :         if (dobj->nDeps >= dobj->allocDeps)
     821              :         {
     822            0 :                 if (dobj->allocDeps <= 0)
     823              :                 {
     824            0 :                         dobj->allocDeps = 16;
     825            0 :                         dobj->dependencies = pg_malloc_array(DumpId, dobj->allocDeps);
     826            0 :                 }
     827              :                 else
     828              :                 {
     829            0 :                         dobj->allocDeps *= 2;
     830            0 :                         dobj->dependencies = pg_realloc_array(dobj->dependencies,
     831              :                                                                                                   DumpId, dobj->allocDeps);
     832              :                 }
     833            0 :         }
     834            0 :         dobj->dependencies[dobj->nDeps++] = refId;
     835            0 : }
     836              : 
     837              : /*
     838              :  * Remove a dependency link from a DumpableObject
     839              :  *
     840              :  * If there are multiple links, all are removed
     841              :  */
     842              : void
     843            0 : removeObjectDependency(DumpableObject *dobj, DumpId refId)
     844              : {
     845            0 :         int                     i;
     846            0 :         int                     j = 0;
     847              : 
     848            0 :         for (i = 0; i < dobj->nDeps; i++)
     849              :         {
     850            0 :                 if (dobj->dependencies[i] != refId)
     851            0 :                         dobj->dependencies[j++] = dobj->dependencies[i];
     852            0 :         }
     853            0 :         dobj->nDeps = j;
     854            0 : }
     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            0 : findTableByOid(Oid oid)
     864              : {
     865            0 :         CatalogId       catId;
     866            0 :         DumpableObject *dobj;
     867              : 
     868            0 :         catId.tableoid = RelationRelationId;
     869            0 :         catId.oid = oid;
     870            0 :         dobj = findObjectByCatalogId(catId);
     871            0 :         Assert(dobj == NULL || dobj->objType == DO_TABLE);
     872            0 :         return (TableInfo *) dobj;
     873            0 : }
     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            0 : findIndexByOid(Oid oid)
     882              : {
     883            0 :         CatalogId       catId;
     884            0 :         DumpableObject *dobj;
     885              : 
     886            0 :         catId.tableoid = RelationRelationId;
     887            0 :         catId.oid = oid;
     888            0 :         dobj = findObjectByCatalogId(catId);
     889            0 :         Assert(dobj == NULL || dobj->objType == DO_INDEX);
     890            0 :         return (IndxInfo *) dobj;
     891            0 : }
     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            0 : findTypeByOid(Oid oid)
     900              : {
     901            0 :         CatalogId       catId;
     902            0 :         DumpableObject *dobj;
     903              : 
     904            0 :         catId.tableoid = TypeRelationId;
     905            0 :         catId.oid = oid;
     906            0 :         dobj = findObjectByCatalogId(catId);
     907            0 :         Assert(dobj == NULL ||
     908              :                    dobj->objType == DO_TYPE || dobj->objType == DO_DUMMY_TYPE);
     909            0 :         return (TypeInfo *) dobj;
     910            0 : }
     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            0 : findFuncByOid(Oid oid)
     919              : {
     920            0 :         CatalogId       catId;
     921            0 :         DumpableObject *dobj;
     922              : 
     923            0 :         catId.tableoid = ProcedureRelationId;
     924            0 :         catId.oid = oid;
     925            0 :         dobj = findObjectByCatalogId(catId);
     926            0 :         Assert(dobj == NULL || dobj->objType == DO_FUNC);
     927            0 :         return (FuncInfo *) dobj;
     928            0 : }
     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            0 : findOprByOid(Oid oid)
     937              : {
     938            0 :         CatalogId       catId;
     939            0 :         DumpableObject *dobj;
     940              : 
     941            0 :         catId.tableoid = OperatorRelationId;
     942            0 :         catId.oid = oid;
     943            0 :         dobj = findObjectByCatalogId(catId);
     944            0 :         Assert(dobj == NULL || dobj->objType == DO_OPERATOR);
     945            0 :         return (OprInfo *) dobj;
     946            0 : }
     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            0 : findAccessMethodByOid(Oid oid)
     955              : {
     956            0 :         CatalogId       catId;
     957            0 :         DumpableObject *dobj;
     958              : 
     959            0 :         catId.tableoid = AccessMethodRelationId;
     960            0 :         catId.oid = oid;
     961            0 :         dobj = findObjectByCatalogId(catId);
     962            0 :         Assert(dobj == NULL || dobj->objType == DO_ACCESS_METHOD);
     963            0 :         return (AccessMethodInfo *) dobj;
     964            0 : }
     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            0 : findCollationByOid(Oid oid)
     973              : {
     974            0 :         CatalogId       catId;
     975            0 :         DumpableObject *dobj;
     976              : 
     977            0 :         catId.tableoid = CollationRelationId;
     978            0 :         catId.oid = oid;
     979            0 :         dobj = findObjectByCatalogId(catId);
     980            0 :         Assert(dobj == NULL || dobj->objType == DO_COLLATION);
     981            0 :         return (CollInfo *) dobj;
     982            0 : }
     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            0 : findNamespaceByOid(Oid oid)
     991              : {
     992            0 :         CatalogId       catId;
     993            0 :         DumpableObject *dobj;
     994              : 
     995            0 :         catId.tableoid = NamespaceRelationId;
     996            0 :         catId.oid = oid;
     997            0 :         dobj = findObjectByCatalogId(catId);
     998            0 :         Assert(dobj == NULL || dobj->objType == DO_NAMESPACE);
     999            0 :         return (NamespaceInfo *) dobj;
    1000            0 : }
    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            0 : findExtensionByOid(Oid oid)
    1009              : {
    1010            0 :         CatalogId       catId;
    1011            0 :         DumpableObject *dobj;
    1012              : 
    1013            0 :         catId.tableoid = ExtensionRelationId;
    1014            0 :         catId.oid = oid;
    1015            0 :         dobj = findObjectByCatalogId(catId);
    1016            0 :         Assert(dobj == NULL || dobj->objType == DO_EXTENSION);
    1017            0 :         return (ExtensionInfo *) dobj;
    1018            0 : }
    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            0 : findPublicationByOid(Oid oid)
    1027              : {
    1028            0 :         CatalogId       catId;
    1029            0 :         DumpableObject *dobj;
    1030              : 
    1031            0 :         catId.tableoid = PublicationRelationId;
    1032            0 :         catId.oid = oid;
    1033            0 :         dobj = findObjectByCatalogId(catId);
    1034            0 :         Assert(dobj == NULL || dobj->objType == DO_PUBLICATION);
    1035            0 :         return (PublicationInfo *) dobj;
    1036            0 : }
    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            0 : findSubscriptionByOid(Oid oid)
    1045              : {
    1046            0 :         CatalogId       catId;
    1047            0 :         DumpableObject *dobj;
    1048              : 
    1049            0 :         catId.tableoid = SubscriptionRelationId;
    1050            0 :         catId.oid = oid;
    1051            0 :         dobj = findObjectByCatalogId(catId);
    1052            0 :         Assert(dobj == NULL || dobj->objType == DO_SUBSCRIPTION);
    1053            0 :         return (SubscriptionInfo *) dobj;
    1054            0 : }
    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            0 : recordExtensionMembership(CatalogId catId, ExtensionInfo *ext)
    1064              : {
    1065            0 :         CatalogIdMapEntry *entry;
    1066            0 :         bool            found;
    1067              : 
    1068              :         /* CatalogId hash table must exist, if we have an ExtensionInfo */
    1069            0 :         Assert(catalogIdHash != NULL);
    1070              : 
    1071              :         /* Add reference to CatalogId hash */
    1072            0 :         entry = catalogid_insert(catalogIdHash, catId, &found);
    1073            0 :         if (!found)
    1074              :         {
    1075            0 :                 entry->dobj = NULL;
    1076            0 :                 entry->ext = NULL;
    1077            0 :         }
    1078            0 :         Assert(entry->ext == NULL);
    1079            0 :         entry->ext = ext;
    1080            0 : }
    1081              : 
    1082              : /*
    1083              :  * findOwningExtension
    1084              :  *        return owning extension for specified catalog ID, or NULL if none
    1085              :  */
    1086              : ExtensionInfo *
    1087            0 : findOwningExtension(CatalogId catalogId)
    1088              : {
    1089            0 :         CatalogIdMapEntry *entry;
    1090              : 
    1091            0 :         if (catalogIdHash == NULL)
    1092            0 :                 return NULL;                    /* no objects exist yet */
    1093              : 
    1094            0 :         entry = catalogid_lookup(catalogIdHash, catalogId);
    1095            0 :         if (entry == NULL)
    1096            0 :                 return NULL;
    1097            0 :         return entry->ext;
    1098            0 : }
    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            0 : parseOidArray(const char *str, Oid *array, int arraysize)
    1112              : {
    1113            0 :         int                     j,
    1114              :                                 argNum;
    1115            0 :         char            temp[100];
    1116            0 :         char            s;
    1117              : 
    1118            0 :         argNum = 0;
    1119            0 :         j = 0;
    1120            0 :         for (;;)
    1121              :         {
    1122            0 :                 s = *str++;
    1123            0 :                 if (s == ' ' || s == '\0')
    1124              :                 {
    1125            0 :                         if (j > 0)
    1126              :                         {
    1127            0 :                                 if (argNum >= arraysize)
    1128            0 :                                         pg_fatal("could not parse numeric array \"%s\": too many numbers", str);
    1129            0 :                                 temp[j] = '\0';
    1130            0 :                                 array[argNum++] = atooid(temp);
    1131            0 :                                 j = 0;
    1132            0 :                         }
    1133            0 :                         if (s == '\0')
    1134            0 :                                 break;
    1135            0 :                 }
    1136              :                 else
    1137              :                 {
    1138            0 :                         if (!(isdigit((unsigned char) s) || s == '-') ||
    1139            0 :                                 j >= sizeof(temp) - 1)
    1140            0 :                                 pg_fatal("could not parse numeric array \"%s\": invalid character in number", str);
    1141            0 :                         temp[j++] = s;
    1142              :                 }
    1143              :         }
    1144              : 
    1145            0 :         while (argNum < arraysize)
    1146            0 :                 array[argNum++] = InvalidOid;
    1147            0 : }
    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            0 : strInArray(const char *pattern, char **arr, int arr_size)
    1159              : {
    1160            0 :         int                     i;
    1161              : 
    1162            0 :         for (i = 0; i < arr_size; i++)
    1163              :         {
    1164            0 :                 if (strcmp(pattern, arr[i]) == 0)
    1165            0 :                         return i;
    1166            0 :         }
    1167            0 :         return -1;
    1168            0 : }
        

Generated by: LCOV version 2.3.2-1