Re: [COMMITTERS] pgsql: Modify pg_dump to use error-free memory allocation macros. This
От | Bruce Momjian |
---|---|
Тема | Re: [COMMITTERS] pgsql: Modify pg_dump to use error-free memory allocation macros. This |
Дата | |
Msg-id | 201111270338.pAR3c4Z02328@momjian.us обсуждение исходный текст |
Ответ на | Re: [COMMITTERS] pgsql: Modify pg_dump to use error-free memory allocation macros. This (Tom Lane <tgl@sss.pgh.pa.us>) |
Список | pgsql-hackers |
Tom Lane wrote: > Bruce Momjian <bruce@momjian.us> writes: > > Basically, if we keep the existing functions in common.c, we are > > deciding that it is never worth moving C functions to new C files for > > source code clarity. I was not sure we had made that decision in the > > past. > > I once held hope that git would let us be more flexible about this, > but experimentation has shown that it's not significantly smarter than > CVS about back-patches in moved code :-(. > > I don't want to say that we should *never* move code once it's released; > but I think the bar for that needs to be set pretty high, and this > particular case isn't clearing the bar for me. OK, hearing no other opinions, I have moved the functions back into common.c, and created a new dumpmem.c/h. Applied patch attached. There is now no need to modify MSVC. -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + It's impossible for everything to be true. + diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile new file mode 100644 index 9d13bec..4e8e421 *** a/src/bin/pg_dump/Makefile --- b/src/bin/pg_dump/Makefile *************** override CPPFLAGS := -I$(libpq_srcdir) $ *** 20,26 **** 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) KEYWRDOBJS = keywords.o kwlookup.o --- 20,26 ---- 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 dumpmem.o dumputils.o compress_io.o $(WIN32RES) KEYWRDOBJS = keywords.o kwlookup.o *************** kwlookup.c: % : $(top_srcdir)/src/backen *** 29,36 **** 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_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) --- 29,36 ---- all: pg_dump pg_restore pg_dumpall ! 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 new file mode 100644 index 1a3f4cb..6f921f7 *** a/src/bin/pg_dump/common.c --- b/src/bin/pg_dump/common.c *************** *** 1,8 **** /*------------------------------------------------------------------------- * * common.c ! * common routines between 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 --- 1,8 ---- /*------------------------------------------------------------------------- * * common.c ! * 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,73 **** *------------------------------------------------------------------------- */ #include "postgres_fe.h" - #include "pg_backup.h" - #include "common.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; } --- 14,979 ---- *------------------------------------------------------------------------- */ #include "postgres_fe.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); ! ! ! /* ! * 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/common.h b/src/bin/pg_dump/common.h new file mode . index 742d9f6..e69de29 *** a/src/bin/pg_dump/common.h --- b/src/bin/pg_dump/common.h *************** *** 1,24 **** - /*------------------------------------------------------------------------- - * - * common.h - * Common header file for the pg_dump, pg_dumpall, 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 - * - *------------------------------------------------------------------------- - */ - - #ifndef COMMON_H - #define COMMON_H - - #include "postgres_fe.h" - - extern char *pg_strdup(const char *string); - 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 */ --- 0 ---- diff --git a/src/bin/pg_dump/compress_io.c b/src/bin/pg_dump/compress_io.c new file mode 100644 index 8375762..8c1e2b8 *** a/src/bin/pg_dump/compress_io.c --- b/src/bin/pg_dump/compress_io.c *************** *** 53,59 **** */ #include "compress_io.h" ! #include "common.h" /*---------------------- * Compressor API --- 53,59 ---- */ #include "compress_io.h" ! #include "dumpmem.h" /*---------------------- * Compressor API diff --git a/src/bin/pg_dump/dumpcatalog.c b/src/bin/pg_dump/dumpcatalog.c new file mode . index 9747d47..e69de29 *** a/src/bin/pg_dump/dumpcatalog.c --- b/src/bin/pg_dump/dumpcatalog.c *************** *** 1,978 **** - /*------------------------------------------------------------------------- - * - * 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; - } --- 0 ---- diff --git a/src/bin/pg_dump/dumpmem.c b/src/bin/pg_dump/dumpmem.c new file mode 100644 index ...a50f4f5 *** a/src/bin/pg_dump/dumpmem.c --- b/src/bin/pg_dump/dumpmem.c *************** *** 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/dumpmem.h b/src/bin/pg_dump/dumpmem.h new file mode 100644 index ...f70b320 *** a/src/bin/pg_dump/dumpmem.h --- b/src/bin/pg_dump/dumpmem.h *************** *** 0 **** --- 1,24 ---- + /*------------------------------------------------------------------------- + * + * 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/dumpmem.h + * + *------------------------------------------------------------------------- + */ + + #ifndef DUMPMEM_H + #define DUMPMEM_H + + #include "postgres_fe.h" + + extern char *pg_strdup(const char *string); + 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 /* DUMPMEM_H */ diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c new file mode 100644 index 5cc012d..92b9d28 *** a/src/bin/pg_dump/dumputils.c --- b/src/bin/pg_dump/dumputils.c *************** *** 16,22 **** #include <ctype.h> ! #include "common.h" #include "dumputils.h" #include "parser/keywords.h" --- 16,22 ---- #include <ctype.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 new file mode 100644 index 8fb8382..164d593 *** a/src/bin/pg_dump/pg_backup_archiver.c --- b/src/bin/pg_dump/pg_backup_archiver.c *************** *** 21,27 **** */ #include "pg_backup_db.h" ! #include "common.h" #include "dumputils.h" #include <ctype.h> --- 21,27 ---- */ #include "pg_backup_db.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 new file mode 100644 index bfdf482..b2f3196 *** a/src/bin/pg_dump/pg_backup_custom.c --- b/src/bin/pg_dump/pg_backup_custom.c *************** *** 25,31 **** */ #include "compress_io.h" ! #include "common.h" /*-------- * Routines in the format interface --- 25,31 ---- */ #include "compress_io.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 new file mode 100644 index a58eb2d..bd1b8ef *** a/src/bin/pg_dump/pg_backup_db.c --- b/src/bin/pg_dump/pg_backup_db.c *************** *** 11,17 **** */ #include "pg_backup_db.h" ! #include "common.h" #include "dumputils.h" #include <unistd.h> --- 11,17 ---- */ #include "pg_backup_db.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 new file mode 100644 index 4f9fcc2..bd18ec5 *** a/src/bin/pg_dump/pg_backup_directory.c --- b/src/bin/pg_dump/pg_backup_directory.c *************** *** 34,40 **** */ #include "compress_io.h" ! #include "common.h" #include <dirent.h> #include <sys/stat.h> --- 34,40 ---- */ #include "compress_io.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 new file mode 100644 index 76366e1..85373b5 *** a/src/bin/pg_dump/pg_backup_files.c --- b/src/bin/pg_dump/pg_backup_files.c *************** *** 26,32 **** */ #include "pg_backup_archiver.h" ! #include "common.h" static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te); static void _StartData(ArchiveHandle *AH, TocEntry *te); --- 26,32 ---- */ #include "pg_backup_archiver.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 new file mode 100644 index 252e7a4..201f0d9 *** a/src/bin/pg_dump/pg_backup_null.c --- b/src/bin/pg_dump/pg_backup_null.c *************** *** 23,29 **** */ #include "pg_backup_archiver.h" ! #include "common.h" #include "dumputils.h" #include <unistd.h> /* for dup */ --- 23,29 ---- */ #include "pg_backup_archiver.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 new file mode 100644 index 94133cf..39ce417 *** a/src/bin/pg_dump/pg_backup_tar.c --- b/src/bin/pg_dump/pg_backup_tar.c *************** *** 28,34 **** #include "pg_backup.h" #include "pg_backup_archiver.h" #include "pg_backup_tar.h" ! #include "common.h" #include <sys/stat.h> #include <ctype.h> --- 28,34 ---- #include "pg_backup.h" #include "pg_backup_archiver.h" #include "pg_backup_tar.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 new file mode 100644 index e11ba4d..ec932e4 *** a/src/bin/pg_dump/pg_dump.c --- b/src/bin/pg_dump/pg_dump.c *************** *** 57,63 **** #include "libpq/libpq-fs.h" #include "pg_backup_archiver.h" ! #include "common.h" #include "dumputils.h" extern char *optarg; --- 57,63 ---- #include "libpq/libpq-fs.h" #include "pg_backup_archiver.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 new file mode 100644 index 3bb220d..8023450 *** a/src/bin/pg_dump/pg_dump_sort.c --- b/src/bin/pg_dump/pg_dump_sort.c *************** *** 14,20 **** *------------------------------------------------------------------------- */ #include "pg_backup_archiver.h" ! #include "common.h" static const char *modulename = gettext_noop("sorter"); --- 14,20 ---- *------------------------------------------------------------------------- */ #include "pg_backup_archiver.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 new file mode 100644 index a810ed6..ea68f51 *** a/src/bin/pg_dump/pg_restore.c --- b/src/bin/pg_dump/pg_restore.c *************** *** 39,45 **** *------------------------------------------------------------------------- */ ! #include "common.h" #include "pg_backup_archiver.h" #include "dumputils.h" --- 39,45 ---- *------------------------------------------------------------------------- */ ! #include "dumpmem.h" #include "pg_backup_archiver.h" #include "dumputils.h"
В списке pgsql-hackers по дате отправления:
Следующее
От: NISHIYAMA TomoakiДата:
Сообщение: Re: [PATCH] PostgreSQL fails to build with 32bit MinGW-w64