LCOV - code coverage report
Current view: top level - src/bin/pg_dump - common.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 381 397 96.0 %
Date: 2019-11-15 22:06:47 Functions: 29 29 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-2019, 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 "fe_utils/string_utils.h"
      22             : #include "pg_backup_archiver.h"
      23             : #include "pg_backup_utils.h"
      24             : #include "pg_dump.h"
      25             : 
      26             : /*
      27             :  * Variables for mapping DumpId to DumpableObject
      28             :  */
      29             : static DumpableObject **dumpIdMap = NULL;
      30             : static int  allocedDumpIds = 0;
      31             : static DumpId lastDumpId = 0;
      32             : 
      33             : /*
      34             :  * Variables for mapping CatalogId to DumpableObject
      35             :  */
      36             : static bool catalogIdMapValid = false;
      37             : static DumpableObject **catalogIdMap = NULL;
      38             : static int  numCatalogIds = 0;
      39             : 
      40             : /*
      41             :  * These variables are static to avoid the notational cruft of having to pass
      42             :  * them into findTableByOid() and friends.  For each of these arrays, we build
      43             :  * a sorted-by-OID index array immediately after the objects are fetched,
      44             :  * and then we use binary search in findTableByOid() and friends.  (qsort'ing
      45             :  * the object arrays themselves would be simpler, but it doesn't work because
      46             :  * pg_dump.c may have already established pointers between items.)
      47             :  */
      48             : static DumpableObject **tblinfoindex;
      49             : static DumpableObject **typinfoindex;
      50             : static DumpableObject **funinfoindex;
      51             : static DumpableObject **oprinfoindex;
      52             : static DumpableObject **collinfoindex;
      53             : static DumpableObject **nspinfoindex;
      54             : static DumpableObject **extinfoindex;
      55             : static int  numTables;
      56             : static int  numTypes;
      57             : static int  numFuncs;
      58             : static int  numOperators;
      59             : static int  numCollations;
      60             : static int  numNamespaces;
      61             : static int  numExtensions;
      62             : 
      63             : /* This is an array of object identities, not actual DumpableObjects */
      64             : static ExtensionMemberId *extmembers;
      65             : static int  numextmembers;
      66             : 
      67             : static void flagInhTables(Archive *fout, TableInfo *tbinfo, int numTables,
      68             :                           InhInfo *inhinfo, int numInherits);
      69             : static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables);
      70             : static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables);
      71             : static DumpableObject **buildIndexArray(void *objArray, int numObjs,
      72             :                                         Size objSize);
      73             : static int  DOCatalogIdCompare(const void *p1, const void *p2);
      74             : static int  ExtensionMemberIdCompare(const void *p1, const void *p2);
      75             : static void findParentsByOid(TableInfo *self,
      76             :                              InhInfo *inhinfo, int numInherits);
      77             : static int  strInArray(const char *pattern, char **arr, int arr_size);
      78             : static IndxInfo *findIndexByOid(Oid oid, DumpableObject **idxinfoindex,
      79             :                                 int numIndexes);
      80             : 
      81             : 
      82             : /*
      83             :  * getSchemaData
      84             :  *    Collect information about all potentially dumpable objects
      85             :  */
      86             : TableInfo *
      87         158 : getSchemaData(Archive *fout, int *numTablesPtr)
      88             : {
      89             :     TableInfo  *tblinfo;
      90             :     TypeInfo   *typinfo;
      91             :     FuncInfo   *funinfo;
      92             :     OprInfo    *oprinfo;
      93             :     CollInfo   *collinfo;
      94             :     NamespaceInfo *nspinfo;
      95             :     ExtensionInfo *extinfo;
      96             :     InhInfo    *inhinfo;
      97             :     int         numAggregates;
      98             :     int         numInherits;
      99             :     int         numRules;
     100             :     int         numProcLangs;
     101             :     int         numCasts;
     102             :     int         numTransforms;
     103             :     int         numAccessMethods;
     104             :     int         numOpclasses;
     105             :     int         numOpfamilies;
     106             :     int         numConversions;
     107             :     int         numTSParsers;
     108             :     int         numTSTemplates;
     109             :     int         numTSDicts;
     110             :     int         numTSConfigs;
     111             :     int         numForeignDataWrappers;
     112             :     int         numForeignServers;
     113             :     int         numDefaultACLs;
     114             :     int         numEventTriggers;
     115             : 
     116             :     /*
     117             :      * We must read extensions and extension membership info first, because
     118             :      * extension membership needs to be consultable during decisions about
     119             :      * whether other objects are to be dumped.
     120             :      */
     121         158 :     pg_log_info("reading extensions");
     122         158 :     extinfo = getExtensions(fout, &numExtensions);
     123         158 :     extinfoindex = buildIndexArray(extinfo, numExtensions, sizeof(ExtensionInfo));
     124             : 
     125         158 :     pg_log_info("identifying extension members");
     126         158 :     getExtensionMembership(fout, extinfo, numExtensions);
     127             : 
     128         158 :     pg_log_info("reading schemas");
     129         158 :     nspinfo = getNamespaces(fout, &numNamespaces);
     130         158 :     nspinfoindex = buildIndexArray(nspinfo, numNamespaces, sizeof(NamespaceInfo));
     131             : 
     132             :     /*
     133             :      * getTables should be done as soon as possible, so as to minimize the
     134             :      * window between starting our transaction and acquiring per-table locks.
     135             :      * However, we have to do getNamespaces first because the tables get
     136             :      * linked to their containing namespaces during getTables.
     137             :      */
     138         158 :     pg_log_info("reading user-defined tables");
     139         158 :     tblinfo = getTables(fout, &numTables);
     140         156 :     tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo));
     141             : 
     142             :     /* Do this after we've built tblinfoindex */
     143         156 :     getOwnedSeqs(fout, tblinfo, numTables);
     144             : 
     145         156 :     pg_log_info("reading user-defined functions");
     146         156 :     funinfo = getFuncs(fout, &numFuncs);
     147         156 :     funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo));
     148             : 
     149             :     /* this must be after getTables and getFuncs */
     150         156 :     pg_log_info("reading user-defined types");
     151         156 :     typinfo = getTypes(fout, &numTypes);
     152         156 :     typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo));
     153             : 
     154             :     /* this must be after getFuncs, too */
     155         156 :     pg_log_info("reading procedural languages");
     156         156 :     getProcLangs(fout, &numProcLangs);
     157             : 
     158         156 :     pg_log_info("reading user-defined aggregate functions");
     159         156 :     getAggregates(fout, &numAggregates);
     160             : 
     161         156 :     pg_log_info("reading user-defined operators");
     162         156 :     oprinfo = getOperators(fout, &numOperators);
     163         156 :     oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
     164             : 
     165         156 :     pg_log_info("reading user-defined access methods");
     166         156 :     getAccessMethods(fout, &numAccessMethods);
     167             : 
     168         156 :     pg_log_info("reading user-defined operator classes");
     169         156 :     getOpclasses(fout, &numOpclasses);
     170             : 
     171         156 :     pg_log_info("reading user-defined operator families");
     172         156 :     getOpfamilies(fout, &numOpfamilies);
     173             : 
     174         156 :     pg_log_info("reading user-defined text search parsers");
     175         156 :     getTSParsers(fout, &numTSParsers);
     176             : 
     177         156 :     pg_log_info("reading user-defined text search templates");
     178         156 :     getTSTemplates(fout, &numTSTemplates);
     179             : 
     180         156 :     pg_log_info("reading user-defined text search dictionaries");
     181         156 :     getTSDictionaries(fout, &numTSDicts);
     182             : 
     183         156 :     pg_log_info("reading user-defined text search configurations");
     184         156 :     getTSConfigurations(fout, &numTSConfigs);
     185             : 
     186         156 :     pg_log_info("reading user-defined foreign-data wrappers");
     187         156 :     getForeignDataWrappers(fout, &numForeignDataWrappers);
     188             : 
     189         156 :     pg_log_info("reading user-defined foreign servers");
     190         156 :     getForeignServers(fout, &numForeignServers);
     191             : 
     192         156 :     pg_log_info("reading default privileges");
     193         156 :     getDefaultACLs(fout, &numDefaultACLs);
     194             : 
     195         156 :     pg_log_info("reading user-defined collations");
     196         156 :     collinfo = getCollations(fout, &numCollations);
     197         156 :     collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
     198             : 
     199         156 :     pg_log_info("reading user-defined conversions");
     200         156 :     getConversions(fout, &numConversions);
     201             : 
     202         156 :     pg_log_info("reading type casts");
     203         156 :     getCasts(fout, &numCasts);
     204             : 
     205         156 :     pg_log_info("reading transforms");
     206         156 :     getTransforms(fout, &numTransforms);
     207             : 
     208         156 :     pg_log_info("reading table inheritance information");
     209         156 :     inhinfo = getInherits(fout, &numInherits);
     210             : 
     211         156 :     pg_log_info("reading event triggers");
     212         156 :     getEventTriggers(fout, &numEventTriggers);
     213             : 
     214             :     /* Identify extension configuration tables that should be dumped */
     215         156 :     pg_log_info("finding extension tables");
     216         156 :     processExtensionTables(fout, extinfo, numExtensions);
     217             : 
     218             :     /* Link tables to parents, mark parents of target tables interesting */
     219         156 :     pg_log_info("finding inheritance relationships");
     220         156 :     flagInhTables(fout, tblinfo, numTables, inhinfo, numInherits);
     221             : 
     222         156 :     pg_log_info("reading column info for interesting tables");
     223         156 :     getTableAttrs(fout, tblinfo, numTables);
     224             : 
     225         156 :     pg_log_info("flagging inherited columns in subtables");
     226         156 :     flagInhAttrs(fout->dopt, tblinfo, numTables);
     227             : 
     228         156 :     pg_log_info("reading indexes");
     229         156 :     getIndexes(fout, tblinfo, numTables);
     230             : 
     231         156 :     pg_log_info("flagging indexes in partitioned tables");
     232         156 :     flagInhIndexes(fout, tblinfo, numTables);
     233             : 
     234         156 :     pg_log_info("reading extended statistics");
     235         156 :     getExtendedStatistics(fout);
     236             : 
     237         156 :     pg_log_info("reading constraints");
     238         156 :     getConstraints(fout, tblinfo, numTables);
     239             : 
     240         156 :     pg_log_info("reading triggers");
     241         156 :     getTriggers(fout, tblinfo, numTables);
     242             : 
     243         156 :     pg_log_info("reading rewrite rules");
     244         156 :     getRules(fout, &numRules);
     245             : 
     246         156 :     pg_log_info("reading policies");
     247         156 :     getPolicies(fout, tblinfo, numTables);
     248             : 
     249         156 :     pg_log_info("reading publications");
     250         156 :     getPublications(fout);
     251             : 
     252         156 :     pg_log_info("reading publication membership");
     253         156 :     getPublicationTables(fout, tblinfo, numTables);
     254             : 
     255         156 :     pg_log_info("reading subscriptions");
     256         156 :     getSubscriptions(fout);
     257             : 
     258         156 :     *numTablesPtr = numTables;
     259         156 :     return tblinfo;
     260             : }
     261             : 
     262             : /* flagInhTables -
     263             :  *   Fill in parent link fields of tables for which we need that information,
     264             :  *   and mark parents of target tables as interesting
     265             :  *
     266             :  * Note that only direct ancestors of targets are marked interesting.
     267             :  * This is sufficient; we don't much care whether they inherited their
     268             :  * attributes or not.
     269             :  *
     270             :  * modifies tblinfo
     271             :  */
     272             : static void
     273         156 : flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
     274             :               InhInfo *inhinfo, int numInherits)
     275             : {
     276         156 :     DumpOptions *dopt = fout->dopt;
     277             :     int         i,
     278             :                 j;
     279             : 
     280       35736 :     for (i = 0; i < numTables; i++)
     281             :     {
     282       35580 :         bool        find_parents = true;
     283       35580 :         bool        mark_parents = true;
     284             : 
     285             :         /* Some kinds never have parents */
     286       70630 :         if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
     287       50440 :             tblinfo[i].relkind == RELKIND_VIEW ||
     288       15390 :             tblinfo[i].relkind == RELKIND_MATVIEW)
     289       20638 :             continue;
     290             : 
     291             :         /*
     292             :          * Normally, we don't bother computing anything for non-target tables,
     293             :          * but if load-via-partition-root is specified, we gather information
     294             :          * on every partition in the system so that getRootTableInfo can trace
     295             :          * from any given to leaf partition all the way up to the root.  (We
     296             :          * don't need to mark them as interesting for getTableAttrs, though.)
     297             :          */
     298       14942 :         if (!tblinfo[i].dobj.dump)
     299             :         {
     300       10754 :             mark_parents = false;
     301             : 
     302       10754 :             if (!dopt->load_via_partition_root ||
     303           0 :                 !tblinfo[i].ispartition)
     304       10754 :                 find_parents = false;
     305             :         }
     306             : 
     307             :         /* If needed, find all the immediate parent tables. */
     308       14942 :         if (find_parents)
     309        4188 :             findParentsByOid(&tblinfo[i], inhinfo, numInherits);
     310             : 
     311             :         /*
     312             :          * If needed, mark the parents as interesting for getTableAttrs and
     313             :          * getIndexes.
     314             :          */
     315       14942 :         if (mark_parents)
     316             :         {
     317        4188 :             int         numParents = tblinfo[i].numParents;
     318        4188 :             TableInfo **parents = tblinfo[i].parents;
     319             : 
     320        5516 :             for (j = 0; j < numParents; j++)
     321        1328 :                 parents[j]->interesting = true;
     322             :         }
     323             :     }
     324         156 : }
     325             : 
     326             : /*
     327             :  * flagInhIndexes -
     328             :  *   Create IndexAttachInfo objects for partitioned indexes, and add
     329             :  *   appropriate dependency links.
     330             :  */
     331             : static void
     332         156 : flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
     333             : {
     334             :     int         i,
     335             :                 j,
     336             :                 k;
     337             :     DumpableObject ***parentIndexArray;
     338             : 
     339         156 :     parentIndexArray = (DumpableObject ***)
     340         156 :         pg_malloc0(getMaxDumpId() * sizeof(DumpableObject **));
     341             : 
     342       35736 :     for (i = 0; i < numTables; i++)
     343             :     {
     344             :         TableInfo  *parenttbl;
     345             :         IndexAttachInfo *attachinfo;
     346             : 
     347       35580 :         if (!tblinfo[i].ispartition || tblinfo[i].numParents == 0)
     348       34528 :             continue;
     349             : 
     350             :         Assert(tblinfo[i].numParents == 1);
     351        1052 :         parenttbl = tblinfo[i].parents[0];
     352             : 
     353             :         /*
     354             :          * We need access to each parent table's index list, but there is no
     355             :          * index to cover them outside of this function.  To avoid having to
     356             :          * sort every parent table's indexes each time we come across each of
     357             :          * its partitions, create an indexed array for each parent the first
     358             :          * time it is required.
     359             :          */
     360        1052 :         if (parentIndexArray[parenttbl->dobj.dumpId] == NULL)
     361         940 :             parentIndexArray[parenttbl->dobj.dumpId] =
     362         470 :                 buildIndexArray(parenttbl->indexes,
     363             :                                 parenttbl->numIndexes,
     364             :                                 sizeof(IndxInfo));
     365             : 
     366        1052 :         attachinfo = (IndexAttachInfo *)
     367        1052 :             pg_malloc0(tblinfo[i].numIndexes * sizeof(IndexAttachInfo));
     368        1440 :         for (j = 0, k = 0; j < tblinfo[i].numIndexes; j++)
     369             :         {
     370         388 :             IndxInfo   *index = &(tblinfo[i].indexes[j]);
     371             :             IndxInfo   *parentidx;
     372             : 
     373         388 :             if (index->parentidx == 0)
     374          60 :                 continue;
     375             : 
     376         656 :             parentidx = findIndexByOid(index->parentidx,
     377         328 :                                        parentIndexArray[parenttbl->dobj.dumpId],
     378             :                                        parenttbl->numIndexes);
     379         328 :             if (parentidx == NULL)
     380           0 :                 continue;
     381             : 
     382         328 :             attachinfo[k].dobj.objType = DO_INDEX_ATTACH;
     383         328 :             attachinfo[k].dobj.catId.tableoid = 0;
     384         328 :             attachinfo[k].dobj.catId.oid = 0;
     385         328 :             AssignDumpId(&attachinfo[k].dobj);
     386         328 :             attachinfo[k].dobj.name = pg_strdup(index->dobj.name);
     387         328 :             attachinfo[k].dobj.namespace = index->indextable->dobj.namespace;
     388         328 :             attachinfo[k].parentIdx = parentidx;
     389         328 :             attachinfo[k].partitionIdx = index;
     390             : 
     391             :             /*
     392             :              * We must state the DO_INDEX_ATTACH object's dependencies
     393             :              * explicitly, since it will not match anything in pg_depend.
     394             :              *
     395             :              * Give it dependencies on both the partition index and the parent
     396             :              * index, so that it will not be executed till both of those
     397             :              * exist.  (There's no need to care what order those are created
     398             :              * in.)
     399             :              *
     400             :              * In addition, give it dependencies on the indexes' underlying
     401             :              * tables.  This does nothing of great value so far as serial
     402             :              * restore ordering goes, but it ensures that a parallel restore
     403             :              * will not try to run the ATTACH concurrently with other
     404             :              * operations on those tables.
     405             :              */
     406         328 :             addObjectDependency(&attachinfo[k].dobj, index->dobj.dumpId);
     407         328 :             addObjectDependency(&attachinfo[k].dobj, parentidx->dobj.dumpId);
     408         328 :             addObjectDependency(&attachinfo[k].dobj,
     409         328 :                                 index->indextable->dobj.dumpId);
     410         328 :             addObjectDependency(&attachinfo[k].dobj,
     411         328 :                                 parentidx->indextable->dobj.dumpId);
     412             : 
     413             :             /* keep track of the list of partitions in the parent index */
     414         328 :             simple_ptr_list_append(&parentidx->partattaches, &attachinfo[k].dobj);
     415             : 
     416         328 :             k++;
     417             :         }
     418             :     }
     419             : 
     420       35736 :     for (i = 0; i < numTables; i++)
     421       35580 :         if (parentIndexArray[i])
     422         386 :             pg_free(parentIndexArray[i]);
     423         156 :     pg_free(parentIndexArray);
     424         156 : }
     425             : 
     426             : /* flagInhAttrs -
     427             :  *   for each dumpable table in tblinfo, flag its inherited attributes
     428             :  *
     429             :  * What we need to do here is detect child columns that inherit NOT NULL
     430             :  * bits from their parents (so that we needn't specify that again for the
     431             :  * child) and child columns that have DEFAULT NULL when their parents had
     432             :  * some non-null default.  In the latter case, we make up a dummy AttrDefInfo
     433             :  * object so that we'll correctly emit the necessary DEFAULT NULL clause;
     434             :  * otherwise the backend will apply an inherited default to the column.
     435             :  *
     436             :  * modifies tblinfo
     437             :  */
     438             : static void
     439         156 : flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
     440             : {
     441             :     int         i,
     442             :                 j,
     443             :                 k;
     444             : 
     445       35736 :     for (i = 0; i < numTables; i++)
     446             :     {
     447       35580 :         TableInfo  *tbinfo = &(tblinfo[i]);
     448             :         int         numParents;
     449             :         TableInfo **parents;
     450             : 
     451             :         /* Some kinds never have parents */
     452       70630 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
     453       50440 :             tbinfo->relkind == RELKIND_VIEW ||
     454       15390 :             tbinfo->relkind == RELKIND_MATVIEW)
     455       20638 :             continue;
     456             : 
     457             :         /* Don't bother computing anything for non-target tables, either */
     458       14942 :         if (!tbinfo->dobj.dump)
     459       10754 :             continue;
     460             : 
     461        4188 :         numParents = tbinfo->numParents;
     462        4188 :         parents = tbinfo->parents;
     463             : 
     464        4188 :         if (numParents == 0)
     465        2884 :             continue;           /* nothing to see here, move along */
     466             : 
     467             :         /* For each column, search for matching column names in parent(s) */
     468        4792 :         for (j = 0; j < tbinfo->numatts; j++)
     469             :         {
     470             :             bool        foundNotNull;   /* Attr was NOT NULL in a parent */
     471             :             bool        foundDefault;   /* Found a default in a parent */
     472             : 
     473             :             /* no point in examining dropped columns */
     474        3488 :             if (tbinfo->attisdropped[j])
     475         360 :                 continue;
     476             : 
     477        3128 :             foundNotNull = false;
     478        3128 :             foundDefault = false;
     479        6382 :             for (k = 0; k < numParents; k++)
     480             :             {
     481        3254 :                 TableInfo  *parent = parents[k];
     482             :                 int         inhAttrInd;
     483             : 
     484        3254 :                 inhAttrInd = strInArray(tbinfo->attnames[j],
     485             :                                         parent->attnames,
     486             :                                         parent->numatts);
     487        3254 :                 if (inhAttrInd >= 0)
     488             :                 {
     489        3050 :                     foundNotNull |= parent->notnull[inhAttrInd];
     490        3050 :                     foundDefault |= (parent->attrdefs[inhAttrInd] != NULL);
     491             :                 }
     492             :             }
     493             : 
     494             :             /* Remember if we found inherited NOT NULL */
     495        3128 :             tbinfo->inhNotNull[j] = foundNotNull;
     496             : 
     497             :             /* Manufacture a DEFAULT NULL clause if necessary */
     498        3128 :             if (foundDefault && tbinfo->attrdefs[j] == NULL)
     499             :             {
     500             :                 AttrDefInfo *attrDef;
     501             : 
     502         108 :                 attrDef = (AttrDefInfo *) pg_malloc(sizeof(AttrDefInfo));
     503         108 :                 attrDef->dobj.objType = DO_ATTRDEF;
     504         108 :                 attrDef->dobj.catId.tableoid = 0;
     505         108 :                 attrDef->dobj.catId.oid = 0;
     506         108 :                 AssignDumpId(&attrDef->dobj);
     507         108 :                 attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
     508         108 :                 attrDef->dobj.namespace = tbinfo->dobj.namespace;
     509         108 :                 attrDef->dobj.dump = tbinfo->dobj.dump;
     510             : 
     511         108 :                 attrDef->adtable = tbinfo;
     512         108 :                 attrDef->adnum = j + 1;
     513         108 :                 attrDef->adef_expr = pg_strdup("NULL");
     514             : 
     515             :                 /* Will column be dumped explicitly? */
     516         108 :                 if (shouldPrintColumn(dopt, tbinfo, j))
     517             :                 {
     518         108 :                     attrDef->separate = false;
     519             :                     /* No dependency needed: NULL cannot have dependencies */
     520             :                 }
     521             :                 else
     522             :                 {
     523             :                     /* column will be suppressed, print default separately */
     524           0 :                     attrDef->separate = true;
     525             :                     /* ensure it comes out after the table */
     526           0 :                     addObjectDependency(&attrDef->dobj,
     527             :                                         tbinfo->dobj.dumpId);
     528             :                 }
     529             : 
     530         108 :                 tbinfo->attrdefs[j] = attrDef;
     531             :             }
     532             :         }
     533             :     }
     534         156 : }
     535             : 
     536             : /*
     537             :  * AssignDumpId
     538             :  *      Given a newly-created dumpable object, assign a dump ID,
     539             :  *      and enter the object into the lookup table.
     540             :  *
     541             :  * The caller is expected to have filled in objType and catId,
     542             :  * but not any of the other standard fields of a DumpableObject.
     543             :  */
     544             : void
     545      376818 : AssignDumpId(DumpableObject *dobj)
     546             : {
     547      376818 :     dobj->dumpId = ++lastDumpId;
     548      376818 :     dobj->name = NULL;           /* must be set later */
     549      376818 :     dobj->namespace = NULL;      /* may be set later */
     550      376818 :     dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
     551      376818 :     dobj->ext_member = false;    /* default assumption */
     552      376818 :     dobj->dependencies = NULL;
     553      376818 :     dobj->nDeps = 0;
     554      376818 :     dobj->allocDeps = 0;
     555             : 
     556      754424 :     while (dobj->dumpId >= allocedDumpIds)
     557             :     {
     558             :         int         newAlloc;
     559             : 
     560         788 :         if (allocedDumpIds <= 0)
     561             :         {
     562         158 :             newAlloc = 256;
     563         158 :             dumpIdMap = (DumpableObject **)
     564         158 :                 pg_malloc(newAlloc * sizeof(DumpableObject *));
     565             :         }
     566             :         else
     567             :         {
     568         630 :             newAlloc = allocedDumpIds * 2;
     569         630 :             dumpIdMap = (DumpableObject **)
     570         630 :                 pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
     571             :         }
     572         788 :         memset(dumpIdMap + allocedDumpIds, 0,
     573         788 :                (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
     574         788 :         allocedDumpIds = newAlloc;
     575             :     }
     576      376818 :     dumpIdMap[dobj->dumpId] = dobj;
     577             : 
     578             :     /* mark catalogIdMap invalid, but don't rebuild it yet */
     579      376818 :     catalogIdMapValid = false;
     580      376818 : }
     581             : 
     582             : /*
     583             :  * Assign a DumpId that's not tied to a DumpableObject.
     584             :  *
     585             :  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
     586             :  * participate in the sorting logic.
     587             :  */
     588             : DumpId
     589        4124 : createDumpId(void)
     590             : {
     591        4124 :     return ++lastDumpId;
     592             : }
     593             : 
     594             : /*
     595             :  * Return the largest DumpId so far assigned
     596             :  */
     597             : DumpId
     598        1338 : getMaxDumpId(void)
     599             : {
     600        1338 :     return lastDumpId;
     601             : }
     602             : 
     603             : /*
     604             :  * Find a DumpableObject by dump ID
     605             :  *
     606             :  * Returns NULL for invalid ID
     607             :  */
     608             : DumpableObject *
     609    10914478 : findObjectByDumpId(DumpId dumpId)
     610             : {
     611    10914478 :     if (dumpId <= 0 || dumpId >= allocedDumpIds)
     612           0 :         return NULL;            /* out of range? */
     613    10914478 :     return dumpIdMap[dumpId];
     614             : }
     615             : 
     616             : /*
     617             :  * Find a DumpableObject by catalog ID
     618             :  *
     619             :  * Returns NULL for unknown ID
     620             :  *
     621             :  * We use binary search in a sorted list that is built on first call.
     622             :  * If AssignDumpId() and findObjectByCatalogId() calls were freely intermixed,
     623             :  * the code would work, but possibly be very slow.  In the current usage
     624             :  * pattern that does not happen, indeed we build the list at most twice.
     625             :  */
     626             : DumpableObject *
     627      386282 : findObjectByCatalogId(CatalogId catalogId)
     628             : {
     629             :     DumpableObject **low;
     630             :     DumpableObject **high;
     631             : 
     632      386282 :     if (!catalogIdMapValid)
     633             :     {
     634         202 :         if (catalogIdMap)
     635          46 :             free(catalogIdMap);
     636         202 :         getDumpableObjects(&catalogIdMap, &numCatalogIds);
     637         202 :         if (numCatalogIds > 1)
     638         202 :             qsort((void *) catalogIdMap, numCatalogIds,
     639             :                   sizeof(DumpableObject *), DOCatalogIdCompare);
     640         202 :         catalogIdMapValid = true;
     641             :     }
     642             : 
     643             :     /*
     644             :      * We could use bsearch() here, but the notational cruft of calling
     645             :      * bsearch is nearly as bad as doing it ourselves; and the generalized
     646             :      * bsearch function is noticeably slower as well.
     647             :      */
     648      386282 :     if (numCatalogIds <= 0)
     649           0 :         return NULL;
     650      386282 :     low = catalogIdMap;
     651      386282 :     high = catalogIdMap + (numCatalogIds - 1);
     652     4474148 :     while (low <= high)
     653             :     {
     654             :         DumpableObject **middle;
     655             :         int         difference;
     656             : 
     657     4073662 :         middle = low + (high - low) / 2;
     658             :         /* comparison must match DOCatalogIdCompare, below */
     659     4073662 :         difference = oidcmp((*middle)->catId.oid, catalogId.oid);
     660     4073662 :         if (difference == 0)
     661      383848 :             difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid);
     662     4073662 :         if (difference == 0)
     663      372078 :             return *middle;
     664     3701584 :         else if (difference < 0)
     665     2219618 :             low = middle + 1;
     666             :         else
     667     1481966 :             high = middle - 1;
     668             :     }
     669       14204 :     return NULL;
     670             : }
     671             : 
     672             : /*
     673             :  * Find a DumpableObject by OID, in a pre-sorted array of one type of object
     674             :  *
     675             :  * Returns NULL for unknown OID
     676             :  */
     677             : static DumpableObject *
     678      438952 : findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
     679             : {
     680             :     DumpableObject **low;
     681             :     DumpableObject **high;
     682             : 
     683             :     /*
     684             :      * This is the same as findObjectByCatalogId except we assume we need not
     685             :      * look at table OID because the objects are all the same type.
     686             :      *
     687             :      * We could use bsearch() here, but the notational cruft of calling
     688             :      * bsearch is nearly as bad as doing it ourselves; and the generalized
     689             :      * bsearch function is noticeably slower as well.
     690             :      */
     691      438952 :     if (numObjs <= 0)
     692           0 :         return NULL;
     693      438952 :     low = indexArray;
     694      438952 :     high = indexArray + (numObjs - 1);
     695     2303810 :     while (low <= high)
     696             :     {
     697             :         DumpableObject **middle;
     698             :         int         difference;
     699             : 
     700     1857196 :         middle = low + (high - low) / 2;
     701     1857196 :         difference = oidcmp((*middle)->catId.oid, oid);
     702     1857196 :         if (difference == 0)
     703      431290 :             return *middle;
     704     1425906 :         else if (difference < 0)
     705      444086 :             low = middle + 1;
     706             :         else
     707      981820 :             high = middle - 1;
     708             :     }
     709        7662 :     return NULL;
     710             : }
     711             : 
     712             : /*
     713             :  * Build an index array of DumpableObject pointers, sorted by OID
     714             :  */
     715             : static DumpableObject **
     716        1566 : buildIndexArray(void *objArray, int numObjs, Size objSize)
     717             : {
     718             :     DumpableObject **ptrs;
     719             :     int         i;
     720             : 
     721        1566 :     ptrs = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
     722      241068 :     for (i = 0; i < numObjs; i++)
     723      239502 :         ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize);
     724             : 
     725             :     /* We can use DOCatalogIdCompare to sort since its first key is OID */
     726        1566 :     if (numObjs > 1)
     727        1020 :         qsort((void *) ptrs, numObjs, sizeof(DumpableObject *),
     728             :               DOCatalogIdCompare);
     729             : 
     730        1566 :     return ptrs;
     731             : }
     732             : 
     733             : /*
     734             :  * qsort comparator for pointers to DumpableObjects
     735             :  */
     736             : static int
     737     7945426 : DOCatalogIdCompare(const void *p1, const void *p2)
     738             : {
     739     7945426 :     const DumpableObject *obj1 = *(DumpableObject *const *) p1;
     740     7945426 :     const DumpableObject *obj2 = *(DumpableObject *const *) p2;
     741             :     int         cmpval;
     742             : 
     743             :     /*
     744             :      * Compare OID first since it's usually unique, whereas there will only be
     745             :      * a few distinct values of tableoid.
     746             :      */
     747     7945426 :     cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
     748     7945426 :     if (cmpval == 0)
     749       19098 :         cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
     750     7945426 :     return cmpval;
     751             : }
     752             : 
     753             : /*
     754             :  * Build an array of pointers to all known dumpable objects
     755             :  *
     756             :  * This simply creates a modifiable copy of the internal map.
     757             :  */
     758             : void
     759         366 : getDumpableObjects(DumpableObject ***objs, int *numObjs)
     760             : {
     761             :     int         i,
     762             :                 j;
     763             : 
     764         366 :     *objs = (DumpableObject **)
     765         366 :         pg_malloc(allocedDumpIds * sizeof(DumpableObject *));
     766         366 :     j = 0;
     767     1564672 :     for (i = 1; i < allocedDumpIds; i++)
     768             :     {
     769     1564306 :         if (dumpIdMap[i])
     770      897780 :             (*objs)[j++] = dumpIdMap[i];
     771             :     }
     772         366 :     *numObjs = j;
     773         366 : }
     774             : 
     775             : /*
     776             :  * Add a dependency link to a DumpableObject
     777             :  *
     778             :  * Note: duplicate dependencies are currently not eliminated
     779             :  */
     780             : void
     781      668412 : addObjectDependency(DumpableObject *dobj, DumpId refId)
     782             : {
     783      668412 :     if (dobj->nDeps >= dobj->allocDeps)
     784             :     {
     785      105132 :         if (dobj->allocDeps <= 0)
     786             :         {
     787      101368 :             dobj->allocDeps = 16;
     788      101368 :             dobj->dependencies = (DumpId *)
     789      101368 :                 pg_malloc(dobj->allocDeps * sizeof(DumpId));
     790             :         }
     791             :         else
     792             :         {
     793        3764 :             dobj->allocDeps *= 2;
     794        3764 :             dobj->dependencies = (DumpId *)
     795        3764 :                 pg_realloc(dobj->dependencies,
     796        3764 :                            dobj->allocDeps * sizeof(DumpId));
     797             :         }
     798             :     }
     799      668412 :     dobj->dependencies[dobj->nDeps++] = refId;
     800      668412 : }
     801             : 
     802             : /*
     803             :  * Remove a dependency link from a DumpableObject
     804             :  *
     805             :  * If there are multiple links, all are removed
     806             :  */
     807             : void
     808       22174 : removeObjectDependency(DumpableObject *dobj, DumpId refId)
     809             : {
     810             :     int         i;
     811       22174 :     int         j = 0;
     812             : 
     813      129106 :     for (i = 0; i < dobj->nDeps; i++)
     814             :     {
     815      106932 :         if (dobj->dependencies[i] != refId)
     816       64026 :             dobj->dependencies[j++] = dobj->dependencies[i];
     817             :     }
     818       22174 :     dobj->nDeps = j;
     819       22174 : }
     820             : 
     821             : 
     822             : /*
     823             :  * findTableByOid
     824             :  *    finds the entry (in tblinfo) of the table with the given oid
     825             :  *    returns NULL if not found
     826             :  */
     827             : TableInfo *
     828       65702 : findTableByOid(Oid oid)
     829             : {
     830       65702 :     return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
     831             : }
     832             : 
     833             : /*
     834             :  * findTypeByOid
     835             :  *    finds the entry (in typinfo) of the type with the given oid
     836             :  *    returns NULL if not found
     837             :  */
     838             : TypeInfo *
     839       67744 : findTypeByOid(Oid oid)
     840             : {
     841       67744 :     return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
     842             : }
     843             : 
     844             : /*
     845             :  * findFuncByOid
     846             :  *    finds the entry (in funinfo) of the function with the given oid
     847             :  *    returns NULL if not found
     848             :  */
     849             : FuncInfo *
     850         342 : findFuncByOid(Oid oid)
     851             : {
     852         342 :     return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
     853             : }
     854             : 
     855             : /*
     856             :  * findOprByOid
     857             :  *    finds the entry (in oprinfo) of the operator with the given oid
     858             :  *    returns NULL if not found
     859             :  */
     860             : OprInfo *
     861          30 : findOprByOid(Oid oid)
     862             : {
     863          30 :     return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
     864             : }
     865             : 
     866             : /*
     867             :  * findCollationByOid
     868             :  *    finds the entry (in collinfo) of the collation with the given oid
     869             :  *    returns NULL if not found
     870             :  */
     871             : CollInfo *
     872         346 : findCollationByOid(Oid oid)
     873             : {
     874         346 :     return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations);
     875             : }
     876             : 
     877             : /*
     878             :  * findNamespaceByOid
     879             :  *    finds the entry (in nspinfo) of the namespace with the given oid
     880             :  *    returns NULL if not found
     881             :  */
     882             : NamespaceInfo *
     883      304270 : findNamespaceByOid(Oid oid)
     884             : {
     885      304270 :     return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
     886             : }
     887             : 
     888             : /*
     889             :  * findExtensionByOid
     890             :  *    finds the entry (in extinfo) of the extension with the given oid
     891             :  *    returns NULL if not found
     892             :  */
     893             : ExtensionInfo *
     894         190 : findExtensionByOid(Oid oid)
     895             : {
     896         190 :     return (ExtensionInfo *) findObjectByOid(oid, extinfoindex, numExtensions);
     897             : }
     898             : 
     899             : /*
     900             :  * findIndexByOid
     901             :  *      find the entry of the index with the given oid
     902             :  *
     903             :  * This one's signature is different from the previous ones because we lack a
     904             :  * global array of all indexes, so caller must pass their array as argument.
     905             :  */
     906             : static IndxInfo *
     907         328 : findIndexByOid(Oid oid, DumpableObject **idxinfoindex, int numIndexes)
     908             : {
     909         328 :     return (IndxInfo *) findObjectByOid(oid, idxinfoindex, numIndexes);
     910             : }
     911             : 
     912             : /*
     913             :  * setExtensionMembership
     914             :  *    accept and save data about which objects belong to extensions
     915             :  */
     916             : void
     917         158 : setExtensionMembership(ExtensionMemberId *extmems, int nextmems)
     918             : {
     919             :     /* Sort array in preparation for binary searches */
     920         158 :     if (nextmems > 1)
     921         158 :         qsort((void *) extmems, nextmems, sizeof(ExtensionMemberId),
     922             :               ExtensionMemberIdCompare);
     923             :     /* And save */
     924         158 :     extmembers = extmems;
     925         158 :     numextmembers = nextmems;
     926         158 : }
     927             : 
     928             : /*
     929             :  * findOwningExtension
     930             :  *    return owning extension for specified catalog ID, or NULL if none
     931             :  */
     932             : ExtensionInfo *
     933      298124 : findOwningExtension(CatalogId catalogId)
     934             : {
     935             :     ExtensionMemberId *low;
     936             :     ExtensionMemberId *high;
     937             : 
     938             :     /*
     939             :      * We could use bsearch() here, but the notational cruft of calling
     940             :      * bsearch is nearly as bad as doing it ourselves; and the generalized
     941             :      * bsearch function is noticeably slower as well.
     942             :      */
     943      298124 :     if (numextmembers <= 0)
     944           0 :         return NULL;
     945      298124 :     low = extmembers;
     946      298124 :     high = extmembers + (numextmembers - 1);
     947     1324072 :     while (low <= high)
     948             :     {
     949             :         ExtensionMemberId *middle;
     950             :         int         difference;
     951             : 
     952      728412 :         middle = low + (high - low) / 2;
     953             :         /* comparison must match ExtensionMemberIdCompare, below */
     954      728412 :         difference = oidcmp(middle->catId.oid, catalogId.oid);
     955      728412 :         if (difference == 0)
     956         588 :             difference = oidcmp(middle->catId.tableoid, catalogId.tableoid);
     957      728412 :         if (difference == 0)
     958         588 :             return middle->ext;
     959      727824 :         else if (difference < 0)
     960       48812 :             low = middle + 1;
     961             :         else
     962      679012 :             high = middle - 1;
     963             :     }
     964      297536 :     return NULL;
     965             : }
     966             : 
     967             : /*
     968             :  * qsort comparator for ExtensionMemberIds
     969             :  */
     970             : static int
     971         858 : ExtensionMemberIdCompare(const void *p1, const void *p2)
     972             : {
     973         858 :     const ExtensionMemberId *obj1 = (const ExtensionMemberId *) p1;
     974         858 :     const ExtensionMemberId *obj2 = (const ExtensionMemberId *) p2;
     975             :     int         cmpval;
     976             : 
     977             :     /*
     978             :      * Compare OID first since it's usually unique, whereas there will only be
     979             :      * a few distinct values of tableoid.
     980             :      */
     981         858 :     cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
     982         858 :     if (cmpval == 0)
     983           0 :         cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
     984         858 :     return cmpval;
     985             : }
     986             : 
     987             : 
     988             : /*
     989             :  * findParentsByOid
     990             :  *    find a table's parents in tblinfo[]
     991             :  */
     992             : static void
     993        4188 : findParentsByOid(TableInfo *self,
     994             :                  InhInfo *inhinfo, int numInherits)
     995             : {
     996        4188 :     Oid         oid = self->dobj.catId.oid;
     997             :     int         i,
     998             :                 j;
     999             :     int         numParents;
    1000             : 
    1001        4188 :     numParents = 0;
    1002      746198 :     for (i = 0; i < numInherits; i++)
    1003             :     {
    1004      742010 :         if (inhinfo[i].inhrelid == oid)
    1005        1328 :             numParents++;
    1006             :     }
    1007             : 
    1008        4188 :     self->numParents = numParents;
    1009             : 
    1010        4188 :     if (numParents > 0)
    1011             :     {
    1012        1304 :         self->parents = (TableInfo **)
    1013        1304 :             pg_malloc(sizeof(TableInfo *) * numParents);
    1014        1304 :         j = 0;
    1015      274164 :         for (i = 0; i < numInherits; i++)
    1016             :         {
    1017      272860 :             if (inhinfo[i].inhrelid == oid)
    1018             :             {
    1019             :                 TableInfo  *parent;
    1020             : 
    1021        1328 :                 parent = findTableByOid(inhinfo[i].inhparent);
    1022        1328 :                 if (parent == NULL)
    1023             :                 {
    1024           0 :                     pg_log_error("failed sanity check, parent OID %u of table \"%s\" (OID %u) not found",
    1025             :                                  inhinfo[i].inhparent,
    1026             :                                  self->dobj.name,
    1027             :                                  oid);
    1028           0 :                     exit_nicely(1);
    1029             :                 }
    1030        1328 :                 self->parents[j++] = parent;
    1031             :             }
    1032             :         }
    1033             :     }
    1034             :     else
    1035        2884 :         self->parents = NULL;
    1036        4188 : }
    1037             : 
    1038             : /*
    1039             :  * parseOidArray
    1040             :  *    parse a string of numbers delimited by spaces into a character array
    1041             :  *
    1042             :  * Note: actually this is used for both Oids and potentially-signed
    1043             :  * attribute numbers.  This should cause no trouble, but we could split
    1044             :  * the function into two functions with different argument types if it does.
    1045             :  */
    1046             : 
    1047             : void
    1048        5102 : parseOidArray(const char *str, Oid *array, int arraysize)
    1049             : {
    1050             :     int         j,
    1051             :                 argNum;
    1052             :     char        temp[100];
    1053             :     char        s;
    1054             : 
    1055        5102 :     argNum = 0;
    1056        5102 :     j = 0;
    1057             :     for (;;)
    1058             :     {
    1059       43482 :         s = *str++;
    1060       24292 :         if (s == ' ' || s == '\0')
    1061             :         {
    1062        8036 :             if (j > 0)
    1063             :             {
    1064        8036 :                 if (argNum >= arraysize)
    1065             :                 {
    1066           0 :                     pg_log_error("could not parse numeric array \"%s\": too many numbers", str);
    1067           0 :                     exit_nicely(1);
    1068             :                 }
    1069        8036 :                 temp[j] = '\0';
    1070        8036 :                 array[argNum++] = atooid(temp);
    1071        8036 :                 j = 0;
    1072             :             }
    1073       10970 :             if (s == '\0')
    1074        5102 :                 break;
    1075             :         }
    1076             :         else
    1077             :         {
    1078       32512 :             if (!(isdigit((unsigned char) s) || s == '-') ||
    1079       16256 :                 j >= sizeof(temp) - 1)
    1080             :             {
    1081           0 :                 pg_log_error("could not parse numeric array \"%s\": invalid character in number", str);
    1082           0 :                 exit_nicely(1);
    1083             :             }
    1084       16256 :             temp[j++] = s;
    1085             :         }
    1086             :     }
    1087             : 
    1088       10204 :     while (argNum < arraysize)
    1089           0 :         array[argNum++] = InvalidOid;
    1090        5102 : }
    1091             : 
    1092             : 
    1093             : /*
    1094             :  * strInArray:
    1095             :  *    takes in a string and a string array and the number of elements in the
    1096             :  * string array.
    1097             :  *    returns the index if the string is somewhere in the array, -1 otherwise
    1098             :  */
    1099             : 
    1100             : static int
    1101        3254 : strInArray(const char *pattern, char **arr, int arr_size)
    1102             : {
    1103             :     int         i;
    1104             : 
    1105        6578 :     for (i = 0; i < arr_size; i++)
    1106             :     {
    1107        6374 :         if (strcmp(pattern, arr[i]) == 0)
    1108        3050 :             return i;
    1109             :     }
    1110         204 :     return -1;
    1111             : }

Generated by: LCOV version 1.13