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

Generated by: LCOV version 1.14