/*-------------------------------------------------------------------------
*
* common.c
- * common routines between pg_dump and pg4_dump
+ * Catalog routines used by pg_dump; long ago these were shared
+ * by another dump tool, but not anymore.
*
- * Since pg4_dump is long-dead code, there is no longer any useful distinction
- * between this file and pg_dump.c.
- *
- * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.87 2005/10/15 02:49:38 momjian Exp $
+ * src/bin/pg_dump/common.c
*
*-------------------------------------------------------------------------
*/
-
-#include "postgres_fe.h"
-#include "pg_dump.h"
#include "pg_backup_archiver.h"
-#include "postgres.h"
-#include "catalog/pg_class.h"
-
#include <ctype.h>
-#include "libpq-fe.h"
-#ifndef HAVE_STRDUP
-#include "strdup.h"
-#endif
+#include "catalog/pg_class.h"
/*
/*
* These variables are static to avoid the notational cruft of having to pass
- * them into findTableByOid() and friends.
+ * 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 NamespaceInfo *nspinfo;
static int numTables;
static int numTypes;
static int numFuncs;
static int numOperators;
+static int numCollations;
+static int numNamespaces;
+static DumpableObject **tblinfoindex;
+static DumpableObject **typinfoindex;
+static DumpableObject **funinfoindex;
+static DumpableObject **oprinfoindex;
+static DumpableObject **collinfoindex;
+static DumpableObject **nspinfoindex;
static void flagInhTables(TableInfo *tbinfo, int numTables,
InhInfo *inhinfo, int numInherits);
-static void flagInhAttrs(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);
* Collect information about all potentially dumpable objects
*/
TableInfo *
-getSchemaData(int *numTablesPtr,
- const bool schemaOnly,
- const bool dataOnly)
+getSchemaData(Archive *fout, int *numTablesPtr)
{
- NamespaceInfo *nsinfo;
- AggInfo *agginfo;
+ ExtensionInfo *extinfo;
InhInfo *inhinfo;
- RuleInfo *ruleinfo;
- ProcLangInfo *proclanginfo;
- CastInfo *castinfo;
- OpclassInfo *opcinfo;
- ConvInfo *convinfo;
- int numNamespaces;
+ CollInfo *collinfo;
+ 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;
+ int numEventTriggers;
if (g_verbose)
write_msg(NULL, "reading schemas\n");
- nsinfo = getNamespaces(&numNamespaces);
+ nspinfo = getNamespaces(fout, &numNamespaces);
+ nspinfoindex = buildIndexArray(nspinfo, numNamespaces, sizeof(NamespaceInfo));
+
+ /*
+ * 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(fout, &numTables);
+ tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo));
+
+ /* Do this after we've built tblinfoindex */
+ getOwnedSeqs(fout, tblinfo, numTables);
+
+ if (g_verbose)
+ write_msg(NULL, "reading extensions\n");
+ extinfo = getExtensions(fout, &numExtensions);
if (g_verbose)
write_msg(NULL, "reading user-defined functions\n");
- funinfo = getFuncs(&numFuncs);
+ funinfo = getFuncs(fout, &numFuncs);
+ funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo));
- /* this must be after getFuncs */
+ /* this must be after getTables and getFuncs */
if (g_verbose)
write_msg(NULL, "reading user-defined types\n");
- typinfo = getTypes(&numTypes);
+ typinfo = getTypes(fout, &numTypes);
+ typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo));
/* this must be after getFuncs, too */
if (g_verbose)
write_msg(NULL, "reading procedural languages\n");
- proclanginfo = getProcLangs(&numProcLangs);
+ getProcLangs(fout, &numProcLangs);
if (g_verbose)
write_msg(NULL, "reading user-defined aggregate functions\n");
- agginfo = getAggregates(&numAggregates);
+ getAggregates(fout, &numAggregates);
if (g_verbose)
write_msg(NULL, "reading user-defined operators\n");
- oprinfo = getOperators(&numOperators);
+ oprinfo = getOperators(fout, &numOperators);
+ oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
if (g_verbose)
write_msg(NULL, "reading user-defined operator classes\n");
- opcinfo = getOpclasses(&numOpclasses);
+ getOpclasses(fout, &numOpclasses);
+
+ if (g_verbose)
+ write_msg(NULL, "reading user-defined operator families\n");
+ getOpfamilies(fout, &numOpfamilies);
+
+ if (g_verbose)
+ write_msg(NULL, "reading user-defined text search parsers\n");
+ getTSParsers(fout, &numTSParsers);
+
+ if (g_verbose)
+ write_msg(NULL, "reading user-defined text search templates\n");
+ getTSTemplates(fout, &numTSTemplates);
+
+ if (g_verbose)
+ write_msg(NULL, "reading user-defined text search dictionaries\n");
+ getTSDictionaries(fout, &numTSDicts);
+
+ if (g_verbose)
+ write_msg(NULL, "reading user-defined text search configurations\n");
+ getTSConfigurations(fout, &numTSConfigs);
+
+ if (g_verbose)
+ write_msg(NULL, "reading user-defined foreign-data wrappers\n");
+ getForeignDataWrappers(fout, &numForeignDataWrappers);
+
+ if (g_verbose)
+ write_msg(NULL, "reading user-defined foreign servers\n");
+ getForeignServers(fout, &numForeignServers);
+
+ if (g_verbose)
+ write_msg(NULL, "reading default privileges\n");
+ getDefaultACLs(fout, &numDefaultACLs);
+
+ if (g_verbose)
+ write_msg(NULL, "reading user-defined collations\n");
+ collinfo = getCollations(fout, &numCollations);
+ collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
if (g_verbose)
write_msg(NULL, "reading user-defined conversions\n");
- convinfo = getConversions(&numConversions);
+ getConversions(fout, &numConversions);
if (g_verbose)
- write_msg(NULL, "reading user-defined tables\n");
- tblinfo = getTables(&numTables);
+ write_msg(NULL, "reading type casts\n");
+ getCasts(fout, &numCasts);
if (g_verbose)
write_msg(NULL, "reading table inheritance information\n");
- inhinfo = getInherits(&numInherits);
+ inhinfo = getInherits(fout, &numInherits);
if (g_verbose)
write_msg(NULL, "reading rewrite rules\n");
- ruleinfo = getRules(&numRules);
+ getRules(fout, &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, "reading type casts\n");
- castinfo = getCasts(&numCasts);
+ write_msg(NULL, "finding extension members\n");
+ getExtensionMembership(fout, extinfo, numExtensions);
/* Link tables to parents, mark parents of target tables interesting */
if (g_verbose)
if (g_verbose)
write_msg(NULL, "reading column info for interesting tables\n");
- getTableAttrs(tblinfo, numTables);
+ getTableAttrs(fout, tblinfo, numTables);
if (g_verbose)
write_msg(NULL, "flagging inherited columns in subtables\n");
- flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
+ flagInhAttrs(tblinfo, numTables);
if (g_verbose)
write_msg(NULL, "reading indexes\n");
- getIndexes(tblinfo, numTables);
+ getIndexes(fout, tblinfo, numTables);
if (g_verbose)
write_msg(NULL, "reading constraints\n");
- getConstraints(tblinfo, numTables);
+ getConstraints(fout, tblinfo, numTables);
if (g_verbose)
write_msg(NULL, "reading triggers\n");
- getTriggers(tblinfo, numTables);
+ getTriggers(fout, tblinfo, numTables);
+
+ if (g_verbose)
+ write_msg(NULL, "reading event triggers\n");
+ getEventTriggers(fout, &numEventTriggers);
*numTablesPtr = numTables;
return tblinfo;
continue;
/* Don't bother computing anything for non-target tables, either */
- if (!tblinfo[i].dump)
+ if (!tblinfo[i].dobj.dump)
continue;
/* Find all the immediate parent tables */
/* 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
+ *
+ * What we need to do here is detect child columns that inherit NOT NULL
+ * bits from their parents (so that we needn't specify that again for the
+ * child) and child columns that have DEFAULT NULL when their parents had
+ * some non-null default. In the latter case, we make up a dummy AttrDefInfo
+ * object so that we'll correctly emit the necessary DEFAULT NULL clause;
+ * otherwise the backend will apply an inherited default to the column.
*
* modifies tblinfo
*/
static void
-flagInhAttrs(TableInfo *tblinfo, int numTables,
- InhInfo *inhinfo, int numInherits)
+flagInhAttrs(TableInfo *tblinfo, int numTables)
{
int i,
j,
TableInfo *tbinfo = &(tblinfo[i]);
int numParents;
TableInfo **parents;
- TableInfo *parent;
/* Sequences and views never have parents */
if (tbinfo->relkind == RELKIND_SEQUENCE ||
continue;
/* Don't bother computing anything for non-target tables, either */
- if (!tbinfo->dump)
+ if (!tbinfo->dobj.dump)
continue;
numParents = tbinfo->numParents;
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 each column, search for matching column names in parent(s) */
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;
+ bool foundDefault; /* Found a default in a parent */
- attrDef = tbinfo->attrdefs[j];
+ /* no point in examining dropped columns */
+ if (tbinfo->attisdropped[j])
+ continue;
+ foundNotNull = false;
+ foundDefault = false;
for (k = 0; k < numParents; k++)
{
+ TableInfo *parent = parents[k];
int inhAttrInd;
- parent = parents[k];
inhAttrInd = strInArray(tbinfo->attnames[j],
parent->attnames,
parent->numatts);
-
- if (inhAttrInd != -1)
+ if (inhAttrInd >= 0)
{
- foundAttr = true;
foundNotNull |= parent->notnull[inhAttrInd];
- if (attrDef != NULL) /* If we have a default, check
- * parent */
- {
- AttrDefInfo *inhDef;
-
- inhDef = parent->attrdefs[inhAttrInd];
- if (inhDef != NULL)
- {
- defaultsFound = true;
- defaultsMatch &= (strcmp(attrDef->adef_expr,
- inhDef->adef_expr) == 0);
- }
- }
+ foundDefault |= (parent->attrdefs[inhAttrInd] != NULL);
}
}
- /*
- * Based on the scan of the parents, decide if we can rely on the
- * inherited attr
- */
- if (foundAttr) /* Attr was inherited */
+ /* Remember if we found inherited NOT NULL */
+ tbinfo->inhNotNull[j] = foundNotNull;
+
+ /* Manufacture a DEFAULT NULL clause if necessary */
+ if (foundDefault && tbinfo->attrdefs[j] == NULL)
{
- /* 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))
+ AttrDefInfo *attrDef;
+
+ 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->dobj.name = pg_strdup(tbinfo->dobj.name);
+ attrDef->dobj.namespace = tbinfo->dobj.namespace;
+ attrDef->dobj.dump = tbinfo->dobj.dump;
+
+ attrDef->adtable = tbinfo;
+ attrDef->adnum = j + 1;
+ attrDef->adef_expr = pg_strdup("NULL");
+
+ /* Will column be dumped explicitly? */
+ if (shouldPrintColumn(tbinfo, j))
{
- tbinfo->inhAttrs[j] = false;
- tbinfo->inhAttrDef[j] = false;
+ attrDef->separate = false;
+ /* No dependency needed: NULL cannot have dependencies */
}
-
- /*
- * Clear it if NOT NULL and none of the parents were NOT NULL
- */
- if (tbinfo->notnull[j] && !foundNotNull)
+ else
{
- tbinfo->inhAttrs[j] = false;
- tbinfo->inhNotNull[j] = false;
+ /* column will be suppressed, print default separately */
+ attrDef->separate = true;
+ /* ensure it comes out after the table */
+ addObjectDependency(&attrDef->dobj,
+ tbinfo->dobj.dumpId);
}
- /* Clear it if attr has local definition */
- if (tbinfo->attislocal[j])
- tbinfo->inhAttrs[j] = false;
- }
- }
-
- /*
- * Check for inherited CHECK constraints. We assume a constraint is
- * inherited if its name matches the name of any constraint in the
- * parent. Originally this code tried to compare the expression
- * texts, but that can fail if the parent and child tables are in
- * different schemas, because reverse-listing of function calls may
- * produce different text (schema-qualified or not) depending on
- * search path. We really need a more bulletproof way of detecting
- * inherited constraints --- pg_constraint should record this
- * explicitly!
- */
- for (j = 0; j < tbinfo->ncheck; j++)
- {
- ConstraintInfo *constr;
-
- constr = &(tbinfo->checkexprs[j]);
-
- for (k = 0; k < numParents; k++)
- {
- int l;
-
- parent = parents[k];
- for (l = 0; l < parent->ncheck; l++)
- {
- ConstraintInfo *pconstr = &(parent->checkexprs[l]);
-
- if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
- {
- constr->coninherited = true;
- break;
- }
- }
- if (constr->coninherited)
- break;
+ tbinfo->attrdefs[j] = attrDef;
}
}
}
* 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 catalogId,
+ * The caller is expected to have filled in objType and catId,
* but not any of the other standard fields of a DumpableObject.
*/
void
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;
{
newAlloc = 256;
dumpIdMap = (DumpableObject **)
- malloc(newAlloc * sizeof(DumpableObject *));
+ pg_malloc(newAlloc * sizeof(DumpableObject *));
}
else
{
newAlloc = allocedDumpIds * 2;
dumpIdMap = (DumpableObject **)
- realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
+ pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
}
- if (dumpIdMap == NULL)
- exit_horribly(NULL, NULL, "out of memory\n");
memset(dumpIdMap + allocedDumpIds, 0,
(newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
allocedDumpIds = newAlloc;
* 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 intermixed,
+ * 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 only need to build the list once.
+ * pattern that does not happen, indeed we build the list at most twice.
*/
DumpableObject *
findObjectByCatalogId(CatalogId catalogId)
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)
{
- DumpableObject *obj1 = *(DumpableObject **) p1;
- DumpableObject *obj2 = *(DumpableObject **) p2;
+ const DumpableObject *obj1 = *(DumpableObject *const *) p1;
+ const DumpableObject *obj2 = *(DumpableObject *const *) p2;
int cmpval;
/*
j;
*objs = (DumpableObject **)
- malloc(allocedDumpIds * sizeof(DumpableObject *));
- if (*objs == NULL)
- exit_horribly(NULL, NULL, "out of memory\n");
+ pg_malloc(allocedDumpIds * sizeof(DumpableObject *));
j = 0;
for (i = 1; i < allocedDumpIds; i++)
{
{
dobj->allocDeps = 16;
dobj->dependencies = (DumpId *)
- malloc(dobj->allocDeps * sizeof(DumpId));
+ pg_malloc(dobj->allocDeps * sizeof(DumpId));
}
else
{
dobj->allocDeps *= 2;
dobj->dependencies = (DumpId *)
- realloc(dobj->dependencies,
- dobj->allocDeps * sizeof(DumpId));
+ pg_realloc(dobj->dependencies,
+ dobj->allocDeps * sizeof(DumpId));
}
- if (dobj->dependencies == NULL)
- exit_horribly(NULL, NULL, "out of memory\n");
}
dobj->dependencies[dobj->nDeps++] = refId;
}
* findTableByOid
* finds the entry (in tblinfo) of the table with the given oid
* returns NULL if not found
- *
- * NOTE: should hash this, but just do linear search for now
*/
TableInfo *
findTableByOid(Oid oid)
{
- int i;
-
- for (i = 0; i < numTables; i++)
- {
- if (tblinfo[i].dobj.catId.oid == oid)
- return &tblinfo[i];
- }
- return NULL;
+ return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
}
/*
* findTypeByOid
* finds the entry (in typinfo) of the type with the given oid
* returns NULL if not found
- *
- * NOTE: should hash this, but just do linear search for now
*/
TypeInfo *
findTypeByOid(Oid oid)
{
- int i;
-
- for (i = 0; i < numTypes; i++)
- {
- if (typinfo[i].dobj.catId.oid == oid)
- return &typinfo[i];
- }
- return NULL;
+ return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
}
/*
* findFuncByOid
* finds the entry (in funinfo) of the function with the given oid
* returns NULL if not found
- *
- * NOTE: should hash this, but just do linear search for now
*/
FuncInfo *
findFuncByOid(Oid oid)
{
- int i;
-
- for (i = 0; i < numFuncs; i++)
- {
- if (funinfo[i].dobj.catId.oid == oid)
- return &funinfo[i];
- }
- return NULL;
+ return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
}
/*
* findOprByOid
* finds the entry (in oprinfo) of the operator with the given oid
* returns NULL if not found
- *
- * NOTE: should hash this, but just do linear search for now
*/
OprInfo *
findOprByOid(Oid oid)
{
- int i;
+ return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
+}
- for (i = 0; i < numOperators; i++)
- {
- if (oprinfo[i].dobj.catId.oid == oid)
- return &oprinfo[i];
- }
- return NULL;
+/*
+ * 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);
+}
+
+/*
+ * findNamespaceByOid
+ * finds the entry (in nspinfo) of the namespace with the given oid
+ * returns NULL if not found
+ */
+NamespaceInfo *
+findNamespaceByOid(Oid oid)
+{
+ return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
}
if (numParents > 0)
{
- self->parents = (TableInfo **) malloc(sizeof(TableInfo *) * numParents);
+ self->parents = (TableInfo **)
+ pg_malloc(sizeof(TableInfo *) * numParents);
j = 0;
for (i = 0; i < numInherits; i++)
{
inhinfo[i].inhparent,
self->dobj.name,
oid);
- exit_nicely();
+ exit_nicely(1);
}
self->parents[j++] = parent;
}
{
if (argNum >= arraysize)
{
- write_msg(NULL, "could not parse numeric array: too many numbers\n");
- exit_nicely();
+ write_msg(NULL, "could not parse numeric array \"%s\": too many numbers\n", str);
+ exit_nicely(1);
}
temp[j] = '\0';
array[argNum++] = atooid(temp);
if (!(isdigit((unsigned char) s) || s == '-') ||
j >= sizeof(temp) - 1)
{
- write_msg(NULL, "could not parse numeric array: invalid character in number\n");
- exit_nicely();
+ write_msg(NULL, "could not parse numeric array \"%s\": invalid character in number\n", str);
+ exit_nicely(1);
}
temp[j++] = s;
}
}
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;
+}
+
+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;
+}