LCOV - code coverage report
Current view: top level - src/bin/pg_dump - common.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 363 376 96.5 %
Date: 2024-03-28 08:11:21 Functions: 26 26 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14