LCOV - code coverage report
Current view: top level - src/bin/pg_dump - common.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 380 396 96.0 %
Date: 2020-05-31 23:07:13 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-2020, 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         162 : 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         162 :     pg_log_info("reading extensions");
     122         162 :     extinfo = getExtensions(fout, &numExtensions);
     123         162 :     extinfoindex = buildIndexArray(extinfo, numExtensions, sizeof(ExtensionInfo));
     124             : 
     125         162 :     pg_log_info("identifying extension members");
     126         162 :     getExtensionMembership(fout, extinfo, numExtensions);
     127             : 
     128         162 :     pg_log_info("reading schemas");
     129         162 :     nspinfo = getNamespaces(fout, &numNamespaces);
     130         162 :     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         162 :     pg_log_info("reading user-defined tables");
     139         162 :     tblinfo = getTables(fout, &numTables);
     140         160 :     tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo));
     141             : 
     142             :     /* Do this after we've built tblinfoindex */
     143         160 :     getOwnedSeqs(fout, tblinfo, numTables);
     144             : 
     145         160 :     pg_log_info("reading user-defined functions");
     146         160 :     funinfo = getFuncs(fout, &numFuncs);
     147         160 :     funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo));
     148             : 
     149             :     /* this must be after getTables and getFuncs */
     150         160 :     pg_log_info("reading user-defined types");
     151         160 :     typinfo = getTypes(fout, &numTypes);
     152         160 :     typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo));
     153             : 
     154             :     /* this must be after getFuncs, too */
     155         160 :     pg_log_info("reading procedural languages");
     156         160 :     getProcLangs(fout, &numProcLangs);
     157             : 
     158         160 :     pg_log_info("reading user-defined aggregate functions");
     159         160 :     getAggregates(fout, &numAggregates);
     160             : 
     161         160 :     pg_log_info("reading user-defined operators");
     162         160 :     oprinfo = getOperators(fout, &numOperators);
     163         160 :     oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
     164             : 
     165         160 :     pg_log_info("reading user-defined access methods");
     166         160 :     getAccessMethods(fout, &numAccessMethods);
     167             : 
     168         160 :     pg_log_info("reading user-defined operator classes");
     169         160 :     getOpclasses(fout, &numOpclasses);
     170             : 
     171         160 :     pg_log_info("reading user-defined operator families");
     172         160 :     getOpfamilies(fout, &numOpfamilies);
     173             : 
     174         160 :     pg_log_info("reading user-defined text search parsers");
     175         160 :     getTSParsers(fout, &numTSParsers);
     176             : 
     177         160 :     pg_log_info("reading user-defined text search templates");
     178         160 :     getTSTemplates(fout, &numTSTemplates);
     179             : 
     180         160 :     pg_log_info("reading user-defined text search dictionaries");
     181         160 :     getTSDictionaries(fout, &numTSDicts);
     182             : 
     183         160 :     pg_log_info("reading user-defined text search configurations");
     184         160 :     getTSConfigurations(fout, &numTSConfigs);
     185             : 
     186         160 :     pg_log_info("reading user-defined foreign-data wrappers");
     187         160 :     getForeignDataWrappers(fout, &numForeignDataWrappers);
     188             : 
     189         160 :     pg_log_info("reading user-defined foreign servers");
     190         160 :     getForeignServers(fout, &numForeignServers);
     191             : 
     192         160 :     pg_log_info("reading default privileges");
     193         160 :     getDefaultACLs(fout, &numDefaultACLs);
     194             : 
     195         160 :     pg_log_info("reading user-defined collations");
     196         160 :     collinfo = getCollations(fout, &numCollations);
     197         160 :     collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
     198             : 
     199         160 :     pg_log_info("reading user-defined conversions");
     200         160 :     getConversions(fout, &numConversions);
     201             : 
     202         160 :     pg_log_info("reading type casts");
     203         160 :     getCasts(fout, &numCasts);
     204             : 
     205         160 :     pg_log_info("reading transforms");
     206         160 :     getTransforms(fout, &numTransforms);
     207             : 
     208         160 :     pg_log_info("reading table inheritance information");
     209         160 :     inhinfo = getInherits(fout, &numInherits);
     210             : 
     211         160 :     pg_log_info("reading event triggers");
     212         160 :     getEventTriggers(fout, &numEventTriggers);
     213             : 
     214             :     /* Identify extension configuration tables that should be dumped */
     215         160 :     pg_log_info("finding extension tables");
     216         160 :     processExtensionTables(fout, extinfo, numExtensions);
     217             : 
     218             :     /* Link tables to parents, mark parents of target tables interesting */
     219         160 :     pg_log_info("finding inheritance relationships");
     220         160 :     flagInhTables(fout, tblinfo, numTables, inhinfo, numInherits);
     221             : 
     222         160 :     pg_log_info("reading column info for interesting tables");
     223         160 :     getTableAttrs(fout, tblinfo, numTables);
     224             : 
     225         160 :     pg_log_info("flagging inherited columns in subtables");
     226         160 :     flagInhAttrs(fout->dopt, tblinfo, numTables);
     227             : 
     228         160 :     pg_log_info("reading indexes");
     229         160 :     getIndexes(fout, tblinfo, numTables);
     230             : 
     231         160 :     pg_log_info("flagging indexes in partitioned tables");
     232         160 :     flagInhIndexes(fout, tblinfo, numTables);
     233             : 
     234         160 :     pg_log_info("reading extended statistics");
     235         160 :     getExtendedStatistics(fout);
     236             : 
     237         160 :     pg_log_info("reading constraints");
     238         160 :     getConstraints(fout, tblinfo, numTables);
     239             : 
     240         160 :     pg_log_info("reading triggers");
     241         160 :     getTriggers(fout, tblinfo, numTables);
     242             : 
     243         160 :     pg_log_info("reading rewrite rules");
     244         160 :     getRules(fout, &numRules);
     245             : 
     246         160 :     pg_log_info("reading policies");
     247         160 :     getPolicies(fout, tblinfo, numTables);
     248             : 
     249         160 :     pg_log_info("reading publications");
     250         160 :     getPublications(fout);
     251             : 
     252         160 :     pg_log_info("reading publication membership");
     253         160 :     getPublicationTables(fout, tblinfo, numTables);
     254             : 
     255         160 :     pg_log_info("reading subscriptions");
     256         160 :     getSubscriptions(fout);
     257             : 
     258         160 :     *numTablesPtr = numTables;
     259         160 :     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         160 : flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
     274             :               InhInfo *inhinfo, int numInherits)
     275             : {
     276         160 :     DumpOptions *dopt = fout->dopt;
     277             :     int         i,
     278             :                 j;
     279             : 
     280       37246 :     for (i = 0; i < numTables; i++)
     281             :     {
     282       37086 :         bool        find_parents = true;
     283       37086 :         bool        mark_parents = true;
     284             : 
     285             :         /* Some kinds never have parents */
     286       37086 :         if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
     287       36556 :             tblinfo[i].relkind == RELKIND_VIEW ||
     288       15736 :             tblinfo[i].relkind == RELKIND_MATVIEW)
     289       21798 :             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       15288 :         if (!tblinfo[i].dobj.dump)
     299             :         {
     300       10862 :             mark_parents = false;
     301             : 
     302       10862 :             if (!dopt->load_via_partition_root ||
     303           0 :                 !tblinfo[i].ispartition)
     304       10862 :                 find_parents = false;
     305             :         }
     306             : 
     307             :         /* If needed, find all the immediate parent tables. */
     308       15288 :         if (find_parents)
     309        4426 :             findParentsByOid(&tblinfo[i], inhinfo, numInherits);
     310             : 
     311             :         /*
     312             :          * If needed, mark the parents as interesting for getTableAttrs and
     313             :          * getIndexes.
     314             :          */
     315       15288 :         if (mark_parents)
     316             :         {
     317        4426 :             int         numParents = tblinfo[i].numParents;
     318        4426 :             TableInfo **parents = tblinfo[i].parents;
     319             : 
     320        5886 :             for (j = 0; j < numParents; j++)
     321        1460 :                 parents[j]->interesting = true;
     322             :         }
     323             :     }
     324         160 : }
     325             : 
     326             : /*
     327             :  * flagInhIndexes -
     328             :  *   Create IndexAttachInfo objects for partitioned indexes, and add
     329             :  *   appropriate dependency links.
     330             :  */
     331             : static void
     332         160 : flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
     333             : {
     334             :     int         i,
     335             :                 j,
     336             :                 k;
     337             :     DumpableObject ***parentIndexArray;
     338             : 
     339             :     parentIndexArray = (DumpableObject ***)
     340         160 :         pg_malloc0(getMaxDumpId() * sizeof(DumpableObject **));
     341             : 
     342       37246 :     for (i = 0; i < numTables; i++)
     343             :     {
     344             :         TableInfo  *parenttbl;
     345             :         IndexAttachInfo *attachinfo;
     346             : 
     347       37086 :         if (!tblinfo[i].ispartition || tblinfo[i].numParents == 0)
     348       35914 :             continue;
     349             : 
     350             :         Assert(tblinfo[i].numParents == 1);
     351        1172 :         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        1172 :         if (parentIndexArray[parenttbl->dobj.dumpId] == NULL)
     361         524 :             parentIndexArray[parenttbl->dobj.dumpId] =
     362         524 :                 buildIndexArray(parenttbl->indexes,
     363             :                                 parenttbl->numIndexes,
     364             :                                 sizeof(IndxInfo));
     365             : 
     366             :         attachinfo = (IndexAttachInfo *)
     367        1172 :             pg_malloc0(tblinfo[i].numIndexes * sizeof(IndexAttachInfo));
     368        1572 :         for (j = 0, k = 0; j < tblinfo[i].numIndexes; j++)
     369             :         {
     370         400 :             IndxInfo   *index = &(tblinfo[i].indexes[j]);
     371             :             IndxInfo   *parentidx;
     372             : 
     373         400 :             if (index->parentidx == 0)
     374          60 :                 continue;
     375             : 
     376         680 :             parentidx = findIndexByOid(index->parentidx,
     377         340 :                                        parentIndexArray[parenttbl->dobj.dumpId],
     378             :                                        parenttbl->numIndexes);
     379         340 :             if (parentidx == NULL)
     380           0 :                 continue;
     381             : 
     382         340 :             attachinfo[k].dobj.objType = DO_INDEX_ATTACH;
     383         340 :             attachinfo[k].dobj.catId.tableoid = 0;
     384         340 :             attachinfo[k].dobj.catId.oid = 0;
     385         340 :             AssignDumpId(&attachinfo[k].dobj);
     386         340 :             attachinfo[k].dobj.name = pg_strdup(index->dobj.name);
     387         340 :             attachinfo[k].dobj.namespace = index->indextable->dobj.namespace;
     388         340 :             attachinfo[k].parentIdx = parentidx;
     389         340 :             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         340 :             addObjectDependency(&attachinfo[k].dobj, index->dobj.dumpId);
     407         340 :             addObjectDependency(&attachinfo[k].dobj, parentidx->dobj.dumpId);
     408         340 :             addObjectDependency(&attachinfo[k].dobj,
     409         340 :                                 index->indextable->dobj.dumpId);
     410         340 :             addObjectDependency(&attachinfo[k].dobj,
     411         340 :                                 parentidx->indextable->dobj.dumpId);
     412             : 
     413             :             /* keep track of the list of partitions in the parent index */
     414         340 :             simple_ptr_list_append(&parentidx->partattaches, &attachinfo[k].dobj);
     415             : 
     416         340 :             k++;
     417             :         }
     418             :     }
     419             : 
     420       37246 :     for (i = 0; i < numTables; i++)
     421       37086 :         if (parentIndexArray[i])
     422         442 :             pg_free(parentIndexArray[i]);
     423         160 :     pg_free(parentIndexArray);
     424         160 : }
     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         160 : flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
     440             : {
     441             :     int         i,
     442             :                 j,
     443             :                 k;
     444             : 
     445       37246 :     for (i = 0; i < numTables; i++)
     446             :     {
     447       37086 :         TableInfo  *tbinfo = &(tblinfo[i]);
     448             :         int         numParents;
     449             :         TableInfo **parents;
     450             : 
     451             :         /* Some kinds never have parents */
     452       37086 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
     453       36556 :             tbinfo->relkind == RELKIND_VIEW ||
     454       15736 :             tbinfo->relkind == RELKIND_MATVIEW)
     455       21798 :             continue;
     456             : 
     457             :         /* Don't bother computing anything for non-target tables, either */
     458       15288 :         if (!tbinfo->dobj.dump)
     459       10862 :             continue;
     460             : 
     461        4426 :         numParents = tbinfo->numParents;
     462        4426 :         parents = tbinfo->parents;
     463             : 
     464        4426 :         if (numParents == 0)
     465        2990 :             continue;           /* nothing to see here, move along */
     466             : 
     467             :         /* For each column, search for matching column names in parent(s) */
     468        5278 :         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        3842 :             if (tbinfo->attisdropped[j])
     475         366 :                 continue;
     476             : 
     477        3476 :             foundNotNull = false;
     478        3476 :             foundDefault = false;
     479        7078 :             for (k = 0; k < numParents; k++)
     480             :             {
     481        3602 :                 TableInfo  *parent = parents[k];
     482             :                 int         inhAttrInd;
     483             : 
     484        3602 :                 inhAttrInd = strInArray(tbinfo->attnames[j],
     485             :                                         parent->attnames,
     486             :                                         parent->numatts);
     487        3602 :                 if (inhAttrInd >= 0)
     488             :                 {
     489        3398 :                     foundNotNull |= parent->notnull[inhAttrInd];
     490        3398 :                     foundDefault |= (parent->attrdefs[inhAttrInd] != NULL);
     491             :                 }
     492             :             }
     493             : 
     494             :             /* Remember if we found inherited NOT NULL */
     495        3476 :             tbinfo->inhNotNull[j] = foundNotNull;
     496             : 
     497             :             /* Manufacture a DEFAULT NULL clause if necessary */
     498        3476 :             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         160 : }
     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      392582 : AssignDumpId(DumpableObject *dobj)
     546             : {
     547      392582 :     dobj->dumpId = ++lastDumpId;
     548      392582 :     dobj->name = NULL;           /* must be set later */
     549      392582 :     dobj->namespace = NULL;      /* may be set later */
     550      392582 :     dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
     551      392582 :     dobj->ext_member = false;    /* default assumption */
     552      392582 :     dobj->depends_on_ext = false;    /* default assumption */
     553      392582 :     dobj->dependencies = NULL;
     554      392582 :     dobj->nDeps = 0;
     555      392582 :     dobj->allocDeps = 0;
     556             : 
     557      393390 :     while (dobj->dumpId >= allocedDumpIds)
     558             :     {
     559             :         int         newAlloc;
     560             : 
     561         808 :         if (allocedDumpIds <= 0)
     562             :         {
     563         162 :             newAlloc = 256;
     564         162 :             dumpIdMap = (DumpableObject **)
     565         162 :                 pg_malloc(newAlloc * sizeof(DumpableObject *));
     566             :         }
     567             :         else
     568             :         {
     569         646 :             newAlloc = allocedDumpIds * 2;
     570         646 :             dumpIdMap = (DumpableObject **)
     571         646 :                 pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
     572             :         }
     573         808 :         memset(dumpIdMap + allocedDumpIds, 0,
     574         808 :                (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
     575         808 :         allocedDumpIds = newAlloc;
     576             :     }
     577      392582 :     dumpIdMap[dobj->dumpId] = dobj;
     578             : 
     579             :     /* mark catalogIdMap invalid, but don't rebuild it yet */
     580      392582 :     catalogIdMapValid = false;
     581      392582 : }
     582             : 
     583             : /*
     584             :  * Assign a DumpId that's not tied to a DumpableObject.
     585             :  *
     586             :  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
     587             :  * participate in the sorting logic.
     588             :  */
     589             : DumpId
     590        4136 : createDumpId(void)
     591             : {
     592        4136 :     return ++lastDumpId;
     593             : }
     594             : 
     595             : /*
     596             :  * Return the largest DumpId so far assigned
     597             :  */
     598             : DumpId
     599        1376 : getMaxDumpId(void)
     600             : {
     601        1376 :     return lastDumpId;
     602             : }
     603             : 
     604             : /*
     605             :  * Find a DumpableObject by dump ID
     606             :  *
     607             :  * Returns NULL for invalid ID
     608             :  */
     609             : DumpableObject *
     610    11885978 : findObjectByDumpId(DumpId dumpId)
     611             : {
     612    11885978 :     if (dumpId <= 0 || dumpId >= allocedDumpIds)
     613           0 :         return NULL;            /* out of range? */
     614    11885978 :     return dumpIdMap[dumpId];
     615             : }
     616             : 
     617             : /*
     618             :  * Find a DumpableObject by catalog ID
     619             :  *
     620             :  * Returns NULL for unknown ID
     621             :  *
     622             :  * We use binary search in a sorted list that is built on first call.
     623             :  * If AssignDumpId() and findObjectByCatalogId() calls were freely intermixed,
     624             :  * the code would work, but possibly be very slow.  In the current usage
     625             :  * pattern that does not happen, indeed we build the list at most twice.
     626             :  */
     627             : DumpableObject *
     628      401386 : findObjectByCatalogId(CatalogId catalogId)
     629             : {
     630             :     DumpableObject **low;
     631             :     DumpableObject **high;
     632             : 
     633      401386 :     if (!catalogIdMapValid)
     634             :     {
     635         206 :         if (catalogIdMap)
     636          46 :             free(catalogIdMap);
     637         206 :         getDumpableObjects(&catalogIdMap, &numCatalogIds);
     638         206 :         if (numCatalogIds > 1)
     639         206 :             qsort((void *) catalogIdMap, numCatalogIds,
     640             :                   sizeof(DumpableObject *), DOCatalogIdCompare);
     641         206 :         catalogIdMapValid = true;
     642             :     }
     643             : 
     644             :     /*
     645             :      * We could use bsearch() here, but the notational cruft of calling
     646             :      * bsearch is nearly as bad as doing it ourselves; and the generalized
     647             :      * bsearch function is noticeably slower as well.
     648             :      */
     649      401386 :     if (numCatalogIds <= 0)
     650           0 :         return NULL;
     651      401386 :     low = catalogIdMap;
     652      401386 :     high = catalogIdMap + (numCatalogIds - 1);
     653     4278726 :     while (low <= high)
     654             :     {
     655             :         DumpableObject **middle;
     656             :         int         difference;
     657             : 
     658     4263702 :         middle = low + (high - low) / 2;
     659             :         /* comparison must match DOCatalogIdCompare, below */
     660     4263702 :         difference = oidcmp((*middle)->catId.oid, catalogId.oid);
     661     4263702 :         if (difference == 0)
     662      397572 :             difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid);
     663     4263702 :         if (difference == 0)
     664      386362 :             return *middle;
     665     3877340 :         else if (difference < 0)
     666     2294712 :             low = middle + 1;
     667             :         else
     668     1582628 :             high = middle - 1;
     669             :     }
     670       15024 :     return NULL;
     671             : }
     672             : 
     673             : /*
     674             :  * Find a DumpableObject by OID, in a pre-sorted array of one type of object
     675             :  *
     676             :  * Returns NULL for unknown OID
     677             :  */
     678             : static DumpableObject *
     679      458120 : findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
     680             : {
     681             :     DumpableObject **low;
     682             :     DumpableObject **high;
     683             : 
     684             :     /*
     685             :      * This is the same as findObjectByCatalogId except we assume we need not
     686             :      * look at table OID because the objects are all the same type.
     687             :      *
     688             :      * We could use bsearch() here, but the notational cruft of calling
     689             :      * bsearch is nearly as bad as doing it ourselves; and the generalized
     690             :      * bsearch function is noticeably slower as well.
     691             :      */
     692      458120 :     if (numObjs <= 0)
     693           0 :         return NULL;
     694      458120 :     low = indexArray;
     695      458120 :     high = indexArray + (numObjs - 1);
     696     1795014 :     while (low <= high)
     697             :     {
     698             :         DumpableObject **middle;
     699             :         int         difference;
     700             : 
     701     1787278 :         middle = low + (high - low) / 2;
     702     1787278 :         difference = oidcmp((*middle)->catId.oid, oid);
     703     1787278 :         if (difference == 0)
     704      450384 :             return *middle;
     705     1336894 :         else if (difference < 0)
     706      456666 :             low = middle + 1;
     707             :         else
     708      880228 :             high = middle - 1;
     709             :     }
     710        7736 :     return NULL;
     711             : }
     712             : 
     713             : /*
     714             :  * Build an index array of DumpableObject pointers, sorted by OID
     715             :  */
     716             : static DumpableObject **
     717        1648 : buildIndexArray(void *objArray, int numObjs, Size objSize)
     718             : {
     719             :     DumpableObject **ptrs;
     720             :     int         i;
     721             : 
     722        1648 :     ptrs = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
     723      250570 :     for (i = 0; i < numObjs; i++)
     724      248922 :         ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize);
     725             : 
     726             :     /* We can use DOCatalogIdCompare to sort since its first key is OID */
     727        1648 :     if (numObjs > 1)
     728        1044 :         qsort((void *) ptrs, numObjs, sizeof(DumpableObject *),
     729             :               DOCatalogIdCompare);
     730             : 
     731        1648 :     return ptrs;
     732             : }
     733             : 
     734             : /*
     735             :  * qsort comparator for pointers to DumpableObjects
     736             :  */
     737             : static int
     738     8234810 : DOCatalogIdCompare(const void *p1, const void *p2)
     739             : {
     740     8234810 :     const DumpableObject *obj1 = *(DumpableObject *const *) p1;
     741     8234810 :     const DumpableObject *obj2 = *(DumpableObject *const *) p2;
     742             :     int         cmpval;
     743             : 
     744             :     /*
     745             :      * Compare OID first since it's usually unique, whereas there will only be
     746             :      * a few distinct values of tableoid.
     747             :      */
     748     8234810 :     cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
     749     8234810 :     if (cmpval == 0)
     750       19700 :         cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
     751     8234810 :     return cmpval;
     752             : }
     753             : 
     754             : /*
     755             :  * Build an array of pointers to all known dumpable objects
     756             :  *
     757             :  * This simply creates a modifiable copy of the internal map.
     758             :  */
     759             : void
     760         376 : getDumpableObjects(DumpableObject ***objs, int *numObjs)
     761             : {
     762             :     int         i,
     763             :                 j;
     764             : 
     765         376 :     *objs = (DumpableObject **)
     766         376 :         pg_malloc(allocedDumpIds * sizeof(DumpableObject *));
     767         376 :     j = 0;
     768     1605632 :     for (i = 1; i < allocedDumpIds; i++)
     769             :     {
     770     1605256 :         if (dumpIdMap[i])
     771      936518 :             (*objs)[j++] = dumpIdMap[i];
     772             :     }
     773         376 :     *numObjs = j;
     774         376 : }
     775             : 
     776             : /*
     777             :  * Add a dependency link to a DumpableObject
     778             :  *
     779             :  * Note: duplicate dependencies are currently not eliminated
     780             :  */
     781             : void
     782      694704 : addObjectDependency(DumpableObject *dobj, DumpId refId)
     783             : {
     784      694704 :     if (dobj->nDeps >= dobj->allocDeps)
     785             :     {
     786      110338 :         if (dobj->allocDeps <= 0)
     787             :         {
     788      106414 :             dobj->allocDeps = 16;
     789      106414 :             dobj->dependencies = (DumpId *)
     790      106414 :                 pg_malloc(dobj->allocDeps * sizeof(DumpId));
     791             :         }
     792             :         else
     793             :         {
     794        3924 :             dobj->allocDeps *= 2;
     795        3924 :             dobj->dependencies = (DumpId *)
     796        3924 :                 pg_realloc(dobj->dependencies,
     797        3924 :                            dobj->allocDeps * sizeof(DumpId));
     798             :         }
     799             :     }
     800      694704 :     dobj->dependencies[dobj->nDeps++] = refId;
     801      694704 : }
     802             : 
     803             : /*
     804             :  * Remove a dependency link from a DumpableObject
     805             :  *
     806             :  * If there are multiple links, all are removed
     807             :  */
     808             : void
     809       23444 : removeObjectDependency(DumpableObject *dobj, DumpId refId)
     810             : {
     811             :     int         i;
     812       23444 :     int         j = 0;
     813             : 
     814      134882 :     for (i = 0; i < dobj->nDeps; i++)
     815             :     {
     816      111438 :         if (dobj->dependencies[i] != refId)
     817       66084 :             dobj->dependencies[j++] = dobj->dependencies[i];
     818             :     }
     819       23444 :     dobj->nDeps = j;
     820       23444 : }
     821             : 
     822             : 
     823             : /*
     824             :  * findTableByOid
     825             :  *    finds the entry (in tblinfo) of the table with the given oid
     826             :  *    returns NULL if not found
     827             :  */
     828             : TableInfo *
     829       68582 : findTableByOid(Oid oid)
     830             : {
     831       68582 :     return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
     832             : }
     833             : 
     834             : /*
     835             :  * findTypeByOid
     836             :  *    finds the entry (in typinfo) of the type with the given oid
     837             :  *    returns NULL if not found
     838             :  */
     839             : TypeInfo *
     840       72008 : findTypeByOid(Oid oid)
     841             : {
     842       72008 :     return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
     843             : }
     844             : 
     845             : /*
     846             :  * findFuncByOid
     847             :  *    finds the entry (in funinfo) of the function with the given oid
     848             :  *    returns NULL if not found
     849             :  */
     850             : FuncInfo *
     851         342 : findFuncByOid(Oid oid)
     852             : {
     853         342 :     return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
     854             : }
     855             : 
     856             : /*
     857             :  * findOprByOid
     858             :  *    finds the entry (in oprinfo) of the operator with the given oid
     859             :  *    returns NULL if not found
     860             :  */
     861             : OprInfo *
     862          30 : findOprByOid(Oid oid)
     863             : {
     864          30 :     return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
     865             : }
     866             : 
     867             : /*
     868             :  * findCollationByOid
     869             :  *    finds the entry (in collinfo) of the collation with the given oid
     870             :  *    returns NULL if not found
     871             :  */
     872             : CollInfo *
     873         346 : findCollationByOid(Oid oid)
     874             : {
     875         346 :     return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations);
     876             : }
     877             : 
     878             : /*
     879             :  * findNamespaceByOid
     880             :  *    finds the entry (in nspinfo) of the namespace with the given oid
     881             :  *    returns NULL if not found
     882             :  */
     883             : NamespaceInfo *
     884      316278 : findNamespaceByOid(Oid oid)
     885             : {
     886      316278 :     return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
     887             : }
     888             : 
     889             : /*
     890             :  * findExtensionByOid
     891             :  *    finds the entry (in extinfo) of the extension with the given oid
     892             :  *    returns NULL if not found
     893             :  */
     894             : ExtensionInfo *
     895         194 : findExtensionByOid(Oid oid)
     896             : {
     897         194 :     return (ExtensionInfo *) findObjectByOid(oid, extinfoindex, numExtensions);
     898             : }
     899             : 
     900             : /*
     901             :  * findIndexByOid
     902             :  *      find the entry of the index with the given oid
     903             :  *
     904             :  * This one's signature is different from the previous ones because we lack a
     905             :  * global array of all indexes, so caller must pass their array as argument.
     906             :  */
     907             : static IndxInfo *
     908         340 : findIndexByOid(Oid oid, DumpableObject **idxinfoindex, int numIndexes)
     909             : {
     910         340 :     return (IndxInfo *) findObjectByOid(oid, idxinfoindex, numIndexes);
     911             : }
     912             : 
     913             : /*
     914             :  * setExtensionMembership
     915             :  *    accept and save data about which objects belong to extensions
     916             :  */
     917             : void
     918         162 : setExtensionMembership(ExtensionMemberId *extmems, int nextmems)
     919             : {
     920             :     /* Sort array in preparation for binary searches */
     921         162 :     if (nextmems > 1)
     922         162 :         qsort((void *) extmems, nextmems, sizeof(ExtensionMemberId),
     923             :               ExtensionMemberIdCompare);
     924             :     /* And save */
     925         162 :     extmembers = extmems;
     926         162 :     numextmembers = nextmems;
     927         162 : }
     928             : 
     929             : /*
     930             :  * findOwningExtension
     931             :  *    return owning extension for specified catalog ID, or NULL if none
     932             :  */
     933             : ExtensionInfo *
     934      310452 : findOwningExtension(CatalogId catalogId)
     935             : {
     936             :     ExtensionMemberId *low;
     937             :     ExtensionMemberId *high;
     938             : 
     939             :     /*
     940             :      * We could use bsearch() here, but the notational cruft of calling
     941             :      * bsearch is nearly as bad as doing it ourselves; and the generalized
     942             :      * bsearch function is noticeably slower as well.
     943             :      */
     944      310452 :     if (numextmembers <= 0)
     945           0 :         return NULL;
     946      310452 :     low = extmembers;
     947      310452 :     high = extmembers + (numextmembers - 1);
     948     1065490 :     while (low <= high)
     949             :     {
     950             :         ExtensionMemberId *middle;
     951             :         int         difference;
     952             : 
     953      755630 :         middle = low + (high - low) / 2;
     954             :         /* comparison must match ExtensionMemberIdCompare, below */
     955      755630 :         difference = oidcmp(middle->catId.oid, catalogId.oid);
     956      755630 :         if (difference == 0)
     957         592 :             difference = oidcmp(middle->catId.tableoid, catalogId.tableoid);
     958      755630 :         if (difference == 0)
     959         592 :             return middle->ext;
     960      755038 :         else if (difference < 0)
     961       50862 :             low = middle + 1;
     962             :         else
     963      704176 :             high = middle - 1;
     964             :     }
     965      309860 :     return NULL;
     966             : }
     967             : 
     968             : /*
     969             :  * qsort comparator for ExtensionMemberIds
     970             :  */
     971             : static int
     972         870 : ExtensionMemberIdCompare(const void *p1, const void *p2)
     973             : {
     974         870 :     const ExtensionMemberId *obj1 = (const ExtensionMemberId *) p1;
     975         870 :     const ExtensionMemberId *obj2 = (const ExtensionMemberId *) p2;
     976             :     int         cmpval;
     977             : 
     978             :     /*
     979             :      * Compare OID first since it's usually unique, whereas there will only be
     980             :      * a few distinct values of tableoid.
     981             :      */
     982         870 :     cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
     983         870 :     if (cmpval == 0)
     984           0 :         cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
     985         870 :     return cmpval;
     986             : }
     987             : 
     988             : 
     989             : /*
     990             :  * findParentsByOid
     991             :  *    find a table's parents in tblinfo[]
     992             :  */
     993             : static void
     994        4426 : findParentsByOid(TableInfo *self,
     995             :                  InhInfo *inhinfo, int numInherits)
     996             : {
     997        4426 :     Oid         oid = self->dobj.catId.oid;
     998             :     int         i,
     999             :                 j;
    1000             :     int         numParents;
    1001             : 
    1002        4426 :     numParents = 0;
    1003      873030 :     for (i = 0; i < numInherits; i++)
    1004             :     {
    1005      868604 :         if (inhinfo[i].inhrelid == oid)
    1006        1460 :             numParents++;
    1007             :     }
    1008             : 
    1009        4426 :     self->numParents = numParents;
    1010             : 
    1011        4426 :     if (numParents > 0)
    1012             :     {
    1013        1436 :         self->parents = (TableInfo **)
    1014        1436 :             pg_malloc(sizeof(TableInfo *) * numParents);
    1015        1436 :         j = 0;
    1016      336276 :         for (i = 0; i < numInherits; i++)
    1017             :         {
    1018      334840 :             if (inhinfo[i].inhrelid == oid)
    1019             :             {
    1020             :                 TableInfo  *parent;
    1021             : 
    1022        1460 :                 parent = findTableByOid(inhinfo[i].inhparent);
    1023        1460 :                 if (parent == NULL)
    1024             :                 {
    1025           0 :                     pg_log_error("failed sanity check, parent OID %u of table \"%s\" (OID %u) not found",
    1026             :                                  inhinfo[i].inhparent,
    1027             :                                  self->dobj.name,
    1028             :                                  oid);
    1029           0 :                     exit_nicely(1);
    1030             :                 }
    1031        1460 :                 self->parents[j++] = parent;
    1032             :             }
    1033             :         }
    1034             :     }
    1035             :     else
    1036        2990 :         self->parents = NULL;
    1037        4426 : }
    1038             : 
    1039             : /*
    1040             :  * parseOidArray
    1041             :  *    parse a string of numbers delimited by spaces into a character array
    1042             :  *
    1043             :  * Note: actually this is used for both Oids and potentially-signed
    1044             :  * attribute numbers.  This should cause no trouble, but we could split
    1045             :  * the function into two functions with different argument types if it does.
    1046             :  */
    1047             : 
    1048             : void
    1049        5336 : parseOidArray(const char *str, Oid *array, int arraysize)
    1050             : {
    1051             :     int         j,
    1052             :                 argNum;
    1053             :     char        temp[100];
    1054             :     char        s;
    1055             : 
    1056        5336 :     argNum = 0;
    1057        5336 :     j = 0;
    1058             :     for (;;)
    1059             :     {
    1060       19734 :         s = *str++;
    1061       25070 :         if (s == ' ' || s == '\0')
    1062             :         {
    1063        8316 :             if (j > 0)
    1064             :             {
    1065        8316 :                 if (argNum >= arraysize)
    1066             :                 {
    1067           0 :                     pg_log_error("could not parse numeric array \"%s\": too many numbers", str);
    1068           0 :                     exit_nicely(1);
    1069             :                 }
    1070        8316 :                 temp[j] = '\0';
    1071        8316 :                 array[argNum++] = atooid(temp);
    1072        8316 :                 j = 0;
    1073             :             }
    1074        8316 :             if (s == '\0')
    1075        5336 :                 break;
    1076             :         }
    1077             :         else
    1078             :         {
    1079       16754 :             if (!(isdigit((unsigned char) s) || s == '-') ||
    1080       16754 :                 j >= sizeof(temp) - 1)
    1081             :             {
    1082           0 :                 pg_log_error("could not parse numeric array \"%s\": invalid character in number", str);
    1083           0 :                 exit_nicely(1);
    1084             :             }
    1085       16754 :             temp[j++] = s;
    1086             :         }
    1087             :     }
    1088             : 
    1089        5336 :     while (argNum < arraysize)
    1090           0 :         array[argNum++] = InvalidOid;
    1091        5336 : }
    1092             : 
    1093             : 
    1094             : /*
    1095             :  * strInArray:
    1096             :  *    takes in a string and a string array and the number of elements in the
    1097             :  * string array.
    1098             :  *    returns the index if the string is somewhere in the array, -1 otherwise
    1099             :  */
    1100             : 
    1101             : static int
    1102        3602 : strInArray(const char *pattern, char **arr, int arr_size)
    1103             : {
    1104             :     int         i;
    1105             : 
    1106        7238 :     for (i = 0; i < arr_size; i++)
    1107             :     {
    1108        7034 :         if (strcmp(pattern, arr[i]) == 0)
    1109        3398 :             return i;
    1110             :     }
    1111         204 :     return -1;
    1112             : }

Generated by: LCOV version 1.13