From 9a7d49d1fba666c8bfb9df0065545e85d54dbc41 Mon Sep 17 00:00:00 2001 From: Bruce Momjian <bruce@momjian.us> Date: Sat, 26 Nov 2011 22:34:36 -0500 Subject: [PATCH] Move pg_dump memory routines into pg_dumpmem.c/h and restore common.c with its original functions. The previous function migration would cause too many difficulties in back-patching. --- src/bin/pg_dump/Makefile | 6 +- src/bin/pg_dump/common.c | 982 +++++++++++++++++++++++- src/bin/pg_dump/compress_io.c | 2 +- src/bin/pg_dump/dumpcatalog.c | 978 ----------------------- src/bin/pg_dump/dumpmem.c | 73 ++ src/bin/pg_dump/{common.h => dumpmem.h} | 12 +- src/bin/pg_dump/dumputils.c | 2 +- src/bin/pg_dump/pg_backup_archiver.c | 2 +- src/bin/pg_dump/pg_backup_custom.c | 2 +- src/bin/pg_dump/pg_backup_db.c | 2 +- src/bin/pg_dump/pg_backup_directory.c | 2 +- src/bin/pg_dump/pg_backup_files.c | 2 +- src/bin/pg_dump/pg_backup_null.c | 2 +- src/bin/pg_dump/pg_backup_tar.c | 2 +- src/bin/pg_dump/pg_dump.c | 2 +- src/bin/pg_dump/pg_dump_sort.c | 2 +- src/bin/pg_dump/pg_restore.c | 2 +- 17 files changed, 1038 insertions(+), 1037 deletions(-) delete mode 100644 src/bin/pg_dump/dumpcatalog.c create mode 100644 src/bin/pg_dump/dumpmem.c rename src/bin/pg_dump/{common.h => dumpmem.h} (75%) diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile index 9d13bec7933..4e8e421ba1e 100644 --- a/src/bin/pg_dump/Makefile +++ b/src/bin/pg_dump/Makefile @@ -20,7 +20,7 @@ override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS) OBJS= pg_backup_archiver.o pg_backup_db.o pg_backup_custom.o \ pg_backup_files.o pg_backup_null.o pg_backup_tar.o \ - pg_backup_directory.o common.o dumputils.o compress_io.o $(WIN32RES) + pg_backup_directory.o dumpmem.o dumputils.o compress_io.o $(WIN32RES) KEYWRDOBJS = keywords.o kwlookup.o @@ -29,8 +29,8 @@ kwlookup.c: % : $(top_srcdir)/src/backend/parser/% all: pg_dump pg_restore pg_dumpall -pg_dump: pg_dump.o dumpcatalog.o pg_dump_sort.o $(OBJS) $(KEYWRDOBJS) | submake-libpq submake-libpgport - $(CC) $(CFLAGS) pg_dump.o dumpcatalog.o pg_dump_sort.o $(KEYWRDOBJS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) +pg_dump: pg_dump.o common.o pg_dump_sort.o $(OBJS) $(KEYWRDOBJS) | submake-libpq submake-libpgport + $(CC) $(CFLAGS) pg_dump.o common.o pg_dump_sort.o $(KEYWRDOBJS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) pg_restore: pg_restore.o $(OBJS) $(KEYWRDOBJS) | submake-libpq submake-libpgport $(CC) $(CFLAGS) pg_restore.o $(KEYWRDOBJS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 1a3f4cb6e8e..6f921f7758c 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -1,8 +1,8 @@ /*------------------------------------------------------------------------- * * common.c - * common routines between pg_dump and pg_restore (but not pg_dumpall - * because there is no failure location to report). + * catalog routines used by pg_dump; long ago these were shared + * by another dump tool, but not anymore. * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California @@ -14,60 +14,966 @@ *------------------------------------------------------------------------- */ #include "postgres_fe.h" -#include "pg_backup.h" -#include "common.h" #include <ctype.h> +#include "catalog/pg_class.h" + +#include "pg_backup_archiver.h" +#include "dumpmem.h" + + +/* + * Variables for mapping DumpId to DumpableObject + */ +static DumpableObject **dumpIdMap = NULL; +static int allocedDumpIds = 0; +static DumpId lastDumpId = 0; + +/* + * Variables for mapping CatalogId to DumpableObject + */ +static bool catalogIdMapValid = false; +static DumpableObject **catalogIdMap = NULL; +static int numCatalogIds = 0; + +/* + * These variables are static to avoid the notational cruft of having to pass + * them into findTableByOid() and friends. For each of these arrays, we + * build a sorted-by-OID index array immediately after it's built, and then + * we use binary search in findTableByOid() and friends. (qsort'ing the base + * arrays themselves would be simpler, but it doesn't work because pg_dump.c + * may have already established pointers between items.) + */ +static TableInfo *tblinfo; +static TypeInfo *typinfo; +static FuncInfo *funinfo; +static OprInfo *oprinfo; +static int numTables; +static int numTypes; +static int numFuncs; +static int numOperators; +static int numCollations; +static DumpableObject **tblinfoindex; +static DumpableObject **typinfoindex; +static DumpableObject **funinfoindex; +static DumpableObject **oprinfoindex; +static DumpableObject **collinfoindex; + + +static void flagInhTables(TableInfo *tbinfo, int numTables, + InhInfo *inhinfo, int numInherits); +static void flagInhAttrs(TableInfo *tblinfo, int numTables); +static DumpableObject **buildIndexArray(void *objArray, int numObjs, + Size objSize); +static int DOCatalogIdCompare(const void *p1, const void *p2); +static void findParentsByOid(TableInfo *self, + InhInfo *inhinfo, int numInherits); +static int strInArray(const char *pattern, char **arr, int arr_size); + + /* - * Safer versions of some standard C library functions. If an - * out-of-memory condition occurs, these functions will bail out - * safely; therefore, their return value is guaranteed to be non-NULL. - * We also report the program name and close the database connection. + * getSchemaData + * Collect information about all potentially dumpable objects */ +TableInfo * +getSchemaData(int *numTablesPtr) +{ + ExtensionInfo *extinfo; + InhInfo *inhinfo; + CollInfo *collinfo; + int numNamespaces; + int numExtensions; + int numAggregates; + int numInherits; + int numRules; + int numProcLangs; + int numCasts; + int numOpclasses; + int numOpfamilies; + int numConversions; + int numTSParsers; + int numTSTemplates; + int numTSDicts; + int numTSConfigs; + int numForeignDataWrappers; + int numForeignServers; + int numDefaultACLs; + + if (g_verbose) + write_msg(NULL, "reading schemas\n"); + getNamespaces(&numNamespaces); + + /* + * getTables should be done as soon as possible, so as to minimize the + * window between starting our transaction and acquiring per-table locks. + * However, we have to do getNamespaces first because the tables get + * linked to their containing namespaces during getTables. + */ + if (g_verbose) + write_msg(NULL, "reading user-defined tables\n"); + tblinfo = getTables(&numTables); + tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo)); + + if (g_verbose) + write_msg(NULL, "reading extensions\n"); + extinfo = getExtensions(&numExtensions); + + if (g_verbose) + write_msg(NULL, "reading user-defined functions\n"); + funinfo = getFuncs(&numFuncs); + funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo)); + + /* this must be after getTables and getFuncs */ + if (g_verbose) + write_msg(NULL, "reading user-defined types\n"); + typinfo = getTypes(&numTypes); + typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo)); + + /* this must be after getFuncs, too */ + if (g_verbose) + write_msg(NULL, "reading procedural languages\n"); + getProcLangs(&numProcLangs); + + if (g_verbose) + write_msg(NULL, "reading user-defined aggregate functions\n"); + getAggregates(&numAggregates); + + if (g_verbose) + write_msg(NULL, "reading user-defined operators\n"); + oprinfo = getOperators(&numOperators); + oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo)); + + if (g_verbose) + write_msg(NULL, "reading user-defined operator classes\n"); + getOpclasses(&numOpclasses); + + if (g_verbose) + write_msg(NULL, "reading user-defined operator families\n"); + getOpfamilies(&numOpfamilies); + + if (g_verbose) + write_msg(NULL, "reading user-defined text search parsers\n"); + getTSParsers(&numTSParsers); + + if (g_verbose) + write_msg(NULL, "reading user-defined text search templates\n"); + getTSTemplates(&numTSTemplates); -char * -pg_strdup(const char *string) + if (g_verbose) + write_msg(NULL, "reading user-defined text search dictionaries\n"); + getTSDictionaries(&numTSDicts); + + if (g_verbose) + write_msg(NULL, "reading user-defined text search configurations\n"); + getTSConfigurations(&numTSConfigs); + + if (g_verbose) + write_msg(NULL, "reading user-defined foreign-data wrappers\n"); + getForeignDataWrappers(&numForeignDataWrappers); + + if (g_verbose) + write_msg(NULL, "reading user-defined foreign servers\n"); + getForeignServers(&numForeignServers); + + if (g_verbose) + write_msg(NULL, "reading default privileges\n"); + getDefaultACLs(&numDefaultACLs); + + if (g_verbose) + write_msg(NULL, "reading user-defined collations\n"); + collinfo = getCollations(&numCollations); + collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo)); + + if (g_verbose) + write_msg(NULL, "reading user-defined conversions\n"); + getConversions(&numConversions); + + if (g_verbose) + write_msg(NULL, "reading type casts\n"); + getCasts(&numCasts); + + if (g_verbose) + write_msg(NULL, "reading table inheritance information\n"); + inhinfo = getInherits(&numInherits); + + if (g_verbose) + write_msg(NULL, "reading rewrite rules\n"); + getRules(&numRules); + + /* + * Identify extension member objects and mark them as not to be dumped. + * This must happen after reading all objects that can be direct members + * of extensions, but before we begin to process table subsidiary objects. + */ + if (g_verbose) + write_msg(NULL, "finding extension members\n"); + getExtensionMembership(extinfo, numExtensions); + + /* Link tables to parents, mark parents of target tables interesting */ + if (g_verbose) + write_msg(NULL, "finding inheritance relationships\n"); + flagInhTables(tblinfo, numTables, inhinfo, numInherits); + + if (g_verbose) + write_msg(NULL, "reading column info for interesting tables\n"); + getTableAttrs(tblinfo, numTables); + + if (g_verbose) + write_msg(NULL, "flagging inherited columns in subtables\n"); + flagInhAttrs(tblinfo, numTables); + + if (g_verbose) + write_msg(NULL, "reading indexes\n"); + getIndexes(tblinfo, numTables); + + if (g_verbose) + write_msg(NULL, "reading constraints\n"); + getConstraints(tblinfo, numTables); + + if (g_verbose) + write_msg(NULL, "reading triggers\n"); + getTriggers(tblinfo, numTables); + + *numTablesPtr = numTables; + return tblinfo; +} + +/* flagInhTables - + * Fill in parent link fields of every target table, and mark + * parents of target tables as interesting + * + * Note that only direct ancestors of targets are marked interesting. + * This is sufficient; we don't much care whether they inherited their + * attributes or not. + * + * modifies tblinfo + */ +static void +flagInhTables(TableInfo *tblinfo, int numTables, + InhInfo *inhinfo, int numInherits) { - char *tmp; + int i, + j; + int numParents; + TableInfo **parents; + + for (i = 0; i < numTables; i++) + { + /* Sequences and views never have parents */ + if (tblinfo[i].relkind == RELKIND_SEQUENCE || + tblinfo[i].relkind == RELKIND_VIEW) + continue; + + /* Don't bother computing anything for non-target tables, either */ + if (!tblinfo[i].dobj.dump) + continue; + + /* Find all the immediate parent tables */ + findParentsByOid(&tblinfo[i], inhinfo, numInherits); - if (!string) - exit_horribly(NULL, NULL, "cannot duplicate null pointer\n"); - tmp = strdup(string); - if (!tmp) - exit_horribly(NULL, NULL, "out of memory\n"); - return tmp; + /* Mark the parents as interesting for getTableAttrs */ + numParents = tblinfo[i].numParents; + parents = tblinfo[i].parents; + for (j = 0; j < numParents; j++) + parents[j]->interesting = true; + } } -void * -pg_malloc(size_t size) +/* flagInhAttrs - + * for each dumpable table in tblinfo, flag its inherited attributes + * so when we dump the table out, we don't dump out the inherited attributes + * + * modifies tblinfo + */ +static void +flagInhAttrs(TableInfo *tblinfo, int numTables) { - void *tmp; + int i, + j, + k; + + for (i = 0; i < numTables; i++) + { + TableInfo *tbinfo = &(tblinfo[i]); + int numParents; + TableInfo **parents; + TableInfo *parent; + + /* Sequences and views never have parents */ + if (tbinfo->relkind == RELKIND_SEQUENCE || + tbinfo->relkind == RELKIND_VIEW) + continue; + + /* Don't bother computing anything for non-target tables, either */ + if (!tbinfo->dobj.dump) + continue; + + numParents = tbinfo->numParents; + parents = tbinfo->parents; + + if (numParents == 0) + continue; /* nothing to see here, move along */ + + /*---------------------------------------------------------------- + * For each attr, check the parent info: if no parent has an attr + * with the same name, then it's not inherited. If there *is* an + * attr with the same name, then only dump it if: + * + * - it is NOT NULL and zero parents are NOT NULL + * OR + * - it has a default value AND the default value does not match + * all parent default values, or no parents specify a default. + * + * See discussion on -hackers around 2-Apr-2001. + *---------------------------------------------------------------- + */ + for (j = 0; j < tbinfo->numatts; j++) + { + bool foundAttr; /* Attr was found in a parent */ + bool foundNotNull; /* Attr was NOT NULL in a parent */ + bool defaultsMatch; /* All non-empty defaults match */ + bool defaultsFound; /* Found a default in a parent */ + AttrDefInfo *attrDef; + + foundAttr = false; + foundNotNull = false; + defaultsMatch = true; + defaultsFound = false; + + attrDef = tbinfo->attrdefs[j]; + + for (k = 0; k < numParents; k++) + { + int inhAttrInd; + + parent = parents[k]; + inhAttrInd = strInArray(tbinfo->attnames[j], + parent->attnames, + parent->numatts); + + if (inhAttrInd != -1) + { + AttrDefInfo *inhDef = parent->attrdefs[inhAttrInd]; + + foundAttr = true; + foundNotNull |= parent->notnull[inhAttrInd]; + if (inhDef != NULL) + { + defaultsFound = true; + + /* + * If any parent has a default and the child doesn't, + * we have to emit an explicit DEFAULT NULL clause for + * the child, else the parent's default will win. + */ + if (attrDef == NULL) + { + attrDef = (AttrDefInfo *) pg_malloc(sizeof(AttrDefInfo)); + attrDef->dobj.objType = DO_ATTRDEF; + attrDef->dobj.catId.tableoid = 0; + attrDef->dobj.catId.oid = 0; + AssignDumpId(&attrDef->dobj); + attrDef->adtable = tbinfo; + attrDef->adnum = j + 1; + attrDef->adef_expr = pg_strdup("NULL"); + + attrDef->dobj.name = pg_strdup(tbinfo->dobj.name); + attrDef->dobj.namespace = tbinfo->dobj.namespace; + + attrDef->dobj.dump = tbinfo->dobj.dump; + + attrDef->separate = false; + addObjectDependency(&tbinfo->dobj, + attrDef->dobj.dumpId); + + tbinfo->attrdefs[j] = attrDef; + } + if (strcmp(attrDef->adef_expr, inhDef->adef_expr) != 0) + { + defaultsMatch = false; + + /* + * Whenever there is a non-matching parent + * default, add a dependency to force the parent + * default to be dumped first, in case the + * defaults end up being dumped as separate + * commands. Otherwise the parent default will + * override the child's when it is applied. + */ + addObjectDependency(&attrDef->dobj, + inhDef->dobj.dumpId); + } + } + } + } + + /* + * Based on the scan of the parents, decide if we can rely on the + * inherited attr + */ + if (foundAttr) /* Attr was inherited */ + { + /* Set inherited flag by default */ + tbinfo->inhAttrs[j] = true; + tbinfo->inhAttrDef[j] = true; + tbinfo->inhNotNull[j] = true; + + /* + * Clear it if attr had a default, but parents did not, or + * mismatch + */ + if ((attrDef != NULL) && (!defaultsFound || !defaultsMatch)) + { + tbinfo->inhAttrs[j] = false; + tbinfo->inhAttrDef[j] = false; + } + + /* + * Clear it if NOT NULL and none of the parents were NOT NULL + */ + if (tbinfo->notnull[j] && !foundNotNull) + { + tbinfo->inhAttrs[j] = false; + tbinfo->inhNotNull[j] = false; + } + + /* Clear it if attr has local definition */ + if (tbinfo->attislocal[j]) + tbinfo->inhAttrs[j] = false; + } + } + } +} + +/* + * AssignDumpId + * Given a newly-created dumpable object, assign a dump ID, + * and enter the object into the lookup table. + * + * The caller is expected to have filled in objType and catId, + * but not any of the other standard fields of a DumpableObject. + */ +void +AssignDumpId(DumpableObject *dobj) +{ + dobj->dumpId = ++lastDumpId; + dobj->name = NULL; /* must be set later */ + dobj->namespace = NULL; /* may be set later */ + dobj->dump = true; /* default assumption */ + dobj->ext_member = false; /* default assumption */ + dobj->dependencies = NULL; + dobj->nDeps = 0; + dobj->allocDeps = 0; + + while (dobj->dumpId >= allocedDumpIds) + { + int newAlloc; + + if (allocedDumpIds <= 0) + { + newAlloc = 256; + dumpIdMap = (DumpableObject **) + pg_malloc(newAlloc * sizeof(DumpableObject *)); + } + else + { + newAlloc = allocedDumpIds * 2; + dumpIdMap = (DumpableObject **) + pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *)); + } + memset(dumpIdMap + allocedDumpIds, 0, + (newAlloc - allocedDumpIds) * sizeof(DumpableObject *)); + allocedDumpIds = newAlloc; + } + dumpIdMap[dobj->dumpId] = dobj; + + /* mark catalogIdMap invalid, but don't rebuild it yet */ + catalogIdMapValid = false; +} + +/* + * Assign a DumpId that's not tied to a DumpableObject. + * + * This is used when creating a "fixed" ArchiveEntry that doesn't need to + * participate in the sorting logic. + */ +DumpId +createDumpId(void) +{ + return ++lastDumpId; +} + +/* + * Return the largest DumpId so far assigned + */ +DumpId +getMaxDumpId(void) +{ + return lastDumpId; +} + +/* + * Find a DumpableObject by dump ID + * + * Returns NULL for invalid ID + */ +DumpableObject * +findObjectByDumpId(DumpId dumpId) +{ + if (dumpId <= 0 || dumpId >= allocedDumpIds) + return NULL; /* out of range? */ + return dumpIdMap[dumpId]; +} + +/* + * Find a DumpableObject by catalog ID + * + * Returns NULL for unknown ID + * + * We use binary search in a sorted list that is built on first call. + * If AssignDumpId() and findObjectByCatalogId() calls were freely intermixed, + * the code would work, but possibly be very slow. In the current usage + * pattern that does not happen, indeed we build the list at most twice. + */ +DumpableObject * +findObjectByCatalogId(CatalogId catalogId) +{ + DumpableObject **low; + DumpableObject **high; + + if (!catalogIdMapValid) + { + if (catalogIdMap) + free(catalogIdMap); + getDumpableObjects(&catalogIdMap, &numCatalogIds); + if (numCatalogIds > 1) + qsort((void *) catalogIdMap, numCatalogIds, + sizeof(DumpableObject *), DOCatalogIdCompare); + catalogIdMapValid = true; + } + + /* + * We could use bsearch() here, but the notational cruft of calling + * bsearch is nearly as bad as doing it ourselves; and the generalized + * bsearch function is noticeably slower as well. + */ + if (numCatalogIds <= 0) + return NULL; + low = catalogIdMap; + high = catalogIdMap + (numCatalogIds - 1); + while (low <= high) + { + DumpableObject **middle; + int difference; + + middle = low + (high - low) / 2; + /* comparison must match DOCatalogIdCompare, below */ + difference = oidcmp((*middle)->catId.oid, catalogId.oid); + if (difference == 0) + difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid); + if (difference == 0) + return *middle; + else if (difference < 0) + low = middle + 1; + else + high = middle - 1; + } + return NULL; +} + +/* + * Find a DumpableObject by OID, in a pre-sorted array of one type of object + * + * Returns NULL for unknown OID + */ +static DumpableObject * +findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs) +{ + DumpableObject **low; + DumpableObject **high; + + /* + * This is the same as findObjectByCatalogId except we assume we need not + * look at table OID because the objects are all the same type. + * + * We could use bsearch() here, but the notational cruft of calling + * bsearch is nearly as bad as doing it ourselves; and the generalized + * bsearch function is noticeably slower as well. + */ + if (numObjs <= 0) + return NULL; + low = indexArray; + high = indexArray + (numObjs - 1); + while (low <= high) + { + DumpableObject **middle; + int difference; + + middle = low + (high - low) / 2; + difference = oidcmp((*middle)->catId.oid, oid); + if (difference == 0) + return *middle; + else if (difference < 0) + low = middle + 1; + else + high = middle - 1; + } + return NULL; +} + +/* + * Build an index array of DumpableObject pointers, sorted by OID + */ +static DumpableObject ** +buildIndexArray(void *objArray, int numObjs, Size objSize) +{ + DumpableObject **ptrs; + int i; + + ptrs = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *)); + for (i = 0; i < numObjs; i++) + ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize); + + /* We can use DOCatalogIdCompare to sort since its first key is OID */ + if (numObjs > 1) + qsort((void *) ptrs, numObjs, sizeof(DumpableObject *), + DOCatalogIdCompare); + + return ptrs; +} + +/* + * qsort comparator for pointers to DumpableObjects + */ +static int +DOCatalogIdCompare(const void *p1, const void *p2) +{ + const DumpableObject *obj1 = *(DumpableObject * const *) p1; + const DumpableObject *obj2 = *(DumpableObject * const *) p2; + int cmpval; + + /* + * Compare OID first since it's usually unique, whereas there will only be + * a few distinct values of tableoid. + */ + cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid); + if (cmpval == 0) + cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid); + return cmpval; +} + +/* + * Build an array of pointers to all known dumpable objects + * + * This simply creates a modifiable copy of the internal map. + */ +void +getDumpableObjects(DumpableObject ***objs, int *numObjs) +{ + int i, + j; + + *objs = (DumpableObject **) + pg_malloc(allocedDumpIds * sizeof(DumpableObject *)); + j = 0; + for (i = 1; i < allocedDumpIds; i++) + { + if (dumpIdMap[i]) + (*objs)[j++] = dumpIdMap[i]; + } + *numObjs = j; +} + +/* + * Add a dependency link to a DumpableObject + * + * Note: duplicate dependencies are currently not eliminated + */ +void +addObjectDependency(DumpableObject *dobj, DumpId refId) +{ + if (dobj->nDeps >= dobj->allocDeps) + { + if (dobj->allocDeps <= 0) + { + dobj->allocDeps = 16; + dobj->dependencies = (DumpId *) + pg_malloc(dobj->allocDeps * sizeof(DumpId)); + } + else + { + dobj->allocDeps *= 2; + dobj->dependencies = (DumpId *) + pg_realloc(dobj->dependencies, + dobj->allocDeps * sizeof(DumpId)); + } + } + dobj->dependencies[dobj->nDeps++] = refId; +} + +/* + * Remove a dependency link from a DumpableObject + * + * If there are multiple links, all are removed + */ +void +removeObjectDependency(DumpableObject *dobj, DumpId refId) +{ + int i; + int j = 0; + + for (i = 0; i < dobj->nDeps; i++) + { + if (dobj->dependencies[i] != refId) + dobj->dependencies[j++] = dobj->dependencies[i]; + } + dobj->nDeps = j; +} + + +/* + * findTableByOid + * finds the entry (in tblinfo) of the table with the given oid + * returns NULL if not found + */ +TableInfo * +findTableByOid(Oid oid) +{ + return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables); +} + +/* + * findTypeByOid + * finds the entry (in typinfo) of the type with the given oid + * returns NULL if not found + */ +TypeInfo * +findTypeByOid(Oid oid) +{ + return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes); +} + +/* + * findFuncByOid + * finds the entry (in funinfo) of the function with the given oid + * returns NULL if not found + */ +FuncInfo * +findFuncByOid(Oid oid) +{ + return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs); +} + +/* + * findOprByOid + * finds the entry (in oprinfo) of the operator with the given oid + * returns NULL if not found + */ +OprInfo * +findOprByOid(Oid oid) +{ + return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators); +} + +/* + * findCollationByOid + * finds the entry (in collinfo) of the collation with the given oid + * returns NULL if not found + */ +CollInfo * +findCollationByOid(Oid oid) +{ + return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations); +} + + +/* + * findParentsByOid + * find a table's parents in tblinfo[] + */ +static void +findParentsByOid(TableInfo *self, + InhInfo *inhinfo, int numInherits) +{ + Oid oid = self->dobj.catId.oid; + int i, + j; + int numParents; + + numParents = 0; + for (i = 0; i < numInherits; i++) + { + if (inhinfo[i].inhrelid == oid) + numParents++; + } + + self->numParents = numParents; + + if (numParents > 0) + { + self->parents = (TableInfo **) + pg_malloc(sizeof(TableInfo *) * numParents); + j = 0; + for (i = 0; i < numInherits; i++) + { + if (inhinfo[i].inhrelid == oid) + { + TableInfo *parent; + + parent = findTableByOid(inhinfo[i].inhparent); + if (parent == NULL) + { + write_msg(NULL, "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n", + inhinfo[i].inhparent, + self->dobj.name, + oid); + exit_nicely(); + } + self->parents[j++] = parent; + } + } + } + else + self->parents = NULL; +} + +/* + * parseOidArray + * parse a string of numbers delimited by spaces into a character array + * + * Note: actually this is used for both Oids and potentially-signed + * attribute numbers. This should cause no trouble, but we could split + * the function into two functions with different argument types if it does. + */ + +void +parseOidArray(const char *str, Oid *array, int arraysize) +{ + int j, + argNum; + char temp[100]; + char s; + + argNum = 0; + j = 0; + for (;;) + { + s = *str++; + if (s == ' ' || s == '\0') + { + if (j > 0) + { + if (argNum >= arraysize) + { + write_msg(NULL, "could not parse numeric array \"%s\": too many numbers\n", str); + exit_nicely(); + } + temp[j] = '\0'; + array[argNum++] = atooid(temp); + j = 0; + } + if (s == '\0') + break; + } + else + { + if (!(isdigit((unsigned char) s) || s == '-') || + j >= sizeof(temp) - 1) + { + write_msg(NULL, "could not parse numeric array \"%s\": invalid character in number\n", str); + exit_nicely(); + } + temp[j++] = s; + } + } + + while (argNum < arraysize) + array[argNum++] = InvalidOid; +} + + +/* + * strInArray: + * takes in a string and a string array and the number of elements in the + * string array. + * returns the index if the string is somewhere in the array, -1 otherwise + */ + +static int +strInArray(const char *pattern, char **arr, int arr_size) +{ + int i; + + for (i = 0; i < arr_size; i++) + { + if (strcmp(pattern, arr[i]) == 0) + return i; + } + return -1; +} + + +/* + * Support for simple list operations + */ + +void +simple_oid_list_append(SimpleOidList *list, Oid val) +{ + SimpleOidListCell *cell; + + cell = (SimpleOidListCell *) pg_malloc(sizeof(SimpleOidListCell)); + cell->next = NULL; + cell->val = val; + + if (list->tail) + list->tail->next = cell; + else + list->head = cell; + list->tail = cell; +} + +void +simple_string_list_append(SimpleStringList *list, const char *val) +{ + SimpleStringListCell *cell; + + /* this calculation correctly accounts for the null trailing byte */ + cell = (SimpleStringListCell *) + pg_malloc(sizeof(SimpleStringListCell) + strlen(val)); + cell->next = NULL; + strcpy(cell->val, val); - tmp = malloc(size); - if (!tmp) - exit_horribly(NULL, NULL, "out of memory\n"); - return tmp; + if (list->tail) + list->tail->next = cell; + else + list->head = cell; + list->tail = cell; } -void * -pg_calloc(size_t nmemb, size_t size) +bool +simple_oid_list_member(SimpleOidList *list, Oid val) { - void *tmp; + SimpleOidListCell *cell; - tmp = calloc(nmemb, size); - if (!tmp) - exit_horribly(NULL, NULL, _("out of memory\n")); - return tmp; + for (cell = list->head; cell; cell = cell->next) + { + if (cell->val == val) + return true; + } + return false; } -void * -pg_realloc(void *ptr, size_t size) +bool +simple_string_list_member(SimpleStringList *list, const char *val) { - void *tmp; + SimpleStringListCell *cell; - tmp = realloc(ptr, size); - if (!tmp) - exit_horribly(NULL, NULL, _("out of memory\n")); - return tmp; + for (cell = list->head; cell; cell = cell->next) + { + if (strcmp(cell->val, val) == 0) + return true; + } + return false; } diff --git a/src/bin/pg_dump/compress_io.c b/src/bin/pg_dump/compress_io.c index 8375762ff5a..8c1e2b8e509 100644 --- a/src/bin/pg_dump/compress_io.c +++ b/src/bin/pg_dump/compress_io.c @@ -53,7 +53,7 @@ */ #include "compress_io.h" -#include "common.h" +#include "dumpmem.h" /*---------------------- * Compressor API diff --git a/src/bin/pg_dump/dumpcatalog.c b/src/bin/pg_dump/dumpcatalog.c deleted file mode 100644 index 9747d473198..00000000000 --- a/src/bin/pg_dump/dumpcatalog.c +++ /dev/null @@ -1,978 +0,0 @@ -/*------------------------------------------------------------------------- - * - * common.c - * catalog routines used by pg_dump - * - * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/bin/pg_dump/dumpcatalog.c - * - *------------------------------------------------------------------------- - */ -#include "postgres_fe.h" - -#include <ctype.h> - -#include "catalog/pg_class.h" - -#include "pg_backup_archiver.h" -#include "common.h" - - -/* - * Variables for mapping DumpId to DumpableObject - */ -static DumpableObject **dumpIdMap = NULL; -static int allocedDumpIds = 0; -static DumpId lastDumpId = 0; - -/* - * Variables for mapping CatalogId to DumpableObject - */ -static bool catalogIdMapValid = false; -static DumpableObject **catalogIdMap = NULL; -static int numCatalogIds = 0; - -/* - * These variables are static to avoid the notational cruft of having to pass - * them into findTableByOid() and friends. For each of these arrays, we - * build a sorted-by-OID index array immediately after it's built, and then - * we use binary search in findTableByOid() and friends. (qsort'ing the base - * arrays themselves would be simpler, but it doesn't work because pg_dump.c - * may have already established pointers between items.) - */ -static TableInfo *tblinfo; -static TypeInfo *typinfo; -static FuncInfo *funinfo; -static OprInfo *oprinfo; -static int numTables; -static int numTypes; -static int numFuncs; -static int numOperators; -static int numCollations; -static DumpableObject **tblinfoindex; -static DumpableObject **typinfoindex; -static DumpableObject **funinfoindex; -static DumpableObject **oprinfoindex; -static DumpableObject **collinfoindex; - - -static void flagInhTables(TableInfo *tbinfo, int numTables, - InhInfo *inhinfo, int numInherits); -static void flagInhAttrs(TableInfo *tblinfo, int numTables); -static DumpableObject **buildIndexArray(void *objArray, int numObjs, - Size objSize); -static int DOCatalogIdCompare(const void *p1, const void *p2); -static void findParentsByOid(TableInfo *self, - InhInfo *inhinfo, int numInherits); -static int strInArray(const char *pattern, char **arr, int arr_size); - - -/* - * getSchemaData - * Collect information about all potentially dumpable objects - */ -TableInfo * -getSchemaData(int *numTablesPtr) -{ - ExtensionInfo *extinfo; - InhInfo *inhinfo; - CollInfo *collinfo; - int numNamespaces; - int numExtensions; - int numAggregates; - int numInherits; - int numRules; - int numProcLangs; - int numCasts; - int numOpclasses; - int numOpfamilies; - int numConversions; - int numTSParsers; - int numTSTemplates; - int numTSDicts; - int numTSConfigs; - int numForeignDataWrappers; - int numForeignServers; - int numDefaultACLs; - - if (g_verbose) - write_msg(NULL, "reading schemas\n"); - getNamespaces(&numNamespaces); - - /* - * getTables should be done as soon as possible, so as to minimize the - * window between starting our transaction and acquiring per-table locks. - * However, we have to do getNamespaces first because the tables get - * linked to their containing namespaces during getTables. - */ - if (g_verbose) - write_msg(NULL, "reading user-defined tables\n"); - tblinfo = getTables(&numTables); - tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo)); - - if (g_verbose) - write_msg(NULL, "reading extensions\n"); - extinfo = getExtensions(&numExtensions); - - if (g_verbose) - write_msg(NULL, "reading user-defined functions\n"); - funinfo = getFuncs(&numFuncs); - funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo)); - - /* this must be after getTables and getFuncs */ - if (g_verbose) - write_msg(NULL, "reading user-defined types\n"); - typinfo = getTypes(&numTypes); - typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo)); - - /* this must be after getFuncs, too */ - if (g_verbose) - write_msg(NULL, "reading procedural languages\n"); - getProcLangs(&numProcLangs); - - if (g_verbose) - write_msg(NULL, "reading user-defined aggregate functions\n"); - getAggregates(&numAggregates); - - if (g_verbose) - write_msg(NULL, "reading user-defined operators\n"); - oprinfo = getOperators(&numOperators); - oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo)); - - if (g_verbose) - write_msg(NULL, "reading user-defined operator classes\n"); - getOpclasses(&numOpclasses); - - if (g_verbose) - write_msg(NULL, "reading user-defined operator families\n"); - getOpfamilies(&numOpfamilies); - - if (g_verbose) - write_msg(NULL, "reading user-defined text search parsers\n"); - getTSParsers(&numTSParsers); - - if (g_verbose) - write_msg(NULL, "reading user-defined text search templates\n"); - getTSTemplates(&numTSTemplates); - - if (g_verbose) - write_msg(NULL, "reading user-defined text search dictionaries\n"); - getTSDictionaries(&numTSDicts); - - if (g_verbose) - write_msg(NULL, "reading user-defined text search configurations\n"); - getTSConfigurations(&numTSConfigs); - - if (g_verbose) - write_msg(NULL, "reading user-defined foreign-data wrappers\n"); - getForeignDataWrappers(&numForeignDataWrappers); - - if (g_verbose) - write_msg(NULL, "reading user-defined foreign servers\n"); - getForeignServers(&numForeignServers); - - if (g_verbose) - write_msg(NULL, "reading default privileges\n"); - getDefaultACLs(&numDefaultACLs); - - if (g_verbose) - write_msg(NULL, "reading user-defined collations\n"); - collinfo = getCollations(&numCollations); - collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo)); - - if (g_verbose) - write_msg(NULL, "reading user-defined conversions\n"); - getConversions(&numConversions); - - if (g_verbose) - write_msg(NULL, "reading type casts\n"); - getCasts(&numCasts); - - if (g_verbose) - write_msg(NULL, "reading table inheritance information\n"); - inhinfo = getInherits(&numInherits); - - if (g_verbose) - write_msg(NULL, "reading rewrite rules\n"); - getRules(&numRules); - - /* - * Identify extension member objects and mark them as not to be dumped. - * This must happen after reading all objects that can be direct members - * of extensions, but before we begin to process table subsidiary objects. - */ - if (g_verbose) - write_msg(NULL, "finding extension members\n"); - getExtensionMembership(extinfo, numExtensions); - - /* Link tables to parents, mark parents of target tables interesting */ - if (g_verbose) - write_msg(NULL, "finding inheritance relationships\n"); - flagInhTables(tblinfo, numTables, inhinfo, numInherits); - - if (g_verbose) - write_msg(NULL, "reading column info for interesting tables\n"); - getTableAttrs(tblinfo, numTables); - - if (g_verbose) - write_msg(NULL, "flagging inherited columns in subtables\n"); - flagInhAttrs(tblinfo, numTables); - - if (g_verbose) - write_msg(NULL, "reading indexes\n"); - getIndexes(tblinfo, numTables); - - if (g_verbose) - write_msg(NULL, "reading constraints\n"); - getConstraints(tblinfo, numTables); - - if (g_verbose) - write_msg(NULL, "reading triggers\n"); - getTriggers(tblinfo, numTables); - - *numTablesPtr = numTables; - return tblinfo; -} - -/* flagInhTables - - * Fill in parent link fields of every target table, and mark - * parents of target tables as interesting - * - * Note that only direct ancestors of targets are marked interesting. - * This is sufficient; we don't much care whether they inherited their - * attributes or not. - * - * modifies tblinfo - */ -static void -flagInhTables(TableInfo *tblinfo, int numTables, - InhInfo *inhinfo, int numInherits) -{ - int i, - j; - int numParents; - TableInfo **parents; - - for (i = 0; i < numTables; i++) - { - /* Sequences and views never have parents */ - if (tblinfo[i].relkind == RELKIND_SEQUENCE || - tblinfo[i].relkind == RELKIND_VIEW) - continue; - - /* Don't bother computing anything for non-target tables, either */ - if (!tblinfo[i].dobj.dump) - continue; - - /* Find all the immediate parent tables */ - findParentsByOid(&tblinfo[i], inhinfo, numInherits); - - /* Mark the parents as interesting for getTableAttrs */ - numParents = tblinfo[i].numParents; - parents = tblinfo[i].parents; - for (j = 0; j < numParents; j++) - parents[j]->interesting = true; - } -} - -/* flagInhAttrs - - * for each dumpable table in tblinfo, flag its inherited attributes - * so when we dump the table out, we don't dump out the inherited attributes - * - * modifies tblinfo - */ -static void -flagInhAttrs(TableInfo *tblinfo, int numTables) -{ - int i, - j, - k; - - for (i = 0; i < numTables; i++) - { - TableInfo *tbinfo = &(tblinfo[i]); - int numParents; - TableInfo **parents; - TableInfo *parent; - - /* Sequences and views never have parents */ - if (tbinfo->relkind == RELKIND_SEQUENCE || - tbinfo->relkind == RELKIND_VIEW) - continue; - - /* Don't bother computing anything for non-target tables, either */ - if (!tbinfo->dobj.dump) - continue; - - numParents = tbinfo->numParents; - parents = tbinfo->parents; - - if (numParents == 0) - continue; /* nothing to see here, move along */ - - /*---------------------------------------------------------------- - * For each attr, check the parent info: if no parent has an attr - * with the same name, then it's not inherited. If there *is* an - * attr with the same name, then only dump it if: - * - * - it is NOT NULL and zero parents are NOT NULL - * OR - * - it has a default value AND the default value does not match - * all parent default values, or no parents specify a default. - * - * See discussion on -hackers around 2-Apr-2001. - *---------------------------------------------------------------- - */ - for (j = 0; j < tbinfo->numatts; j++) - { - bool foundAttr; /* Attr was found in a parent */ - bool foundNotNull; /* Attr was NOT NULL in a parent */ - bool defaultsMatch; /* All non-empty defaults match */ - bool defaultsFound; /* Found a default in a parent */ - AttrDefInfo *attrDef; - - foundAttr = false; - foundNotNull = false; - defaultsMatch = true; - defaultsFound = false; - - attrDef = tbinfo->attrdefs[j]; - - for (k = 0; k < numParents; k++) - { - int inhAttrInd; - - parent = parents[k]; - inhAttrInd = strInArray(tbinfo->attnames[j], - parent->attnames, - parent->numatts); - - if (inhAttrInd != -1) - { - AttrDefInfo *inhDef = parent->attrdefs[inhAttrInd]; - - foundAttr = true; - foundNotNull |= parent->notnull[inhAttrInd]; - if (inhDef != NULL) - { - defaultsFound = true; - - /* - * If any parent has a default and the child doesn't, - * we have to emit an explicit DEFAULT NULL clause for - * the child, else the parent's default will win. - */ - if (attrDef == NULL) - { - attrDef = (AttrDefInfo *) pg_malloc(sizeof(AttrDefInfo)); - attrDef->dobj.objType = DO_ATTRDEF; - attrDef->dobj.catId.tableoid = 0; - attrDef->dobj.catId.oid = 0; - AssignDumpId(&attrDef->dobj); - attrDef->adtable = tbinfo; - attrDef->adnum = j + 1; - attrDef->adef_expr = pg_strdup("NULL"); - - attrDef->dobj.name = pg_strdup(tbinfo->dobj.name); - attrDef->dobj.namespace = tbinfo->dobj.namespace; - - attrDef->dobj.dump = tbinfo->dobj.dump; - - attrDef->separate = false; - addObjectDependency(&tbinfo->dobj, - attrDef->dobj.dumpId); - - tbinfo->attrdefs[j] = attrDef; - } - if (strcmp(attrDef->adef_expr, inhDef->adef_expr) != 0) - { - defaultsMatch = false; - - /* - * Whenever there is a non-matching parent - * default, add a dependency to force the parent - * default to be dumped first, in case the - * defaults end up being dumped as separate - * commands. Otherwise the parent default will - * override the child's when it is applied. - */ - addObjectDependency(&attrDef->dobj, - inhDef->dobj.dumpId); - } - } - } - } - - /* - * Based on the scan of the parents, decide if we can rely on the - * inherited attr - */ - if (foundAttr) /* Attr was inherited */ - { - /* Set inherited flag by default */ - tbinfo->inhAttrs[j] = true; - tbinfo->inhAttrDef[j] = true; - tbinfo->inhNotNull[j] = true; - - /* - * Clear it if attr had a default, but parents did not, or - * mismatch - */ - if ((attrDef != NULL) && (!defaultsFound || !defaultsMatch)) - { - tbinfo->inhAttrs[j] = false; - tbinfo->inhAttrDef[j] = false; - } - - /* - * Clear it if NOT NULL and none of the parents were NOT NULL - */ - if (tbinfo->notnull[j] && !foundNotNull) - { - tbinfo->inhAttrs[j] = false; - tbinfo->inhNotNull[j] = false; - } - - /* Clear it if attr has local definition */ - if (tbinfo->attislocal[j]) - tbinfo->inhAttrs[j] = false; - } - } - } -} - -/* - * AssignDumpId - * Given a newly-created dumpable object, assign a dump ID, - * and enter the object into the lookup table. - * - * The caller is expected to have filled in objType and catId, - * but not any of the other standard fields of a DumpableObject. - */ -void -AssignDumpId(DumpableObject *dobj) -{ - dobj->dumpId = ++lastDumpId; - dobj->name = NULL; /* must be set later */ - dobj->namespace = NULL; /* may be set later */ - dobj->dump = true; /* default assumption */ - dobj->ext_member = false; /* default assumption */ - dobj->dependencies = NULL; - dobj->nDeps = 0; - dobj->allocDeps = 0; - - while (dobj->dumpId >= allocedDumpIds) - { - int newAlloc; - - if (allocedDumpIds <= 0) - { - newAlloc = 256; - dumpIdMap = (DumpableObject **) - pg_malloc(newAlloc * sizeof(DumpableObject *)); - } - else - { - newAlloc = allocedDumpIds * 2; - dumpIdMap = (DumpableObject **) - pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *)); - } - memset(dumpIdMap + allocedDumpIds, 0, - (newAlloc - allocedDumpIds) * sizeof(DumpableObject *)); - allocedDumpIds = newAlloc; - } - dumpIdMap[dobj->dumpId] = dobj; - - /* mark catalogIdMap invalid, but don't rebuild it yet */ - catalogIdMapValid = false; -} - -/* - * Assign a DumpId that's not tied to a DumpableObject. - * - * This is used when creating a "fixed" ArchiveEntry that doesn't need to - * participate in the sorting logic. - */ -DumpId -createDumpId(void) -{ - return ++lastDumpId; -} - -/* - * Return the largest DumpId so far assigned - */ -DumpId -getMaxDumpId(void) -{ - return lastDumpId; -} - -/* - * Find a DumpableObject by dump ID - * - * Returns NULL for invalid ID - */ -DumpableObject * -findObjectByDumpId(DumpId dumpId) -{ - if (dumpId <= 0 || dumpId >= allocedDumpIds) - return NULL; /* out of range? */ - return dumpIdMap[dumpId]; -} - -/* - * Find a DumpableObject by catalog ID - * - * Returns NULL for unknown ID - * - * We use binary search in a sorted list that is built on first call. - * If AssignDumpId() and findObjectByCatalogId() calls were freely intermixed, - * the code would work, but possibly be very slow. In the current usage - * pattern that does not happen, indeed we build the list at most twice. - */ -DumpableObject * -findObjectByCatalogId(CatalogId catalogId) -{ - DumpableObject **low; - DumpableObject **high; - - if (!catalogIdMapValid) - { - if (catalogIdMap) - free(catalogIdMap); - getDumpableObjects(&catalogIdMap, &numCatalogIds); - if (numCatalogIds > 1) - qsort((void *) catalogIdMap, numCatalogIds, - sizeof(DumpableObject *), DOCatalogIdCompare); - catalogIdMapValid = true; - } - - /* - * We could use bsearch() here, but the notational cruft of calling - * bsearch is nearly as bad as doing it ourselves; and the generalized - * bsearch function is noticeably slower as well. - */ - if (numCatalogIds <= 0) - return NULL; - low = catalogIdMap; - high = catalogIdMap + (numCatalogIds - 1); - while (low <= high) - { - DumpableObject **middle; - int difference; - - middle = low + (high - low) / 2; - /* comparison must match DOCatalogIdCompare, below */ - difference = oidcmp((*middle)->catId.oid, catalogId.oid); - if (difference == 0) - difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid); - if (difference == 0) - return *middle; - else if (difference < 0) - low = middle + 1; - else - high = middle - 1; - } - return NULL; -} - -/* - * Find a DumpableObject by OID, in a pre-sorted array of one type of object - * - * Returns NULL for unknown OID - */ -static DumpableObject * -findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs) -{ - DumpableObject **low; - DumpableObject **high; - - /* - * This is the same as findObjectByCatalogId except we assume we need not - * look at table OID because the objects are all the same type. - * - * We could use bsearch() here, but the notational cruft of calling - * bsearch is nearly as bad as doing it ourselves; and the generalized - * bsearch function is noticeably slower as well. - */ - if (numObjs <= 0) - return NULL; - low = indexArray; - high = indexArray + (numObjs - 1); - while (low <= high) - { - DumpableObject **middle; - int difference; - - middle = low + (high - low) / 2; - difference = oidcmp((*middle)->catId.oid, oid); - if (difference == 0) - return *middle; - else if (difference < 0) - low = middle + 1; - else - high = middle - 1; - } - return NULL; -} - -/* - * Build an index array of DumpableObject pointers, sorted by OID - */ -static DumpableObject ** -buildIndexArray(void *objArray, int numObjs, Size objSize) -{ - DumpableObject **ptrs; - int i; - - ptrs = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *)); - for (i = 0; i < numObjs; i++) - ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize); - - /* We can use DOCatalogIdCompare to sort since its first key is OID */ - if (numObjs > 1) - qsort((void *) ptrs, numObjs, sizeof(DumpableObject *), - DOCatalogIdCompare); - - return ptrs; -} - -/* - * qsort comparator for pointers to DumpableObjects - */ -static int -DOCatalogIdCompare(const void *p1, const void *p2) -{ - const DumpableObject *obj1 = *(DumpableObject * const *) p1; - const DumpableObject *obj2 = *(DumpableObject * const *) p2; - int cmpval; - - /* - * Compare OID first since it's usually unique, whereas there will only be - * a few distinct values of tableoid. - */ - cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid); - if (cmpval == 0) - cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid); - return cmpval; -} - -/* - * Build an array of pointers to all known dumpable objects - * - * This simply creates a modifiable copy of the internal map. - */ -void -getDumpableObjects(DumpableObject ***objs, int *numObjs) -{ - int i, - j; - - *objs = (DumpableObject **) - pg_malloc(allocedDumpIds * sizeof(DumpableObject *)); - j = 0; - for (i = 1; i < allocedDumpIds; i++) - { - if (dumpIdMap[i]) - (*objs)[j++] = dumpIdMap[i]; - } - *numObjs = j; -} - -/* - * Add a dependency link to a DumpableObject - * - * Note: duplicate dependencies are currently not eliminated - */ -void -addObjectDependency(DumpableObject *dobj, DumpId refId) -{ - if (dobj->nDeps >= dobj->allocDeps) - { - if (dobj->allocDeps <= 0) - { - dobj->allocDeps = 16; - dobj->dependencies = (DumpId *) - pg_malloc(dobj->allocDeps * sizeof(DumpId)); - } - else - { - dobj->allocDeps *= 2; - dobj->dependencies = (DumpId *) - pg_realloc(dobj->dependencies, - dobj->allocDeps * sizeof(DumpId)); - } - } - dobj->dependencies[dobj->nDeps++] = refId; -} - -/* - * Remove a dependency link from a DumpableObject - * - * If there are multiple links, all are removed - */ -void -removeObjectDependency(DumpableObject *dobj, DumpId refId) -{ - int i; - int j = 0; - - for (i = 0; i < dobj->nDeps; i++) - { - if (dobj->dependencies[i] != refId) - dobj->dependencies[j++] = dobj->dependencies[i]; - } - dobj->nDeps = j; -} - - -/* - * findTableByOid - * finds the entry (in tblinfo) of the table with the given oid - * returns NULL if not found - */ -TableInfo * -findTableByOid(Oid oid) -{ - return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables); -} - -/* - * findTypeByOid - * finds the entry (in typinfo) of the type with the given oid - * returns NULL if not found - */ -TypeInfo * -findTypeByOid(Oid oid) -{ - return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes); -} - -/* - * findFuncByOid - * finds the entry (in funinfo) of the function with the given oid - * returns NULL if not found - */ -FuncInfo * -findFuncByOid(Oid oid) -{ - return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs); -} - -/* - * findOprByOid - * finds the entry (in oprinfo) of the operator with the given oid - * returns NULL if not found - */ -OprInfo * -findOprByOid(Oid oid) -{ - return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators); -} - -/* - * findCollationByOid - * finds the entry (in collinfo) of the collation with the given oid - * returns NULL if not found - */ -CollInfo * -findCollationByOid(Oid oid) -{ - return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations); -} - - -/* - * findParentsByOid - * find a table's parents in tblinfo[] - */ -static void -findParentsByOid(TableInfo *self, - InhInfo *inhinfo, int numInherits) -{ - Oid oid = self->dobj.catId.oid; - int i, - j; - int numParents; - - numParents = 0; - for (i = 0; i < numInherits; i++) - { - if (inhinfo[i].inhrelid == oid) - numParents++; - } - - self->numParents = numParents; - - if (numParents > 0) - { - self->parents = (TableInfo **) - pg_malloc(sizeof(TableInfo *) * numParents); - j = 0; - for (i = 0; i < numInherits; i++) - { - if (inhinfo[i].inhrelid == oid) - { - TableInfo *parent; - - parent = findTableByOid(inhinfo[i].inhparent); - if (parent == NULL) - { - write_msg(NULL, "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n", - inhinfo[i].inhparent, - self->dobj.name, - oid); - exit_nicely(); - } - self->parents[j++] = parent; - } - } - } - else - self->parents = NULL; -} - -/* - * parseOidArray - * parse a string of numbers delimited by spaces into a character array - * - * Note: actually this is used for both Oids and potentially-signed - * attribute numbers. This should cause no trouble, but we could split - * the function into two functions with different argument types if it does. - */ - -void -parseOidArray(const char *str, Oid *array, int arraysize) -{ - int j, - argNum; - char temp[100]; - char s; - - argNum = 0; - j = 0; - for (;;) - { - s = *str++; - if (s == ' ' || s == '\0') - { - if (j > 0) - { - if (argNum >= arraysize) - { - write_msg(NULL, "could not parse numeric array \"%s\": too many numbers\n", str); - exit_nicely(); - } - temp[j] = '\0'; - array[argNum++] = atooid(temp); - j = 0; - } - if (s == '\0') - break; - } - else - { - if (!(isdigit((unsigned char) s) || s == '-') || - j >= sizeof(temp) - 1) - { - write_msg(NULL, "could not parse numeric array \"%s\": invalid character in number\n", str); - exit_nicely(); - } - temp[j++] = s; - } - } - - while (argNum < arraysize) - array[argNum++] = InvalidOid; -} - - -/* - * strInArray: - * takes in a string and a string array and the number of elements in the - * string array. - * returns the index if the string is somewhere in the array, -1 otherwise - */ - -static int -strInArray(const char *pattern, char **arr, int arr_size) -{ - int i; - - for (i = 0; i < arr_size; i++) - { - if (strcmp(pattern, arr[i]) == 0) - return i; - } - return -1; -} - - -/* - * Support for simple list operations - */ - -void -simple_oid_list_append(SimpleOidList *list, Oid val) -{ - SimpleOidListCell *cell; - - cell = (SimpleOidListCell *) pg_malloc(sizeof(SimpleOidListCell)); - cell->next = NULL; - cell->val = val; - - if (list->tail) - list->tail->next = cell; - else - list->head = cell; - list->tail = cell; -} - -void -simple_string_list_append(SimpleStringList *list, const char *val) -{ - SimpleStringListCell *cell; - - /* this calculation correctly accounts for the null trailing byte */ - cell = (SimpleStringListCell *) - pg_malloc(sizeof(SimpleStringListCell) + strlen(val)); - cell->next = NULL; - strcpy(cell->val, val); - - if (list->tail) - list->tail->next = cell; - else - list->head = cell; - list->tail = cell; -} - -bool -simple_oid_list_member(SimpleOidList *list, Oid val) -{ - SimpleOidListCell *cell; - - for (cell = list->head; cell; cell = cell->next) - { - if (cell->val == val) - return true; - } - return false; -} - -bool -simple_string_list_member(SimpleStringList *list, const char *val) -{ - SimpleStringListCell *cell; - - for (cell = list->head; cell; cell = cell->next) - { - if (strcmp(cell->val, val) == 0) - return true; - } - return false; -} diff --git a/src/bin/pg_dump/dumpmem.c b/src/bin/pg_dump/dumpmem.c new file mode 100644 index 00000000000..a50f4f596b4 --- /dev/null +++ b/src/bin/pg_dump/dumpmem.c @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------- + * + * dumpmem.c + * memory routines used by pg_dump and pg_restore (but not pg_dumpall + * because there is no failure location to report). + * + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/bin/pg_dump/dumpmem.c + * + *------------------------------------------------------------------------- + */ +#include "postgres_fe.h" +#include "pg_backup.h" +#include "dumpmem.h" + +#include <ctype.h> + +/* + * Safer versions of some standard C library functions. If an + * out-of-memory condition occurs, these functions will bail out + * safely; therefore, their return value is guaranteed to be non-NULL. + * We also report the program name and close the database connection. + */ + +char * +pg_strdup(const char *string) +{ + char *tmp; + + if (!string) + exit_horribly(NULL, NULL, "cannot duplicate null pointer\n"); + tmp = strdup(string); + if (!tmp) + exit_horribly(NULL, NULL, "out of memory\n"); + return tmp; +} + +void * +pg_malloc(size_t size) +{ + void *tmp; + + tmp = malloc(size); + if (!tmp) + exit_horribly(NULL, NULL, "out of memory\n"); + return tmp; +} + +void * +pg_calloc(size_t nmemb, size_t size) +{ + void *tmp; + + tmp = calloc(nmemb, size); + if (!tmp) + exit_horribly(NULL, NULL, _("out of memory\n")); + return tmp; +} + +void * +pg_realloc(void *ptr, size_t size) +{ + void *tmp; + + tmp = realloc(ptr, size); + if (!tmp) + exit_horribly(NULL, NULL, _("out of memory\n")); + return tmp; +} diff --git a/src/bin/pg_dump/common.h b/src/bin/pg_dump/dumpmem.h similarity index 75% rename from src/bin/pg_dump/common.h rename to src/bin/pg_dump/dumpmem.h index 742d9f68c6c..f70b32065e6 100644 --- a/src/bin/pg_dump/common.h +++ b/src/bin/pg_dump/dumpmem.h @@ -1,18 +1,18 @@ /*------------------------------------------------------------------------- * - * common.h - * Common header file for the pg_dump, pg_dumpall, and pg_restore + * dumpmem.h + * Common header file for the pg_dump and pg_restore * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * src/bin/pg_dump/common.h + * src/bin/pg_dump/dumpmem.h * *------------------------------------------------------------------------- */ -#ifndef COMMON_H -#define COMMON_H +#ifndef DUMPMEM_H +#define DUMPMEM_H #include "postgres_fe.h" @@ -21,4 +21,4 @@ extern void *pg_malloc(size_t size); extern void *pg_calloc(size_t nmemb, size_t size); extern void *pg_realloc(void *ptr, size_t size); -#endif /* COMMON_H */ +#endif /* DUMPMEM_H */ diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index 5cc012d9e3c..92b9d28e7f1 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -16,7 +16,7 @@ #include <ctype.h> -#include "common.h" +#include "dumpmem.h" #include "dumputils.h" #include "parser/keywords.h" diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index 8fb838276fc..164d593ff9e 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -21,7 +21,7 @@ */ #include "pg_backup_db.h" -#include "common.h" +#include "dumpmem.h" #include "dumputils.h" #include <ctype.h> diff --git a/src/bin/pg_dump/pg_backup_custom.c b/src/bin/pg_dump/pg_backup_custom.c index bfdf482a6b2..b2f3196bf9c 100644 --- a/src/bin/pg_dump/pg_backup_custom.c +++ b/src/bin/pg_dump/pg_backup_custom.c @@ -25,7 +25,7 @@ */ #include "compress_io.h" -#include "common.h" +#include "dumpmem.h" /*-------- * Routines in the format interface diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c index a58eb2da701..bd1b8efac82 100644 --- a/src/bin/pg_dump/pg_backup_db.c +++ b/src/bin/pg_dump/pg_backup_db.c @@ -11,7 +11,7 @@ */ #include "pg_backup_db.h" -#include "common.h" +#include "dumpmem.h" #include "dumputils.h" #include <unistd.h> diff --git a/src/bin/pg_dump/pg_backup_directory.c b/src/bin/pg_dump/pg_backup_directory.c index 4f9fcc2be55..bd18ec517da 100644 --- a/src/bin/pg_dump/pg_backup_directory.c +++ b/src/bin/pg_dump/pg_backup_directory.c @@ -34,7 +34,7 @@ */ #include "compress_io.h" -#include "common.h" +#include "dumpmem.h" #include <dirent.h> #include <sys/stat.h> diff --git a/src/bin/pg_dump/pg_backup_files.c b/src/bin/pg_dump/pg_backup_files.c index 76366e190bc..85373b5f8ce 100644 --- a/src/bin/pg_dump/pg_backup_files.c +++ b/src/bin/pg_dump/pg_backup_files.c @@ -26,7 +26,7 @@ */ #include "pg_backup_archiver.h" -#include "common.h" +#include "dumpmem.h" static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te); static void _StartData(ArchiveHandle *AH, TocEntry *te); diff --git a/src/bin/pg_dump/pg_backup_null.c b/src/bin/pg_dump/pg_backup_null.c index 252e7a403bf..201f0d9a212 100644 --- a/src/bin/pg_dump/pg_backup_null.c +++ b/src/bin/pg_dump/pg_backup_null.c @@ -23,7 +23,7 @@ */ #include "pg_backup_archiver.h" -#include "common.h" +#include "dumpmem.h" #include "dumputils.h" #include <unistd.h> /* for dup */ diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c index 94133cf50db..39ce417d86d 100644 --- a/src/bin/pg_dump/pg_backup_tar.c +++ b/src/bin/pg_dump/pg_backup_tar.c @@ -28,7 +28,7 @@ #include "pg_backup.h" #include "pg_backup_archiver.h" #include "pg_backup_tar.h" -#include "common.h" +#include "dumpmem.h" #include <sys/stat.h> #include <ctype.h> diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index e11ba4db749..ec932e4063f 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -57,7 +57,7 @@ #include "libpq/libpq-fs.h" #include "pg_backup_archiver.h" -#include "common.h" +#include "dumpmem.h" #include "dumputils.h" extern char *optarg; diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c index 3bb220d1966..80234506752 100644 --- a/src/bin/pg_dump/pg_dump_sort.c +++ b/src/bin/pg_dump/pg_dump_sort.c @@ -14,7 +14,7 @@ *------------------------------------------------------------------------- */ #include "pg_backup_archiver.h" -#include "common.h" +#include "dumpmem.h" static const char *modulename = gettext_noop("sorter"); diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c index a810ed60b4e..ea68f5175c1 100644 --- a/src/bin/pg_dump/pg_restore.c +++ b/src/bin/pg_dump/pg_restore.c @@ -39,7 +39,7 @@ *------------------------------------------------------------------------- */ -#include "common.h" +#include "dumpmem.h" #include "pg_backup_archiver.h" #include "dumputils.h" -- GitLab