Header And Logo

PostgreSQL
| The world's most advanced open source database.

common.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * common.c
00004  *  Catalog routines used by pg_dump; long ago these were shared
00005  *  by another dump tool, but not anymore.
00006  *
00007  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00008  * Portions Copyright (c) 1994, Regents of the University of California
00009  *
00010  *
00011  * IDENTIFICATION
00012  *    src/bin/pg_dump/common.c
00013  *
00014  *-------------------------------------------------------------------------
00015  */
00016 #include "pg_backup_archiver.h"
00017 #include "pg_backup_utils.h"
00018 
00019 #include <ctype.h>
00020 
00021 #include "catalog/pg_class.h"
00022 
00023 
00024 /*
00025  * Variables for mapping DumpId to DumpableObject
00026  */
00027 static DumpableObject **dumpIdMap = NULL;
00028 static int  allocedDumpIds = 0;
00029 static DumpId lastDumpId = 0;
00030 
00031 /*
00032  * Variables for mapping CatalogId to DumpableObject
00033  */
00034 static bool catalogIdMapValid = false;
00035 static DumpableObject **catalogIdMap = NULL;
00036 static int  numCatalogIds = 0;
00037 
00038 /*
00039  * These variables are static to avoid the notational cruft of having to pass
00040  * them into findTableByOid() and friends.  For each of these arrays, we
00041  * build a sorted-by-OID index array immediately after it's built, and then
00042  * we use binary search in findTableByOid() and friends.  (qsort'ing the base
00043  * arrays themselves would be simpler, but it doesn't work because pg_dump.c
00044  * may have already established pointers between items.)
00045  */
00046 static TableInfo *tblinfo;
00047 static TypeInfo *typinfo;
00048 static FuncInfo *funinfo;
00049 static OprInfo *oprinfo;
00050 static NamespaceInfo *nspinfo;
00051 static int  numTables;
00052 static int  numTypes;
00053 static int  numFuncs;
00054 static int  numOperators;
00055 static int  numCollations;
00056 static int  numNamespaces;
00057 static DumpableObject **tblinfoindex;
00058 static DumpableObject **typinfoindex;
00059 static DumpableObject **funinfoindex;
00060 static DumpableObject **oprinfoindex;
00061 static DumpableObject **collinfoindex;
00062 static DumpableObject **nspinfoindex;
00063 
00064 
00065 static void flagInhTables(TableInfo *tbinfo, int numTables,
00066               InhInfo *inhinfo, int numInherits);
00067 static void flagInhAttrs(TableInfo *tblinfo, int numTables);
00068 static DumpableObject **buildIndexArray(void *objArray, int numObjs,
00069                 Size objSize);
00070 static int  DOCatalogIdCompare(const void *p1, const void *p2);
00071 static void findParentsByOid(TableInfo *self,
00072                  InhInfo *inhinfo, int numInherits);
00073 static int  strInArray(const char *pattern, char **arr, int arr_size);
00074 
00075 
00076 /*
00077  * getSchemaData
00078  *    Collect information about all potentially dumpable objects
00079  */
00080 TableInfo *
00081 getSchemaData(Archive *fout, int *numTablesPtr)
00082 {
00083     ExtensionInfo *extinfo;
00084     InhInfo    *inhinfo;
00085     CollInfo   *collinfo;
00086     int         numExtensions;
00087     int         numAggregates;
00088     int         numInherits;
00089     int         numRules;
00090     int         numProcLangs;
00091     int         numCasts;
00092     int         numOpclasses;
00093     int         numOpfamilies;
00094     int         numConversions;
00095     int         numTSParsers;
00096     int         numTSTemplates;
00097     int         numTSDicts;
00098     int         numTSConfigs;
00099     int         numForeignDataWrappers;
00100     int         numForeignServers;
00101     int         numDefaultACLs;
00102     int         numEventTriggers;
00103 
00104     if (g_verbose)
00105         write_msg(NULL, "reading schemas\n");
00106     nspinfo = getNamespaces(fout, &numNamespaces);
00107     nspinfoindex = buildIndexArray(nspinfo, numNamespaces, sizeof(NamespaceInfo));
00108 
00109     /*
00110      * getTables should be done as soon as possible, so as to minimize the
00111      * window between starting our transaction and acquiring per-table locks.
00112      * However, we have to do getNamespaces first because the tables get
00113      * linked to their containing namespaces during getTables.
00114      */
00115     if (g_verbose)
00116         write_msg(NULL, "reading user-defined tables\n");
00117     tblinfo = getTables(fout, &numTables);
00118     tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo));
00119 
00120     /* Do this after we've built tblinfoindex */
00121     getOwnedSeqs(fout, tblinfo, numTables);
00122 
00123     if (g_verbose)
00124         write_msg(NULL, "reading extensions\n");
00125     extinfo = getExtensions(fout, &numExtensions);
00126 
00127     if (g_verbose)
00128         write_msg(NULL, "reading user-defined functions\n");
00129     funinfo = getFuncs(fout, &numFuncs);
00130     funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo));
00131 
00132     /* this must be after getTables and getFuncs */
00133     if (g_verbose)
00134         write_msg(NULL, "reading user-defined types\n");
00135     typinfo = getTypes(fout, &numTypes);
00136     typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo));
00137 
00138     /* this must be after getFuncs, too */
00139     if (g_verbose)
00140         write_msg(NULL, "reading procedural languages\n");
00141     getProcLangs(fout, &numProcLangs);
00142 
00143     if (g_verbose)
00144         write_msg(NULL, "reading user-defined aggregate functions\n");
00145     getAggregates(fout, &numAggregates);
00146 
00147     if (g_verbose)
00148         write_msg(NULL, "reading user-defined operators\n");
00149     oprinfo = getOperators(fout, &numOperators);
00150     oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
00151 
00152     if (g_verbose)
00153         write_msg(NULL, "reading user-defined operator classes\n");
00154     getOpclasses(fout, &numOpclasses);
00155 
00156     if (g_verbose)
00157         write_msg(NULL, "reading user-defined operator families\n");
00158     getOpfamilies(fout, &numOpfamilies);
00159 
00160     if (g_verbose)
00161         write_msg(NULL, "reading user-defined text search parsers\n");
00162     getTSParsers(fout, &numTSParsers);
00163 
00164     if (g_verbose)
00165         write_msg(NULL, "reading user-defined text search templates\n");
00166     getTSTemplates(fout, &numTSTemplates);
00167 
00168     if (g_verbose)
00169         write_msg(NULL, "reading user-defined text search dictionaries\n");
00170     getTSDictionaries(fout, &numTSDicts);
00171 
00172     if (g_verbose)
00173         write_msg(NULL, "reading user-defined text search configurations\n");
00174     getTSConfigurations(fout, &numTSConfigs);
00175 
00176     if (g_verbose)
00177         write_msg(NULL, "reading user-defined foreign-data wrappers\n");
00178     getForeignDataWrappers(fout, &numForeignDataWrappers);
00179 
00180     if (g_verbose)
00181         write_msg(NULL, "reading user-defined foreign servers\n");
00182     getForeignServers(fout, &numForeignServers);
00183 
00184     if (g_verbose)
00185         write_msg(NULL, "reading default privileges\n");
00186     getDefaultACLs(fout, &numDefaultACLs);
00187 
00188     if (g_verbose)
00189         write_msg(NULL, "reading user-defined collations\n");
00190     collinfo = getCollations(fout, &numCollations);
00191     collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
00192 
00193     if (g_verbose)
00194         write_msg(NULL, "reading user-defined conversions\n");
00195     getConversions(fout, &numConversions);
00196 
00197     if (g_verbose)
00198         write_msg(NULL, "reading type casts\n");
00199     getCasts(fout, &numCasts);
00200 
00201     if (g_verbose)
00202         write_msg(NULL, "reading table inheritance information\n");
00203     inhinfo = getInherits(fout, &numInherits);
00204 
00205     if (g_verbose)
00206         write_msg(NULL, "reading rewrite rules\n");
00207     getRules(fout, &numRules);
00208 
00209     /*
00210      * Identify extension member objects and mark them as not to be dumped.
00211      * This must happen after reading all objects that can be direct members
00212      * of extensions, but before we begin to process table subsidiary objects.
00213      */
00214     if (g_verbose)
00215         write_msg(NULL, "finding extension members\n");
00216     getExtensionMembership(fout, extinfo, numExtensions);
00217 
00218     /* Link tables to parents, mark parents of target tables interesting */
00219     if (g_verbose)
00220         write_msg(NULL, "finding inheritance relationships\n");
00221     flagInhTables(tblinfo, numTables, inhinfo, numInherits);
00222 
00223     if (g_verbose)
00224         write_msg(NULL, "reading column info for interesting tables\n");
00225     getTableAttrs(fout, tblinfo, numTables);
00226 
00227     if (g_verbose)
00228         write_msg(NULL, "flagging inherited columns in subtables\n");
00229     flagInhAttrs(tblinfo, numTables);
00230 
00231     if (g_verbose)
00232         write_msg(NULL, "reading indexes\n");
00233     getIndexes(fout, tblinfo, numTables);
00234 
00235     if (g_verbose)
00236         write_msg(NULL, "reading constraints\n");
00237     getConstraints(fout, tblinfo, numTables);
00238 
00239     if (g_verbose)
00240         write_msg(NULL, "reading triggers\n");
00241     getTriggers(fout, tblinfo, numTables);
00242 
00243     if (g_verbose)
00244         write_msg(NULL, "reading event triggers\n");
00245     getEventTriggers(fout, &numEventTriggers);
00246 
00247     *numTablesPtr = numTables;
00248     return tblinfo;
00249 }
00250 
00251 /* flagInhTables -
00252  *   Fill in parent link fields of every target table, and mark
00253  *   parents of target tables as interesting
00254  *
00255  * Note that only direct ancestors of targets are marked interesting.
00256  * This is sufficient; we don't much care whether they inherited their
00257  * attributes or not.
00258  *
00259  * modifies tblinfo
00260  */
00261 static void
00262 flagInhTables(TableInfo *tblinfo, int numTables,
00263               InhInfo *inhinfo, int numInherits)
00264 {
00265     int         i,
00266                 j;
00267     int         numParents;
00268     TableInfo **parents;
00269 
00270     for (i = 0; i < numTables; i++)
00271     {
00272         /* Sequences and views never have parents */
00273         if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
00274             tblinfo[i].relkind == RELKIND_VIEW ||
00275             tblinfo[i].relkind == RELKIND_MATVIEW)
00276             continue;
00277 
00278         /* Don't bother computing anything for non-target tables, either */
00279         if (!tblinfo[i].dobj.dump)
00280             continue;
00281 
00282         /* Find all the immediate parent tables */
00283         findParentsByOid(&tblinfo[i], inhinfo, numInherits);
00284 
00285         /* Mark the parents as interesting for getTableAttrs */
00286         numParents = tblinfo[i].numParents;
00287         parents = tblinfo[i].parents;
00288         for (j = 0; j < numParents; j++)
00289             parents[j]->interesting = true;
00290     }
00291 }
00292 
00293 /* flagInhAttrs -
00294  *   for each dumpable table in tblinfo, flag its inherited attributes
00295  *
00296  * What we need to do here is detect child columns that inherit NOT NULL
00297  * bits from their parents (so that we needn't specify that again for the
00298  * child) and child columns that have DEFAULT NULL when their parents had
00299  * some non-null default.  In the latter case, we make up a dummy AttrDefInfo
00300  * object so that we'll correctly emit the necessary DEFAULT NULL clause;
00301  * otherwise the backend will apply an inherited default to the column.
00302  *
00303  * modifies tblinfo
00304  */
00305 static void
00306 flagInhAttrs(TableInfo *tblinfo, int numTables)
00307 {
00308     int         i,
00309                 j,
00310                 k;
00311 
00312     for (i = 0; i < numTables; i++)
00313     {
00314         TableInfo  *tbinfo = &(tblinfo[i]);
00315         int         numParents;
00316         TableInfo **parents;
00317 
00318         /* Sequences and views never have parents */
00319         if (tbinfo->relkind == RELKIND_SEQUENCE ||
00320             tbinfo->relkind == RELKIND_VIEW ||
00321             tbinfo->relkind == RELKIND_MATVIEW)
00322             continue;
00323 
00324         /* Don't bother computing anything for non-target tables, either */
00325         if (!tbinfo->dobj.dump)
00326             continue;
00327 
00328         numParents = tbinfo->numParents;
00329         parents = tbinfo->parents;
00330 
00331         if (numParents == 0)
00332             continue;           /* nothing to see here, move along */
00333 
00334         /* For each column, search for matching column names in parent(s) */
00335         for (j = 0; j < tbinfo->numatts; j++)
00336         {
00337             bool        foundNotNull;   /* Attr was NOT NULL in a parent */
00338             bool        foundDefault;   /* Found a default in a parent */
00339 
00340             /* no point in examining dropped columns */
00341             if (tbinfo->attisdropped[j])
00342                 continue;
00343 
00344             foundNotNull = false;
00345             foundDefault = false;
00346             for (k = 0; k < numParents; k++)
00347             {
00348                 TableInfo  *parent = parents[k];
00349                 int         inhAttrInd;
00350 
00351                 inhAttrInd = strInArray(tbinfo->attnames[j],
00352                                         parent->attnames,
00353                                         parent->numatts);
00354                 if (inhAttrInd >= 0)
00355                 {
00356                     foundNotNull |= parent->notnull[inhAttrInd];
00357                     foundDefault |= (parent->attrdefs[inhAttrInd] != NULL);
00358                 }
00359             }
00360 
00361             /* Remember if we found inherited NOT NULL */
00362             tbinfo->inhNotNull[j] = foundNotNull;
00363 
00364             /* Manufacture a DEFAULT NULL clause if necessary */
00365             if (foundDefault && tbinfo->attrdefs[j] == NULL)
00366             {
00367                 AttrDefInfo *attrDef;
00368 
00369                 attrDef = (AttrDefInfo *) pg_malloc(sizeof(AttrDefInfo));
00370                 attrDef->dobj.objType = DO_ATTRDEF;
00371                 attrDef->dobj.catId.tableoid = 0;
00372                 attrDef->dobj.catId.oid = 0;
00373                 AssignDumpId(&attrDef->dobj);
00374                 attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
00375                 attrDef->dobj.namespace = tbinfo->dobj.namespace;
00376                 attrDef->dobj.dump = tbinfo->dobj.dump;
00377 
00378                 attrDef->adtable = tbinfo;
00379                 attrDef->adnum = j + 1;
00380                 attrDef->adef_expr = pg_strdup("NULL");
00381 
00382                 /* Will column be dumped explicitly? */
00383                 if (shouldPrintColumn(tbinfo, j))
00384                 {
00385                     attrDef->separate = false;
00386                     /* No dependency needed: NULL cannot have dependencies */
00387                 }
00388                 else
00389                 {
00390                     /* column will be suppressed, print default separately */
00391                     attrDef->separate = true;
00392                     /* ensure it comes out after the table */
00393                     addObjectDependency(&attrDef->dobj,
00394                                         tbinfo->dobj.dumpId);
00395                 }
00396 
00397                 tbinfo->attrdefs[j] = attrDef;
00398             }
00399         }
00400     }
00401 }
00402 
00403 /*
00404  * AssignDumpId
00405  *      Given a newly-created dumpable object, assign a dump ID,
00406  *      and enter the object into the lookup table.
00407  *
00408  * The caller is expected to have filled in objType and catId,
00409  * but not any of the other standard fields of a DumpableObject.
00410  */
00411 void
00412 AssignDumpId(DumpableObject *dobj)
00413 {
00414     dobj->dumpId = ++lastDumpId;
00415     dobj->name = NULL;          /* must be set later */
00416     dobj->namespace = NULL;     /* may be set later */
00417     dobj->dump = true;          /* default assumption */
00418     dobj->ext_member = false;   /* default assumption */
00419     dobj->dependencies = NULL;
00420     dobj->nDeps = 0;
00421     dobj->allocDeps = 0;
00422 
00423     while (dobj->dumpId >= allocedDumpIds)
00424     {
00425         int         newAlloc;
00426 
00427         if (allocedDumpIds <= 0)
00428         {
00429             newAlloc = 256;
00430             dumpIdMap = (DumpableObject **)
00431                 pg_malloc(newAlloc * sizeof(DumpableObject *));
00432         }
00433         else
00434         {
00435             newAlloc = allocedDumpIds * 2;
00436             dumpIdMap = (DumpableObject **)
00437                 pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
00438         }
00439         memset(dumpIdMap + allocedDumpIds, 0,
00440                (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
00441         allocedDumpIds = newAlloc;
00442     }
00443     dumpIdMap[dobj->dumpId] = dobj;
00444 
00445     /* mark catalogIdMap invalid, but don't rebuild it yet */
00446     catalogIdMapValid = false;
00447 }
00448 
00449 /*
00450  * Assign a DumpId that's not tied to a DumpableObject.
00451  *
00452  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
00453  * participate in the sorting logic.
00454  */
00455 DumpId
00456 createDumpId(void)
00457 {
00458     return ++lastDumpId;
00459 }
00460 
00461 /*
00462  * Return the largest DumpId so far assigned
00463  */
00464 DumpId
00465 getMaxDumpId(void)
00466 {
00467     return lastDumpId;
00468 }
00469 
00470 /*
00471  * Find a DumpableObject by dump ID
00472  *
00473  * Returns NULL for invalid ID
00474  */
00475 DumpableObject *
00476 findObjectByDumpId(DumpId dumpId)
00477 {
00478     if (dumpId <= 0 || dumpId >= allocedDumpIds)
00479         return NULL;            /* out of range? */
00480     return dumpIdMap[dumpId];
00481 }
00482 
00483 /*
00484  * Find a DumpableObject by catalog ID
00485  *
00486  * Returns NULL for unknown ID
00487  *
00488  * We use binary search in a sorted list that is built on first call.
00489  * If AssignDumpId() and findObjectByCatalogId() calls were freely intermixed,
00490  * the code would work, but possibly be very slow.  In the current usage
00491  * pattern that does not happen, indeed we build the list at most twice.
00492  */
00493 DumpableObject *
00494 findObjectByCatalogId(CatalogId catalogId)
00495 {
00496     DumpableObject **low;
00497     DumpableObject **high;
00498 
00499     if (!catalogIdMapValid)
00500     {
00501         if (catalogIdMap)
00502             free(catalogIdMap);
00503         getDumpableObjects(&catalogIdMap, &numCatalogIds);
00504         if (numCatalogIds > 1)
00505             qsort((void *) catalogIdMap, numCatalogIds,
00506                   sizeof(DumpableObject *), DOCatalogIdCompare);
00507         catalogIdMapValid = true;
00508     }
00509 
00510     /*
00511      * We could use bsearch() here, but the notational cruft of calling
00512      * bsearch is nearly as bad as doing it ourselves; and the generalized
00513      * bsearch function is noticeably slower as well.
00514      */
00515     if (numCatalogIds <= 0)
00516         return NULL;
00517     low = catalogIdMap;
00518     high = catalogIdMap + (numCatalogIds - 1);
00519     while (low <= high)
00520     {
00521         DumpableObject **middle;
00522         int         difference;
00523 
00524         middle = low + (high - low) / 2;
00525         /* comparison must match DOCatalogIdCompare, below */
00526         difference = oidcmp((*middle)->catId.oid, catalogId.oid);
00527         if (difference == 0)
00528             difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid);
00529         if (difference == 0)
00530             return *middle;
00531         else if (difference < 0)
00532             low = middle + 1;
00533         else
00534             high = middle - 1;
00535     }
00536     return NULL;
00537 }
00538 
00539 /*
00540  * Find a DumpableObject by OID, in a pre-sorted array of one type of object
00541  *
00542  * Returns NULL for unknown OID
00543  */
00544 static DumpableObject *
00545 findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
00546 {
00547     DumpableObject **low;
00548     DumpableObject **high;
00549 
00550     /*
00551      * This is the same as findObjectByCatalogId except we assume we need not
00552      * look at table OID because the objects are all the same type.
00553      *
00554      * We could use bsearch() here, but the notational cruft of calling
00555      * bsearch is nearly as bad as doing it ourselves; and the generalized
00556      * bsearch function is noticeably slower as well.
00557      */
00558     if (numObjs <= 0)
00559         return NULL;
00560     low = indexArray;
00561     high = indexArray + (numObjs - 1);
00562     while (low <= high)
00563     {
00564         DumpableObject **middle;
00565         int         difference;
00566 
00567         middle = low + (high - low) / 2;
00568         difference = oidcmp((*middle)->catId.oid, oid);
00569         if (difference == 0)
00570             return *middle;
00571         else if (difference < 0)
00572             low = middle + 1;
00573         else
00574             high = middle - 1;
00575     }
00576     return NULL;
00577 }
00578 
00579 /*
00580  * Build an index array of DumpableObject pointers, sorted by OID
00581  */
00582 static DumpableObject **
00583 buildIndexArray(void *objArray, int numObjs, Size objSize)
00584 {
00585     DumpableObject **ptrs;
00586     int         i;
00587 
00588     ptrs = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
00589     for (i = 0; i < numObjs; i++)
00590         ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize);
00591 
00592     /* We can use DOCatalogIdCompare to sort since its first key is OID */
00593     if (numObjs > 1)
00594         qsort((void *) ptrs, numObjs, sizeof(DumpableObject *),
00595               DOCatalogIdCompare);
00596 
00597     return ptrs;
00598 }
00599 
00600 /*
00601  * qsort comparator for pointers to DumpableObjects
00602  */
00603 static int
00604 DOCatalogIdCompare(const void *p1, const void *p2)
00605 {
00606     const DumpableObject *obj1 = *(DumpableObject *const *) p1;
00607     const DumpableObject *obj2 = *(DumpableObject *const *) p2;
00608     int         cmpval;
00609 
00610     /*
00611      * Compare OID first since it's usually unique, whereas there will only be
00612      * a few distinct values of tableoid.
00613      */
00614     cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
00615     if (cmpval == 0)
00616         cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
00617     return cmpval;
00618 }
00619 
00620 /*
00621  * Build an array of pointers to all known dumpable objects
00622  *
00623  * This simply creates a modifiable copy of the internal map.
00624  */
00625 void
00626 getDumpableObjects(DumpableObject ***objs, int *numObjs)
00627 {
00628     int         i,
00629                 j;
00630 
00631     *objs = (DumpableObject **)
00632         pg_malloc(allocedDumpIds * sizeof(DumpableObject *));
00633     j = 0;
00634     for (i = 1; i < allocedDumpIds; i++)
00635     {
00636         if (dumpIdMap[i])
00637             (*objs)[j++] = dumpIdMap[i];
00638     }
00639     *numObjs = j;
00640 }
00641 
00642 /*
00643  * Add a dependency link to a DumpableObject
00644  *
00645  * Note: duplicate dependencies are currently not eliminated
00646  */
00647 void
00648 addObjectDependency(DumpableObject *dobj, DumpId refId)
00649 {
00650     if (dobj->nDeps >= dobj->allocDeps)
00651     {
00652         if (dobj->allocDeps <= 0)
00653         {
00654             dobj->allocDeps = 16;
00655             dobj->dependencies = (DumpId *)
00656                 pg_malloc(dobj->allocDeps * sizeof(DumpId));
00657         }
00658         else
00659         {
00660             dobj->allocDeps *= 2;
00661             dobj->dependencies = (DumpId *)
00662                 pg_realloc(dobj->dependencies,
00663                            dobj->allocDeps * sizeof(DumpId));
00664         }
00665     }
00666     dobj->dependencies[dobj->nDeps++] = refId;
00667 }
00668 
00669 /*
00670  * Remove a dependency link from a DumpableObject
00671  *
00672  * If there are multiple links, all are removed
00673  */
00674 void
00675 removeObjectDependency(DumpableObject *dobj, DumpId refId)
00676 {
00677     int         i;
00678     int         j = 0;
00679 
00680     for (i = 0; i < dobj->nDeps; i++)
00681     {
00682         if (dobj->dependencies[i] != refId)
00683             dobj->dependencies[j++] = dobj->dependencies[i];
00684     }
00685     dobj->nDeps = j;
00686 }
00687 
00688 
00689 /*
00690  * findTableByOid
00691  *    finds the entry (in tblinfo) of the table with the given oid
00692  *    returns NULL if not found
00693  */
00694 TableInfo *
00695 findTableByOid(Oid oid)
00696 {
00697     return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
00698 }
00699 
00700 /*
00701  * findTypeByOid
00702  *    finds the entry (in typinfo) of the type with the given oid
00703  *    returns NULL if not found
00704  */
00705 TypeInfo *
00706 findTypeByOid(Oid oid)
00707 {
00708     return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
00709 }
00710 
00711 /*
00712  * findFuncByOid
00713  *    finds the entry (in funinfo) of the function with the given oid
00714  *    returns NULL if not found
00715  */
00716 FuncInfo *
00717 findFuncByOid(Oid oid)
00718 {
00719     return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
00720 }
00721 
00722 /*
00723  * findOprByOid
00724  *    finds the entry (in oprinfo) of the operator with the given oid
00725  *    returns NULL if not found
00726  */
00727 OprInfo *
00728 findOprByOid(Oid oid)
00729 {
00730     return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
00731 }
00732 
00733 /*
00734  * findCollationByOid
00735  *    finds the entry (in collinfo) of the collation with the given oid
00736  *    returns NULL if not found
00737  */
00738 CollInfo *
00739 findCollationByOid(Oid oid)
00740 {
00741     return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations);
00742 }
00743 
00744 /*
00745  * findNamespaceByOid
00746  *    finds the entry (in nspinfo) of the namespace with the given oid
00747  *    returns NULL if not found
00748  */
00749 NamespaceInfo *
00750 findNamespaceByOid(Oid oid)
00751 {
00752     return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
00753 }
00754 
00755 
00756 /*
00757  * findParentsByOid
00758  *    find a table's parents in tblinfo[]
00759  */
00760 static void
00761 findParentsByOid(TableInfo *self,
00762                  InhInfo *inhinfo, int numInherits)
00763 {
00764     Oid         oid = self->dobj.catId.oid;
00765     int         i,
00766                 j;
00767     int         numParents;
00768 
00769     numParents = 0;
00770     for (i = 0; i < numInherits; i++)
00771     {
00772         if (inhinfo[i].inhrelid == oid)
00773             numParents++;
00774     }
00775 
00776     self->numParents = numParents;
00777 
00778     if (numParents > 0)
00779     {
00780         self->parents = (TableInfo **)
00781             pg_malloc(sizeof(TableInfo *) * numParents);
00782         j = 0;
00783         for (i = 0; i < numInherits; i++)
00784         {
00785             if (inhinfo[i].inhrelid == oid)
00786             {
00787                 TableInfo  *parent;
00788 
00789                 parent = findTableByOid(inhinfo[i].inhparent);
00790                 if (parent == NULL)
00791                 {
00792                     write_msg(NULL, "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n",
00793                               inhinfo[i].inhparent,
00794                               self->dobj.name,
00795                               oid);
00796                     exit_nicely(1);
00797                 }
00798                 self->parents[j++] = parent;
00799             }
00800         }
00801     }
00802     else
00803         self->parents = NULL;
00804 }
00805 
00806 /*
00807  * parseOidArray
00808  *    parse a string of numbers delimited by spaces into a character array
00809  *
00810  * Note: actually this is used for both Oids and potentially-signed
00811  * attribute numbers.  This should cause no trouble, but we could split
00812  * the function into two functions with different argument types if it does.
00813  */
00814 
00815 void
00816 parseOidArray(const char *str, Oid *array, int arraysize)
00817 {
00818     int         j,
00819                 argNum;
00820     char        temp[100];
00821     char        s;
00822 
00823     argNum = 0;
00824     j = 0;
00825     for (;;)
00826     {
00827         s = *str++;
00828         if (s == ' ' || s == '\0')
00829         {
00830             if (j > 0)
00831             {
00832                 if (argNum >= arraysize)
00833                 {
00834                     write_msg(NULL, "could not parse numeric array \"%s\": too many numbers\n", str);
00835                     exit_nicely(1);
00836                 }
00837                 temp[j] = '\0';
00838                 array[argNum++] = atooid(temp);
00839                 j = 0;
00840             }
00841             if (s == '\0')
00842                 break;
00843         }
00844         else
00845         {
00846             if (!(isdigit((unsigned char) s) || s == '-') ||
00847                 j >= sizeof(temp) - 1)
00848             {
00849                 write_msg(NULL, "could not parse numeric array \"%s\": invalid character in number\n", str);
00850                 exit_nicely(1);
00851             }
00852             temp[j++] = s;
00853         }
00854     }
00855 
00856     while (argNum < arraysize)
00857         array[argNum++] = InvalidOid;
00858 }
00859 
00860 
00861 /*
00862  * strInArray:
00863  *    takes in a string and a string array and the number of elements in the
00864  * string array.
00865  *    returns the index if the string is somewhere in the array, -1 otherwise
00866  */
00867 
00868 static int
00869 strInArray(const char *pattern, char **arr, int arr_size)
00870 {
00871     int         i;
00872 
00873     for (i = 0; i < arr_size; i++)
00874     {
00875         if (strcmp(pattern, arr[i]) == 0)
00876             return i;
00877     }
00878     return -1;
00879 }
00880 
00881 
00882 /*
00883  * Support for simple list operations
00884  */
00885 
00886 void
00887 simple_oid_list_append(SimpleOidList *list, Oid val)
00888 {
00889     SimpleOidListCell *cell;
00890 
00891     cell = (SimpleOidListCell *) pg_malloc(sizeof(SimpleOidListCell));
00892     cell->next = NULL;
00893     cell->val = val;
00894 
00895     if (list->tail)
00896         list->tail->next = cell;
00897     else
00898         list->head = cell;
00899     list->tail = cell;
00900 }
00901 
00902 bool
00903 simple_oid_list_member(SimpleOidList *list, Oid val)
00904 {
00905     SimpleOidListCell *cell;
00906 
00907     for (cell = list->head; cell; cell = cell->next)
00908     {
00909         if (cell->val == val)
00910             return true;
00911     }
00912     return false;
00913 }