Massive overhaul of pg_dump: make use of dependency information from

pg_depend to determine a safe dump order.  Defaults and check constraints
can be emitted either as part of a table or domain definition, or
separately if that's needed to break a dependency loop.  Lots of old
half-baked code for controlling dump order removed.
This commit is contained in:
Tom Lane 2003-12-06 03:00:16 +00:00
parent a5ffa8fea4
commit 005a1217fb
14 changed files with 4446 additions and 3320 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/pg_restore.sgml,v 1.44 2003/11/29 19:51:39 pgsql Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/pg_restore.sgml,v 1.45 2003/12/06 03:00:10 tgl Exp $ -->
<refentry id="APP-PGRESTORE">
<refmeta>
@ -227,35 +227,6 @@
</listitem>
</varlistentry>
<varlistentry>
<term><option>-N</option></term>
<term><option>--orig-order</option></term>
<listitem>
<para>
Restore items in the order they were originally generated within
<application>pg_dump</application>. This option has no known
practical use, since <application>pg_dump</application> generates
the items in an order convenient to it, which is unlikely to be a
safe order for restoring them. (This is <emphasis>not</> the order
in which the items are ultimately listed in the archive's table of
contents.) See also <option>-r</>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-o</option></term>
<term><option>--oid-order</option></term>
<listitem>
<para>
Restore items in order by OID. This option is of limited usefulness,
since OID is only an approximate indication of original creation
order. This option overrides <option>-N</> if both are specified.
See also <option>-r</>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-O</option></term>
<term><option>--no-owner</option></term>
@ -287,31 +258,6 @@
</listitem>
</varlistentry>
<varlistentry>
<term><option>-r</option></term>
<term><option>--rearrange</option></term>
<listitem>
<para>
Rearrange items by object type (this occurs after the sorting
specified by <option>-N</option> or <option>-o</option>, if
given). The rearrangement is intended to give the best possible
restore performance.
</para>
<para>
When none of <option>-N</option>, <option>-o</option>, and
<option>-r</> appear, <application>pg_restore</application> restores
items in the order they appear in the dump's table of contents,
or in the order they appear in the <REPLACEABLE
CLASS="PARAMETER">list-file</REPLACEABLE> if <option>-L</> is
given. The combination of <option>-o</> and <option>-r</>
duplicates the sorting done by <application>pg_dump</application>
before creating the dump's table of contents,
and so it is normally unnecessary to specify it.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-R</option></term>
<term><option>--no-reconnect</option></term>

View File

@ -5,7 +5,7 @@
# Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
# $PostgreSQL: pgsql/src/bin/pg_dump/Makefile,v 1.41 2003/11/29 19:52:04 pgsql Exp $
# $PostgreSQL: pgsql/src/bin/pg_dump/Makefile,v 1.42 2003/12/06 03:00:11 tgl Exp $
#
#-------------------------------------------------------------------------
@ -24,8 +24,8 @@ override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS) -DBINDIR=\"$(bindir)\"
all: submake-libpq submake-libpgport submake-backend pg_dump pg_restore pg_dumpall
pg_dump: pg_dump.o common.o $(OBJS) $(libpq_builddir)/libpq.a
$(CC) $(CFLAGS) pg_dump.o common.o $(OBJS) $(EXTRA_OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@
pg_dump: pg_dump.o common.o pg_dump_sort.o $(OBJS) $(libpq_builddir)/libpq.a
$(CC) $(CFLAGS) pg_dump.o common.o pg_dump_sort.o $(OBJS) $(EXTRA_OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@
pg_restore: pg_restore.o $(OBJS) $(libpq_builddir)/libpq.a
$(CC) $(CFLAGS) pg_restore.o $(OBJS) $(EXTRA_OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@
@ -50,4 +50,4 @@ uninstall:
rm -f $(addprefix $(DESTDIR)$(bindir)/, pg_dump$(X) pg_restore$(X) pg_dumpall$(X))
clean distclean maintainer-clean:
rm -f pg_dump$(X) pg_restore$(X) pg_dumpall$(X) $(OBJS) pg_dump.o common.o pg_restore.o pg_dumpall.o
rm -f pg_dump$(X) pg_restore$(X) pg_dumpall$(X) $(OBJS) pg_dump.o common.o pg_dump_sort.o pg_restore.o pg_dumpall.o

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.77 2003/11/29 19:52:04 pgsql Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.78 2003/12/06 03:00:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -29,10 +29,30 @@
#include "strdup.h"
#endif
static void findParentsByOid(TableInfo *tblinfo, int numTables,
InhInfo *inhinfo, int numInherits,
const char *oid,
int *numParentsPtr, int **parentIndexes);
/*
* Variables for mapping DumpId to DumpableObject
*/
static DumpableObject **dumpIdMap = NULL;
static int allocedDumpIds = 0;
static DumpId lastDumpId = 0;
/*
* These variables are static to avoid the notational cruft of having to pass
* them into findTableByOid() and friends.
*/
static TableInfo *tblinfo;
static TypeInfo *tinfo;
static FuncInfo *finfo;
static OprInfo *oprinfo;
static int numTables;
static int numTypes;
static int numFuncs;
static int numOperators;
static void findParentsByOid(TableInfo *self,
InhInfo *inhinfo, int numInherits);
static void flagInhTables(TableInfo *tbinfo, int numTables,
InhInfo *inhinfo, int numInherits);
static void flagInhAttrs(TableInfo *tbinfo, int numTables,
@ -41,48 +61,48 @@ static int strInArray(const char *pattern, char **arr, int arr_size);
/*
* dumpSchema:
* we have a valid connection, we are now going to dump the schema
* into the file
* getSchemaData
* Collect information about all potentially dumpable objects
*/
TableInfo *
dumpSchema(Archive *fout,
int *numTablesPtr,
const bool aclsSkip,
const bool schemaOnly,
const bool dataOnly)
getSchemaData(int *numTablesPtr,
const bool schemaOnly,
const bool dataOnly)
{
NamespaceInfo *nsinfo;
AggInfo *agginfo;
InhInfo *inhinfo;
RuleInfo *ruleinfo;
ProcLangInfo *proclanginfo;
CastInfo *castinfo;
OpclassInfo *opcinfo;
ConvInfo *convinfo;
int numNamespaces;
int numTypes;
int numFuncs;
int numTables;
int numInherits;
int numAggregates;
int numOperators;
int numInherits;
int numRules;
int numProcLangs;
int numCasts;
int numOpclasses;
int numConversions;
NamespaceInfo *nsinfo;
TypeInfo *tinfo;
FuncInfo *finfo;
AggInfo *agginfo;
TableInfo *tblinfo;
InhInfo *inhinfo;
OprInfo *oprinfo;
OpclassInfo *opcinfo;
ConvInfo *convinfo;
if (g_verbose)
write_msg(NULL, "reading schemas\n");
nsinfo = getNamespaces(&numNamespaces);
if (g_verbose)
write_msg(NULL, "reading user-defined functions\n");
finfo = getFuncs(&numFuncs);
/* this must be after getFuncs */
if (g_verbose)
write_msg(NULL, "reading user-defined types\n");
tinfo = getTypes(&numTypes);
/* this must be after getFuncs, too */
if (g_verbose)
write_msg(NULL, "reading user-defined functions\n");
finfo = getFuncs(&numFuncs);
write_msg(NULL, "reading procedural languages\n");
proclanginfo = getProcLangs(&numProcLangs);
if (g_verbose)
write_msg(NULL, "reading user-defined aggregate functions\n");
@ -108,6 +128,14 @@ dumpSchema(Archive *fout,
write_msg(NULL, "reading table inheritance information\n");
inhinfo = getInherits(&numInherits);
if (g_verbose)
write_msg(NULL, "reading rewrite rules\n");
ruleinfo = getRules(&numRules);
if (g_verbose)
write_msg(NULL, "reading type casts\n");
castinfo = getCasts(&numCasts);
/* Link tables to parents, mark parents of target tables interesting */
if (g_verbose)
write_msg(NULL, "finding inheritance relationships\n");
@ -121,94 +149,24 @@ dumpSchema(Archive *fout,
write_msg(NULL, "flagging inherited columns in subtables\n");
flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
if (!dataOnly)
{
if (g_verbose)
write_msg(NULL, "dumping out database comment\n");
dumpDBComment(fout);
}
if (!dataOnly)
{
if (g_verbose)
write_msg(NULL, "dumping out user-defined schemas\n");
dumpNamespaces(fout, nsinfo, numNamespaces);
}
if (!dataOnly)
{
if (g_verbose)
write_msg(NULL, "dumping out user-defined types\n");
dumpTypes(fout, finfo, numFuncs, tinfo, numTypes);
}
if (g_verbose)
write_msg(NULL, "reading indexes\n");
getIndexes(tblinfo, numTables);
if (g_verbose)
write_msg(NULL, "dumping out tables\n");
dumpTables(fout, tblinfo, numTables,
aclsSkip, schemaOnly, dataOnly);
write_msg(NULL, "reading constraints\n");
getConstraints(tblinfo, numTables);
if (!dataOnly)
{
if (g_verbose)
write_msg(NULL, "dumping out indexes\n");
dumpIndexes(fout, tblinfo, numTables);
}
if (!dataOnly)
{
if (g_verbose)
write_msg(NULL, "dumping out user-defined procedural languages\n");
dumpProcLangs(fout, finfo, numFuncs);
}
if (!dataOnly)
{
if (g_verbose)
write_msg(NULL, "dumping out user-defined functions\n");
dumpFuncs(fout, finfo, numFuncs);
}
if (!dataOnly)
{
if (g_verbose)
write_msg(NULL, "dumping out user-defined aggregate functions\n");
dumpAggs(fout, agginfo, numAggregates);
}
if (!dataOnly)
{
if (g_verbose)
write_msg(NULL, "dumping out user-defined operators\n");
dumpOprs(fout, oprinfo, numOperators);
}
if (!dataOnly)
{
if (g_verbose)
write_msg(NULL, "dumping out user-defined operator classes\n");
dumpOpclasses(fout, opcinfo, numOpclasses);
}
if (!dataOnly)
{
if (g_verbose)
write_msg(NULL, "dumping out user-defined casts\n");
dumpCasts(fout, finfo, numFuncs, tinfo, numTypes);
}
if (!dataOnly)
{
if (g_verbose)
write_msg(NULL, "dumping out user-defined conversions\n");
dumpConversions(fout, convinfo, numConversions);
}
if (g_verbose)
write_msg(NULL, "reading triggers\n");
getTriggers(tblinfo, numTables);
*numTablesPtr = numTables;
return tblinfo;
}
/* flagInhTables -
* Fill in parentIndexes fields of every target table, and mark
* 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.
@ -224,7 +182,7 @@ flagInhTables(TableInfo *tblinfo, int numTables,
int i,
j;
int numParents;
int *parentIndexes;
TableInfo **parents;
for (i = 0; i < numTables; i++)
{
@ -238,21 +196,13 @@ flagInhTables(TableInfo *tblinfo, int numTables,
continue;
/* Find all the immediate parent tables */
findParentsByOid(tblinfo, numTables,
inhinfo, numInherits,
tblinfo[i].oid,
&tblinfo[i].numParents,
&tblinfo[i].parentIndexes);
numParents = tblinfo[i].numParents;
parentIndexes = tblinfo[i].parentIndexes;
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++)
{
int parentInd = parentIndexes[j];
tblinfo[parentInd].interesting = true;
}
parents[j]->interesting = true;
}
}
@ -269,30 +219,25 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
int i,
j,
k;
int parentInd;
int inhAttrInd;
int numParents;
int *parentIndexes;
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 */
char *attrDef;
char *inhDef;
for (i = 0; i < numTables; i++)
{
TableInfo *tbinfo = &(tblinfo[i]);
int numParents;
TableInfo **parents;
TableInfo *parent;
/* Sequences and views never have parents */
if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
tblinfo[i].relkind == RELKIND_VIEW)
if (tbinfo->relkind == RELKIND_SEQUENCE ||
tbinfo->relkind == RELKIND_VIEW)
continue;
/* Don't bother computing anything for non-target tables, either */
if (!tblinfo[i].dump)
if (!tbinfo->dump)
continue;
numParents = tblinfo[i].numParents;
parentIndexes = tblinfo[i].parentIndexes;
numParents = tbinfo->numParents;
parents = tbinfo->parents;
if (numParents == 0)
continue; /* nothing to see here, move along */
@ -310,35 +255,45 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
* See discussion on -hackers around 2-Apr-2001.
*----------------------------------------------------------------
*/
for (j = 0; j < tblinfo[i].numatts; j++)
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 = tblinfo[i].adef_expr[j];
attrDef = tbinfo->attrdefs[j];
for (k = 0; k < numParents; k++)
{
parentInd = parentIndexes[k];
inhAttrInd = strInArray(tblinfo[i].attnames[j],
tblinfo[parentInd].attnames,
tblinfo[parentInd].numatts);
int inhAttrInd;
parent = parents[k];
inhAttrInd = strInArray(tbinfo->attnames[j],
parent->attnames,
parent->numatts);
if (inhAttrInd != -1)
{
foundAttr = true;
foundNotNull |= tblinfo[parentInd].notnull[inhAttrInd];
foundNotNull |= parent->notnull[inhAttrInd];
if (attrDef != NULL) /* If we have a default,
* check parent */
{
inhDef = tblinfo[parentInd].adef_expr[inhAttrInd];
AttrDefInfo *inhDef;
inhDef = parent->attrdefs[inhAttrInd];
if (inhDef != NULL)
{
defaultsFound = true;
defaultsMatch &= (strcmp(attrDef, inhDef) == 0);
defaultsMatch &= (strcmp(attrDef->adef_expr,
inhDef->adef_expr) == 0);
}
}
}
@ -351,9 +306,9 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
if (foundAttr) /* Attr was inherited */
{
/* Set inherited flag by default */
tblinfo[i].inhAttrs[j] = true;
tblinfo[i].inhAttrDef[j] = true;
tblinfo[i].inhNotNull[j] = true;
tbinfo->inhAttrs[j] = true;
tbinfo->inhAttrDef[j] = true;
tbinfo->inhNotNull[j] = true;
/*
* Clear it if attr had a default, but parents did not, or
@ -361,181 +316,377 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
*/
if ((attrDef != NULL) && (!defaultsFound || !defaultsMatch))
{
tblinfo[i].inhAttrs[j] = false;
tblinfo[i].inhAttrDef[j] = false;
tbinfo->inhAttrs[j] = false;
tbinfo->inhAttrDef[j] = false;
}
/*
* Clear it if NOT NULL and none of the parents were NOT
* NULL
*/
if (tblinfo[i].notnull[j] && !foundNotNull)
if (tbinfo->notnull[j] && !foundNotNull)
{
tblinfo[i].inhAttrs[j] = false;
tblinfo[i].inhNotNull[j] = false;
tbinfo->inhAttrs[j] = false;
tbinfo->inhNotNull[j] = false;
}
/* Clear it if attr has local definition */
if (g_fout->remoteVersion >= 70300 && tblinfo[i].attislocal[j])
tblinfo[i].inhAttrs[j] = false;
if (tbinfo->attislocal[j])
tbinfo->inhAttrs[j] = false;
}
}
/*
* Check for inherited CHECK constraints. We assume a constraint
* is inherited if its expression matches the parent and the name
* is the same, *or* both names start with '$'.
*/
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;
pconstr = &(parent->checkexprs[l]);
if (strcmp(pconstr->condef, constr->condef) != 0)
continue;
if (strcmp(pconstr->conname, constr->conname) == 0 ||
(pconstr->conname[0] == '$' &&
constr->conname[0] == '$'))
{
constr->coninherited = true;
break;
}
}
if (constr->coninherited)
break;
}
}
}
}
/*
* 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 catalogId,
* but not any of the other standard fields of a DumpableObject.
*/
void
AssignDumpId(DumpableObject *dobj)
{
dobj->dumpId = ++lastDumpId;
dobj->dependencies = NULL;
dobj->nDeps = 0;
dobj->allocDeps = 0;
while (dobj->dumpId >= allocedDumpIds)
{
int newAlloc;
if (allocedDumpIds <= 0)
{
newAlloc = 256;
dumpIdMap = (DumpableObject **)
malloc(newAlloc * sizeof(DumpableObject *));
}
else
{
newAlloc = allocedDumpIds * 2;
dumpIdMap = (DumpableObject **)
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;
}
dumpIdMap[dobj->dumpId] = dobj;
}
/*
* 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
*
* NOTE: should hash this, but just do linear search for now
*/
DumpableObject *
findObjectByCatalogId(CatalogId catalogId)
{
DumpId i;
for (i = 1; i < allocedDumpIds; i++)
{
DumpableObject *dobj = dumpIdMap[i];
if (dobj &&
dobj->catId.tableoid == catalogId.tableoid &&
dobj->catId.oid == catalogId.oid)
return dobj;
}
return NULL;
}
/*
* 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 **)
malloc(allocedDumpIds * sizeof(DumpableObject *));
if (*objs == NULL)
exit_horribly(NULL, NULL, "out of memory\n");
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 *)
malloc(dobj->allocDeps * sizeof(DumpId));
}
else
{
dobj->allocDeps *= 2;
dobj->dependencies = (DumpId *)
realloc(dobj->dependencies,
dobj->allocDeps * sizeof(DumpId));
}
if (dobj->dependencies == NULL)
exit_horribly(NULL, NULL, "out of memory\n");
}
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 index (in tblinfo) of the table with the given oid
* returns -1 if not found
* 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
*/
int
findTableByOid(TableInfo *tblinfo, int numTables, const char *oid)
TableInfo *
findTableByOid(Oid oid)
{
int i;
for (i = 0; i < numTables; i++)
{
if (strcmp(tblinfo[i].oid, oid) == 0)
return i;
if (tblinfo[i].dobj.catId.oid == oid)
return &tblinfo[i];
}
return -1;
return NULL;
}
/*
* findFuncByOid
* finds the index (in finfo) of the function with the given OID
* returns -1 if not found
* findTypeByOid
* finds the entry (in tinfo) of the type with the given oid
* returns NULL if not found
*
* NOTE: should hash this, but just do linear search for now
*/
int
findFuncByOid(FuncInfo *finfo, int numFuncs, const char *oid)
{
int i;
for (i = 0; i < numFuncs; i++)
{
if (strcmp(finfo[i].oid, oid) == 0)
return i;
}
return -1;
}
/*
* Finds the index (in tinfo) of the type with the given OID. Returns
* -1 if not found.
*/
int
findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid)
TypeInfo *
findTypeByOid(Oid oid)
{
int i;
for (i = 0; i < numTypes; i++)
{
if (strcmp(tinfo[i].oid, oid) == 0)
return i;
if (tinfo[i].dobj.catId.oid == oid)
return &tinfo[i];
}
return -1;
return NULL;
}
/*
* findFuncByOid
* finds the entry (in finfo) 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 (finfo[i].dobj.catId.oid == oid)
return &finfo[i];
}
return NULL;
}
/*
* findOprByOid
* given the oid of an operator, return the name of the operator
* 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
*/
char *
findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid)
OprInfo *
findOprByOid(Oid oid)
{
int i;
for (i = 0; i < numOprs; i++)
for (i = 0; i < numOperators; i++)
{
if (strcmp(oprinfo[i].oid, oid) == 0)
return oprinfo[i].oprname;
if (oprinfo[i].dobj.catId.oid == oid)
return &oprinfo[i];
}
/* should never get here */
write_msg(NULL, "failed sanity check, operator with OID %s not found\n", oid);
/* no suitable operator name was found */
return (NULL);
return NULL;
}
/*
* findParentsByOid
* given the oid of a class, find its parent classes in tblinfo[]
*
* Returns the number of parents and their array indexes into the
* last two arguments.
* find a table's parents in tblinfo[]
*/
static void
findParentsByOid(TableInfo *tblinfo, int numTables,
InhInfo *inhinfo, int numInherits,
const char *oid,
int *numParentsPtr, int **parentIndexes)
findParentsByOid(TableInfo *self,
InhInfo *inhinfo, int numInherits)
{
Oid oid = self->dobj.catId.oid;
int i,
j;
int parentInd,
selfInd;
int numParents;
numParents = 0;
for (i = 0; i < numInherits; i++)
{
if (strcmp(inhinfo[i].inhrelid, oid) == 0)
if (inhinfo[i].inhrelid == oid)
numParents++;
}
*numParentsPtr = numParents;
self->numParents = numParents;
if (numParents > 0)
{
*parentIndexes = (int *) malloc(sizeof(int) * numParents);
self->parents = (TableInfo **) malloc(sizeof(TableInfo *) * numParents);
j = 0;
for (i = 0; i < numInherits; i++)
{
if (strcmp(inhinfo[i].inhrelid, oid) == 0)
if (inhinfo[i].inhrelid == oid)
{
parentInd = findTableByOid(tblinfo, numTables,
inhinfo[i].inhparent);
if (parentInd < 0)
{
selfInd = findTableByOid(tblinfo, numTables, oid);
if (selfInd >= 0)
write_msg(NULL, "failed sanity check, parent OID %s of table \"%s\" (OID %s) not found\n",
inhinfo[i].inhparent,
tblinfo[selfInd].relname,
oid);
else
write_msg(NULL, "failed sanity check, parent OID %s of table (OID %s) not found\n",
inhinfo[i].inhparent,
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->relname,
oid);
exit_nicely();
}
(*parentIndexes)[j++] = parentInd;
self->parents[j++] = parent;
}
}
}
else
*parentIndexes = NULL;
self->parents = NULL;
}
/*
* parseNumericArray
* 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
parseNumericArray(const char *str, char **array, int arraysize)
parseOidArray(const char *str, Oid *array, int arraysize)
{
int j,
argNum;
@ -557,7 +708,7 @@ parseNumericArray(const char *str, char **array, int arraysize)
exit_nicely();
}
temp[j] = '\0';
array[argNum++] = strdup(temp);
array[argNum++] = atooid(temp);
j = 0;
}
if (s == '\0')
@ -576,7 +727,7 @@ parseNumericArray(const char *str, char **array, int arraysize)
}
while (argNum < arraysize)
array[argNum++] = strdup("0");
array[argNum++] = InvalidOid;
}

View File

@ -15,19 +15,22 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup.h,v 1.27 2003/11/29 19:52:05 pgsql Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup.h,v 1.28 2003/12/06 03:00:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PG_BACKUP__
#define PG_BACKUP__
#ifndef PG_BACKUP_H
#define PG_BACKUP_H
#include "postgres_fe.h"
#include "pg_dump.h"
#include "libpq-fe.h"
#include "pqexpbuffer.h"
#define atooid(x) ((Oid) strtoul((x), NULL, 10))
#define oidcmp(x,y) ( ((x) < (y) ? -1 : ((x) > (y)) ? 1 : 0) )
#define oideq(x,y) ( (x) == (y) )
@ -45,7 +48,7 @@ typedef enum _archiveFormat
} ArchiveFormat;
/*
* We may want to have so user-readbale data, but in the mean
* We may want to have some more user-readable data, but in the mean
* time this gives us some abstraction and type checking.
*/
typedef struct _Archive
@ -57,7 +60,7 @@ typedef struct _Archive
/* The rest is private */
} Archive;
typedef int (*DataDumperPtr) (Archive *AH, char *oid, void *userArg);
typedef int (*DataDumperPtr) (Archive *AH, void *userArg);
typedef struct _restoreOptions
{
@ -74,9 +77,6 @@ typedef struct _restoreOptions
int aclsSkip;
int tocSummary;
char *tocFile;
int oidOrder;
int origOrder;
int rearrange;
int format;
char *formatName;
@ -98,8 +98,8 @@ typedef struct _restoreOptions
int ignoreVersion;
int requirePassword;
int *idWanted;
int limitToList;
bool *idWanted;
bool limitToList;
int compression;
int suppressDumpWarnings; /* Suppress output of WARNING
@ -127,11 +127,13 @@ PGconn *ConnectDatabase(Archive *AH,
/* Called to add a TOC entry */
extern void ArchiveEntry(Archive *AHX, const char *oid, const char *tag,
extern void ArchiveEntry(Archive *AHX,
CatalogId catalogId, DumpId dumpId,
const char *tag,
const char *namespace, const char *owner,
const char *desc, const char *((*deps)[]),
const char *defn, const char *dropStmt,
const char *copyStmt,
const char *desc, const char *defn,
const char *dropStmt, const char *copyStmt,
const DumpId *deps, int nDeps,
DataDumperPtr dumpFn, void *dumpArg);
/* Called to write *data* to the archive */
@ -161,19 +163,13 @@ extern void PrintTOCSummary(Archive *AH, RestoreOptions *ropt);
extern RestoreOptions *NewRestoreOptions(void);
/* Rearrange TOC entries */
extern void MoveToStart(Archive *AH, const char *oType);
extern void MoveToEnd(Archive *AH, const char *oType);
extern void SortTocByObjectType(Archive *AH);
extern void SortTocByOID(Archive *AH);
extern void SortTocByID(Archive *AH);
extern void SortTocFromFile(Archive *AH, RestoreOptions *ropt);
/* Convenience functions used only when writing DATA */
extern int archputs(const char *s, Archive *AH);
extern int archputc(const char c, Archive *AH);
extern int
archprintf(Archive *AH, const char *fmt,...)
/* This extension allows gcc to check the format string */
__attribute__((format(printf, 2, 3)));
#endif
#endif /* PG_BACKUP_H */

View File

@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.80 2003/11/29 19:52:05 pgsql Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.81 2003/12/06 03:00:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -41,9 +41,10 @@ typedef enum _teReqs_
REQ_ALL = REQ_SCHEMA + REQ_DATA
} teReqs;
static void _SortToc(ArchiveHandle *AH, TocSortCompareFn fn);
static int _tocSortCompareByOIDNum(const void *p1, const void *p2);
static int _tocSortCompareByIDNum(const void *p1, const void *p2);
const char *progname;
static char *modulename = gettext_noop("archiver");
static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
const int compression, ArchiveMode mode);
static int _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData);
@ -57,15 +58,9 @@ static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName);
static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt);
static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
static TocEntry *_getTocEntry(ArchiveHandle *AH, int id);
static TocEntry *getTocEntryByDumpId(ArchiveHandle *AH, DumpId id);
static void _moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te);
static void _moveBefore(ArchiveHandle *AH, TocEntry *pos, TocEntry *te);
static int _discoverArchiveFormat(ArchiveHandle *AH);
static void _fixupOidInfo(TocEntry *te);
static Oid _findMaxOID(const char *((*deps)[]));
const char *progname;
static char *modulename = gettext_noop("archiver");
static void _write_msg(const char *modulename, const char *fmt, va_list ap);
static void _die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt, va_list ap);
@ -73,6 +68,7 @@ static void _die_horribly(ArchiveHandle *AH, const char *modulename, const char
static int _canRestoreBlobs(ArchiveHandle *AH);
static int _restoringToDB(ArchiveHandle *AH);
/*
* Wrapper functions.
*
@ -534,29 +530,33 @@ WriteData(Archive *AHX, const void *data, size_t dLen)
/* Public */
void
ArchiveEntry(Archive *AHX, const char *oid, const char *tag,
ArchiveEntry(Archive *AHX,
CatalogId catalogId, DumpId dumpId,
const char *tag,
const char *namespace, const char *owner,
const char *desc, const char *((*deps)[]),
const char *defn, const char *dropStmt,
const char *copyStmt,
const char *desc, const char *defn,
const char *dropStmt, const char *copyStmt,
const DumpId *deps, int nDeps,
DataDumperPtr dumpFn, void *dumpArg)
{
ArchiveHandle *AH = (ArchiveHandle *) AHX;
TocEntry *newToc;
AH->lastID++;
AH->tocCount++;
newToc = (TocEntry *) calloc(1, sizeof(TocEntry));
if (!newToc)
die_horribly(AH, modulename, "out of memory\n");
AH->tocCount++;
if (dumpId > AH->maxDumpId)
AH->maxDumpId = dumpId;
newToc->prev = AH->toc->prev;
newToc->next = AH->toc;
AH->toc->prev->next = newToc;
AH->toc->prev = newToc;
newToc->id = AH->lastID;
newToc->catalogId = catalogId;
newToc->dumpId = dumpId;
newToc->tag = strdup(tag);
newToc->namespace = namespace ? strdup(namespace) : NULL;
@ -566,24 +566,26 @@ ArchiveEntry(Archive *AHX, const char *oid, const char *tag,
newToc->dropStmt = strdup(dropStmt);
newToc->copyStmt = copyStmt ? strdup(copyStmt) : NULL;
newToc->oid = strdup(oid);
newToc->depOid = deps; /* NB: not copied */
_fixupOidInfo(newToc);
if (nDeps > 0)
{
newToc->dependencies = (DumpId *) malloc(nDeps * sizeof(DumpId));
memcpy(newToc->dependencies, deps, nDeps * sizeof(DumpId));
newToc->nDeps = nDeps;
}
else
{
newToc->dependencies = NULL;
newToc->nDeps = 0;
}
newToc->printed = 0;
newToc->formatData = NULL;
newToc->dataDumper = dumpFn;
newToc->dataDumperArg = dumpArg;
newToc->hadDumper = dumpFn ? true : false;
newToc->hadDumper = dumpFn ? 1 : 0;
newToc->formatData = NULL;
if (AH->ArchiveEntryPtr !=NULL)
if (AH->ArchiveEntryPtr != NULL)
(*AH->ArchiveEntryPtr) (AH, newToc);
/*
* printf("New toc owned by '%s', oid %u\n", newToc->owner,
* newToc->oidVal);
*/
}
/* Public */
@ -627,7 +629,9 @@ PrintTOCSummary(Archive *AHX, RestoreOptions *ropt)
while (te != AH->toc)
{
if (_tocEntryRequired(te, ropt) != 0)
ahprintf(AH, "%d; %d %s %s %s\n", te->id, te->oidVal, te->desc, te->tag, te->owner);
ahprintf(AH, "%d; %u %u %s %s %s\n", te->dumpId,
te->catalogId.tableoid, te->catalogId.oid,
te->desc, te->tag, te->owner);
te = te->next;
}
@ -781,127 +785,6 @@ EndRestoreBlob(ArchiveHandle *AH, Oid oid)
* Sorting and Reordering
***********/
/*
* Move TOC entries of the specified type to the START of the TOC.
*
* This is public, but if you use it anywhere but SortTocByObjectType,
* you are risking breaking things.
*/
void
MoveToStart(Archive *AHX, const char *oType)
{
ArchiveHandle *AH = (ArchiveHandle *) AHX;
TocEntry *te = AH->toc->next;
TocEntry *newTe;
while (te != AH->toc)
{
te->_moved = 0;
te = te->next;
}
te = AH->toc->prev;
while (te != AH->toc && !te->_moved)
{
newTe = te->prev;
if (strcmp(te->desc, oType) == 0)
_moveAfter(AH, AH->toc, te);
te = newTe;
}
}
/*
* Move TOC entries of the specified type to the end of the TOC.
*
* This is public, but if you use it anywhere but SortTocByObjectType,
* you are risking breaking things.
*/
void
MoveToEnd(Archive *AHX, const char *oType)
{
ArchiveHandle *AH = (ArchiveHandle *) AHX;
TocEntry *te = AH->toc->next;
TocEntry *newTe;
while (te != AH->toc)
{
te->_moved = 0;
te = te->next;
}
te = AH->toc->next;
while (te != AH->toc && !te->_moved)
{
newTe = te->next;
if (strcmp(te->desc, oType) == 0)
_moveBefore(AH, AH->toc, te);
te = newTe;
}
}
/*
* Sort TOC by object type (items of same type keep same relative order)
*
* This is factored out to ensure that pg_dump and pg_restore stay in sync
* about the standard ordering.
*/
void
SortTocByObjectType(Archive *AH)
{
/*
* Procedural languages have to be declared just after database and
* schema creation, before they are used.
*/
MoveToStart(AH, "ACL LANGUAGE");
MoveToStart(AH, "PROCEDURAL LANGUAGE");
MoveToStart(AH, "FUNC PROCEDURAL LANGUAGE");
MoveToStart(AH, "SCHEMA");
MoveToStart(AH, "<Init>");
/* Database entries *must* be at front (see also pg_restore.c) */
MoveToStart(AH, "DATABASE");
MoveToEnd(AH, "TABLE DATA");
MoveToEnd(AH, "BLOBS");
MoveToEnd(AH, "INDEX");
MoveToEnd(AH, "CONSTRAINT");
MoveToEnd(AH, "FK CONSTRAINT");
MoveToEnd(AH, "TRIGGER");
MoveToEnd(AH, "RULE");
MoveToEnd(AH, "SEQUENCE SET");
/*
* Moving all comments to end is annoying, but must do it for comments
* on stuff we just moved, and we don't seem to have quite enough
* dependency structure to get it really right...
*/
MoveToEnd(AH, "COMMENT");
}
/*
* Sort TOC by OID
*/
/* Public */
void
SortTocByOID(Archive *AHX)
{
ArchiveHandle *AH = (ArchiveHandle *) AHX;
_SortToc(AH, _tocSortCompareByOIDNum);
}
/*
* Sort TOC by ID
*/
/* Public */
void
SortTocByID(Archive *AHX)
{
ArchiveHandle *AH = (ArchiveHandle *) AHX;
_SortToc(AH, _tocSortCompareByIDNum);
}
void
SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
{
@ -910,25 +793,14 @@ SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
char buf[1024];
char *cmnt;
char *endptr;
int id;
DumpId id;
TocEntry *te;
TocEntry *tePrev;
int i;
/* Allocate space for the 'wanted' array, and init it */
ropt->idWanted = (int *) malloc(sizeof(int) * AH->tocCount);
for (i = 0; i < AH->tocCount; i++)
ropt->idWanted[i] = 0;
ropt->limitToList = 1;
/* Mark all entries as 'not moved' */
te = AH->toc->next;
while (te != AH->toc)
{
te->_moved = 0;
te = te->next;
}
ropt->idWanted = (bool *) malloc(sizeof(bool) * AH->maxDumpId);
memset(ropt->idWanted, 0, sizeof(bool) * AH->maxDumpId);
ropt->limitToList = true;
/* Set prev entry as head of list */
tePrev = AH->toc;
@ -955,25 +827,27 @@ SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
/* Get an ID */
id = strtol(buf, &endptr, 10);
if (endptr == buf)
if (endptr == buf || id <= 0 || id > AH->maxDumpId)
{
write_msg(modulename, "WARNING: line ignored: %s\n", buf);
continue;
}
/* Find TOC entry */
te = _getTocEntry(AH, id);
te = getTocEntryByDumpId(AH, id);
if (!te)
die_horribly(AH, modulename, "could not find entry for ID %d\n", id);
die_horribly(AH, modulename, "could not find entry for ID %d\n",
id);
ropt->idWanted[id - 1] = 1;
ropt->idWanted[id - 1] = true;
_moveAfter(AH, tePrev, te);
tePrev = te;
}
if (fclose(fh) != 0)
die_horribly(AH, modulename, "could not close TOC file: %s\n", strerror(errno));
die_horribly(AH, modulename, "could not close TOC file: %s\n",
strerror(errno));
}
/**********************
@ -988,13 +862,6 @@ archputs(const char *s, Archive *AH)
return WriteData(AH, s, strlen(s));
}
/* Public */
int
archputc(const char c, Archive *AH)
{
return WriteData(AH, &c, 1);
}
/* Public */
int
archprintf(Archive *AH, const char *fmt,...)
@ -1007,9 +874,6 @@ archprintf(Archive *AH, const char *fmt,...)
/*
* This is paranoid: deal with the possibility that vsnprintf is
* willing to ignore trailing null
*/
/*
* or returns > 0 even if string does not fit. It may be the case that
* it returns cnt = bufsize
*/
@ -1287,6 +1151,7 @@ exit_horribly(Archive *AH, const char *modulename, const char *fmt,...)
va_start(ap, fmt);
_die_horribly((ArchiveHandle *) AH, modulename, fmt, ap);
va_end(ap);
}
/* Archiver use (just different arg declaration) */
@ -1297,6 +1162,7 @@ die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt,...)
va_start(ap, fmt);
_die_horribly(AH, modulename, fmt, ap);
va_end(ap);
}
@ -1311,10 +1177,10 @@ _moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
pos->next->prev = te;
pos->next = te;
te->_moved = 1;
}
#ifdef NOT_USED
static void
_moveBefore(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
{
@ -1325,19 +1191,19 @@ _moveBefore(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
te->next = pos;
pos->prev->next = te;
pos->prev = te;
te->_moved = 1;
}
#endif
static TocEntry *
_getTocEntry(ArchiveHandle *AH, int id)
getTocEntryByDumpId(ArchiveHandle *AH, DumpId id)
{
TocEntry *te;
te = AH->toc->next;
while (te != AH->toc)
{
if (te->id == id)
if (te->dumpId == id)
return te;
te = te->next;
}
@ -1345,9 +1211,9 @@ _getTocEntry(ArchiveHandle *AH, int id)
}
int
TocIDRequired(ArchiveHandle *AH, int id, RestoreOptions *ropt)
TocIDRequired(ArchiveHandle *AH, DumpId id, RestoreOptions *ropt)
{
TocEntry *te = _getTocEntry(AH, id);
TocEntry *te = getTocEntryByDumpId(AH, id);
if (!te)
return 0;
@ -1685,7 +1551,6 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
AH->intSize = sizeof(int);
AH->offSize = sizeof(off_t);
AH->lastID = 0;
if (FileSpec)
{
AH->fSpec = strdup(FileSpec);
@ -1795,7 +1660,7 @@ WriteDataChunks(ArchiveHandle *AH)
* The user-provided DataDumper routine needs to call
* AH->WriteData
*/
(*te->dataDumper) ((Archive *) AH, te->oid, te->dataDumperArg);
(*te->dataDumper) ((Archive *) AH, te->dataDumperArg);
if (endPtr != NULL)
(*endPtr) (AH, te);
@ -1808,18 +1673,24 @@ WriteDataChunks(ArchiveHandle *AH)
void
WriteToc(ArchiveHandle *AH)
{
TocEntry *te = AH->toc->next;
const char *dep;
TocEntry *te;
char workbuf[32];
int i;
/* printf("%d TOC Entries to save\n", AH->tocCount); */
WriteInt(AH, AH->tocCount);
while (te != AH->toc)
for (te = AH->toc->next; te != AH->toc; te = te->next)
{
WriteInt(AH, te->id);
WriteInt(AH, te->dumpId);
WriteInt(AH, te->dataDumper ? 1 : 0);
WriteStr(AH, te->oid);
/* OID is recorded as a string for historical reasons */
sprintf(workbuf, "%u", te->catalogId.tableoid);
WriteStr(AH, workbuf);
sprintf(workbuf, "%u", te->catalogId.oid);
WriteStr(AH, workbuf);
WriteStr(AH, te->tag);
WriteStr(AH, te->desc);
@ -1830,17 +1701,15 @@ WriteToc(ArchiveHandle *AH)
WriteStr(AH, te->owner);
/* Dump list of dependencies */
if (te->depOid != NULL)
for (i = 0; i < te->nDeps; i++)
{
i = 0;
while ((dep = (*te->depOid)[i++]) != NULL)
WriteStr(AH, dep);
sprintf(workbuf, "%d", te->dependencies[i]);
WriteStr(AH, workbuf);
}
WriteStr(AH, NULL); /* Terminate List */
if (AH->WriteExtraTocPtr)
(*AH->WriteExtraTocPtr) (AH, te);
te = te->next;
}
}
@ -1848,27 +1717,43 @@ void
ReadToc(ArchiveHandle *AH)
{
int i;
char *((*deps)[]);
char *tmp;
DumpId *deps;
int depIdx;
int depSize;
TocEntry *te = AH->toc->next;
AH->tocCount = ReadInt(AH);
AH->maxDumpId = 0;
for (i = 0; i < AH->tocCount; i++)
{
te = (TocEntry *) calloc(1, sizeof(TocEntry));
te->id = ReadInt(AH);
te->dumpId = ReadInt(AH);
if (te->dumpId > AH->maxDumpId)
AH->maxDumpId = te->dumpId;
/* Sanity check */
if (te->id <= 0 || te->id > AH->tocCount)
die_horribly(AH, modulename, "entry ID %d out of range -- perhaps a corrupt TOC\n", te->id);
if (te->dumpId <= 0)
die_horribly(AH, modulename,
"entry ID %d out of range -- perhaps a corrupt TOC\n",
te->dumpId);
te->hadDumper = ReadInt(AH);
te->oid = ReadStr(AH);
te->oidVal = atooid(te->oid);
if (AH->version >= K_VERS_1_8)
{
tmp = ReadStr(AH);
sscanf(tmp, "%u", &te->catalogId.tableoid);
free(tmp);
}
else
te->catalogId.tableoid = InvalidOid;
tmp = ReadStr(AH);
sscanf(tmp, "%u", &te->catalogId.oid);
free(tmp);
te->tag = ReadStr(AH);
te->desc = ReadStr(AH);
@ -1887,41 +1772,47 @@ ReadToc(ArchiveHandle *AH)
if (AH->version >= K_VERS_1_5)
{
depSize = 100;
deps = malloc(sizeof(char *) * depSize);
deps = (DumpId *) malloc(sizeof(DumpId) * depSize);
depIdx = 0;
do
for (;;)
{
tmp = ReadStr(AH);
if (!tmp)
break; /* end of list */
if (depIdx >= depSize)
{
depSize *= 2;
deps = realloc(deps, sizeof(char *) * depSize);
deps = (DumpId *) realloc(deps, sizeof(DumpId) * depSize);
}
(*deps)[depIdx] = ReadStr(AH);
#if 0
if ((*deps)[depIdx])
write_msg(modulename, "read dependency for %s -> %s\n",
te->tag, (*deps)[depIdx]);
#endif
} while ((*deps)[depIdx++] != NULL);
sscanf(tmp, "%d", &deps[depIdx]);
free(tmp);
depIdx++;
}
if (depIdx > 1) /* We have a non-null entry */
te->depOid = realloc(deps, sizeof(char *) * depIdx); /* trim it */
if (depIdx > 0) /* We have a non-null entry */
{
deps = (DumpId *) realloc(deps, sizeof(DumpId) * depIdx);
te->dependencies = deps;
te->nDeps = depIdx;
}
else
{
free(deps);
te->depOid = NULL; /* no deps */
te->dependencies = NULL;
te->nDeps = 0;
}
}
else
te->depOid = NULL;
/* Set maxOidVal etc for use in sorting */
_fixupOidInfo(te);
{
te->dependencies = NULL;
te->nDeps = 0;
}
if (AH->ReadExtraTocPtr)
(*AH->ReadExtraTocPtr) (AH, te);
ahlog(AH, 3, "read TOC entry %d (ID %d) for %s %s\n", i, te->id, te->desc, te->tag);
ahlog(AH, 3, "read TOC entry %d (ID %d) for %s %s\n",
i, te->dumpId, te->desc, te->tag);
te->prev = AH->toc->prev;
AH->toc->prev->next = te;
@ -2013,7 +1904,7 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt)
res = res & ~REQ_SCHEMA;
/* Finally, if we used a list, limit based on that as well */
if (ropt->limitToList && !ropt->idWanted[te->id - 1])
if (ropt->limitToList && !ropt->idWanted[te->dumpId - 1])
return 0;
return res;
@ -2190,7 +2081,7 @@ _selectOutputSchema(ArchiveHandle *AH, const char *schemaName)
static int
_printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData)
{
char *pfx;
const char *pfx;
/* Select owner and schema as necessary */
_becomeOwner(AH, te);
@ -2208,8 +2099,23 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat
else
pfx = "";
ahprintf(AH, "--\n-- %sTOC entry %d (OID %s)\n-- Name: %s; Type: %s; Schema: %s; Owner: %s\n",
pfx, te->id, te->oid, te->tag, te->desc,
ahprintf(AH, "--\n");
if (AH->public.verbose)
{
ahprintf(AH, "-- TOC entry %d (class %u OID %u)\n",
te->dumpId, te->catalogId.tableoid, te->catalogId.oid);
if (te->nDeps > 0)
{
int i;
ahprintf(AH, "-- Dependencies:");
for (i = 0; i < te->nDeps; i++)
ahprintf(AH, " %d", te->dependencies[i]);
ahprintf(AH, "\n");
}
}
ahprintf(AH, "-- %sName: %s; Type: %s; Schema: %s; Owner: %s\n",
pfx, te->tag, te->desc,
te->namespace ? te->namespace : "-",
te->owner);
if (AH->PrintExtraTocPtr !=NULL)
@ -2381,181 +2287,3 @@ checkSeek(FILE *fp)
else
return true;
}
static void
_SortToc(ArchiveHandle *AH, TocSortCompareFn fn)
{
TocEntry **tea;
TocEntry *te;
int i;
/* Allocate an array for quicksort (TOC size + head & foot) */
tea = (TocEntry **) malloc(sizeof(TocEntry *) * (AH->tocCount + 2));
/* Build array of toc entries, including header at start and end */
te = AH->toc;
for (i = 0; i <= AH->tocCount + 1; i++)
{
/*
* printf("%d: %x (%x, %x) - %u\n", i, te, te->prev, te->next,
* te->oidVal);
*/
tea[i] = te;
te = te->next;
}
/* Sort it, but ignore the header entries */
qsort(&(tea[1]), AH->tocCount, sizeof(TocEntry *), fn);
/* Rebuild list: this works because we have headers at each end */
for (i = 1; i <= AH->tocCount; i++)
{
tea[i]->next = tea[i + 1];
tea[i]->prev = tea[i - 1];
}
te = AH->toc;
for (i = 0; i <= AH->tocCount + 1; i++)
{
/*
* printf("%d: %x (%x, %x) - %u\n", i, te, te->prev, te->next,
* te->oidVal);
*/
te = te->next;
}
AH->toc->next = tea[1];
AH->toc->prev = tea[AH->tocCount];
}
static int
_tocSortCompareByOIDNum(const void *p1, const void *p2)
{
TocEntry *te1 = *(TocEntry **) p1;
TocEntry *te2 = *(TocEntry **) p2;
Oid id1 = te1->maxOidVal;
Oid id2 = te2->maxOidVal;
int cmpval;
/* printf("Comparing %u to %u\n", id1, id2); */
cmpval = oidcmp(id1, id2);
/* If we have a deterministic answer, return it. */
if (cmpval != 0)
return cmpval;
/* More comparisons required */
if (oideq(id1, te1->maxDepOidVal)) /* maxOid1 came from deps */
{
if (oideq(id2, te2->maxDepOidVal)) /* maxOid2 also came from
* deps */
{
cmpval = oidcmp(te1->oidVal, te2->oidVal); /* Just compare base
* OIDs */
}
else
/* MaxOid2 was entry OID */
{
return 1; /* entry1 > entry2 */
};
}
else
/* must have oideq(id1, te1->oidVal) => maxOid1 = Oid1 */
{
if (oideq(id2, te2->maxDepOidVal)) /* maxOid2 came from deps */
{
return -1; /* entry1 < entry2 */
}
else
/* MaxOid2 was entry OID - deps don't matter */
{
cmpval = 0;
};
};
/*
* If we get here, then we've done another comparison Once again, a 0
* result means we require even more
*/
if (cmpval != 0)
return cmpval;
/*
* Entire OID details match, so use ID number (ie. original pg_dump
* order)
*/
return _tocSortCompareByIDNum(te1, te2);
}
static int
_tocSortCompareByIDNum(const void *p1, const void *p2)
{
TocEntry *te1 = *(TocEntry **) p1;
TocEntry *te2 = *(TocEntry **) p2;
int id1 = te1->id;
int id2 = te2->id;
/* printf("Comparing %d to %d\n", id1, id2); */
if (id1 < id2)
return -1;
else if (id1 > id2)
return 1;
else
return 0;
}
/*
* Assuming Oid and depOid are set, work out the various
* Oid values used in sorting.
*/
static void
_fixupOidInfo(TocEntry *te)
{
te->oidVal = atooid(te->oid);
te->maxDepOidVal = _findMaxOID(te->depOid);
/* For the purpose of sorting, find the max OID. */
if (oidcmp(te->oidVal, te->maxDepOidVal) >= 0)
te->maxOidVal = te->oidVal;
else
te->maxOidVal = te->maxDepOidVal;
}
/*
* Find the max OID value for a given list of string Oid values
*/
static Oid
_findMaxOID(const char *((*deps)[]))
{
const char *dep;
int i;
Oid maxOid = (Oid) 0;
Oid currOid;
if (!deps)
return maxOid;
i = 0;
while ((dep = (*deps)[i++]) != NULL)
{
currOid = atooid(dep);
if (oidcmp(maxOid, currOid) < 0)
maxOid = currOid;
}
return maxOid;
}
/*
* Maybe I can use this somewhere...
*
*create table pgdump_blob_path(p text);
*insert into pgdump_blob_path values('/home/pjw/work/postgresql-cvs/pgsql/src/bin/pg_dump_140');
*
*insert into dump_blob_xref select 12345,lo_import(p || '/q.q') from pgdump_blob_path;
*/

View File

@ -17,7 +17,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.53 2003/11/29 19:52:05 pgsql Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.54 2003/12/06 03:00:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -59,7 +59,7 @@ typedef z_stream *z_streamp;
#include "libpq-fe.h"
#define K_VERS_MAJOR 1
#define K_VERS_MINOR 7
#define K_VERS_MINOR 8
#define K_VERS_REV 0
/* Data block types */
@ -76,7 +76,9 @@ typedef z_stream *z_streamp;
#define K_VERS_1_6 (( (1 * 256 + 6) * 256 + 0) * 256 + 0) /* Schema field in TOCs */
#define K_VERS_1_7 (( (1 * 256 + 7) * 256 + 0) * 256 + 0) /* File Offset size in
* header */
#define K_VERS_MAX (( (1 * 256 + 7) * 256 + 255) * 256 + 0)
#define K_VERS_1_8 (( (1 * 256 + 8) * 256 + 0) * 256 + 0) /* change interpretation of ID numbers and dependencies */
#define K_VERS_MAX (( (1 * 256 + 8) * 256 + 255) * 256 + 0)
/* No of BLOBs to restore in 1 TX */
#define BLOB_BATCH_SIZE 100
@ -114,8 +116,6 @@ typedef void (*PrintTocDataPtr) (struct _archiveHandle * AH, struct _tocEntry *
typedef size_t (*CustomOutPtr) (struct _archiveHandle * AH, const void *buf, size_t len);
typedef int (*TocSortCompareFn) (const void *te1, const void *te2);
typedef enum _archiveMode
{
archModeWrite,
@ -222,7 +222,6 @@ typedef struct _archiveHandle
int createdBlobXref; /* Flag */
int blobCount; /* # of blobs restored */
int lastID; /* Last internal ID for a TOC entry */
char *fSpec; /* Archive File Spec */
FILE *FH; /* General purpose file handle */
void *OF;
@ -230,6 +229,8 @@ typedef struct _archiveHandle
struct _tocEntry *toc; /* List of TOC entries */
int tocCount; /* Number of TOC entries */
DumpId maxDumpId; /* largest DumpId among all TOC entries */
struct _tocEntry *currToc; /* Used when dumping data */
int compression; /* Compression requested on open */
ArchiveMode mode; /* File mode - r or w */
@ -252,8 +253,9 @@ typedef struct _tocEntry
{
struct _tocEntry *prev;
struct _tocEntry *next;
int id;
int hadDumper; /* Archiver was passed a dumper routine
CatalogId catalogId;
DumpId dumpId;
bool hadDumper; /* Archiver was passed a dumper routine
* (used in restore) */
char *tag; /* index tag */
char *namespace; /* null or empty string if not in a schema */
@ -262,23 +264,17 @@ typedef struct _tocEntry
char *defn;
char *dropStmt;
char *copyStmt;
char *oid; /* Oid of source of entry */
Oid oidVal; /* Value of above */
const char *((*depOid)[]);
Oid maxDepOidVal; /* Value of largest OID in deps */
Oid maxOidVal; /* Max of entry OID and max dep OID */
DumpId *dependencies; /* dumpIds of objects this one depends on */
int nDeps; /* number of dependencies */
int printed; /* Indicates if entry defn has been dumped */
DataDumperPtr dataDumper; /* Routine to dump data for object */
void *dataDumperArg; /* Arg for above routine */
void *formatData; /* TOC Entry data specific to file format */
int _moved; /* Marker used when rearranging TOC */
} TocEntry;
/* Used everywhere */
extern const char *progname;
extern void die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt,...) __attribute__((format(printf, 3, 4)));
extern void write_msg(const char *modulename, const char *fmt,...) __attribute__((format(printf, 2, 3)));
@ -290,7 +286,7 @@ extern void WriteToc(ArchiveHandle *AH);
extern void ReadToc(ArchiveHandle *AH);
extern void WriteDataChunks(ArchiveHandle *AH);
extern int TocIDRequired(ArchiveHandle *AH, int id, RestoreOptions *ropt);
extern int TocIDRequired(ArchiveHandle *AH, DumpId id, RestoreOptions *ropt);
extern bool checkSeek(FILE *fp);
/*

View File

@ -19,7 +19,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_custom.c,v 1.27 2003/11/29 19:52:05 pgsql Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_custom.c,v 1.28 2003/12/06 03:00:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -303,7 +303,7 @@ _StartData(ArchiveHandle *AH, TocEntry *te)
tctx->dataState = K_OFFSET_POS_SET;
_WriteByte(AH, BLK_DATA); /* Block type */
WriteInt(AH, te->id); /* For sanity check */
WriteInt(AH, te->dumpId); /* For sanity check */
_StartDataCompressor(AH, te);
}
@ -371,7 +371,7 @@ _StartBlobs(ArchiveHandle *AH, TocEntry *te)
tctx->dataState = K_OFFSET_POS_SET;
_WriteByte(AH, BLK_BLOBS); /* Block type */
WriteInt(AH, te->id); /* For sanity check */
WriteInt(AH, te->dumpId); /* For sanity check */
}
/*
@ -439,7 +439,7 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
_readBlockHeader(AH, &blkType, &id);
while (id != te->id)
while (id != te->dumpId)
{
if ((TocIDRequired(AH, id, ropt) & 2) != 0)
die_horribly(AH, modulename,
@ -475,9 +475,9 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
}
/* Are we sane? */
if (id != te->id)
if (id != te->dumpId)
die_horribly(AH, modulename, "found unexpected block ID (%d) when reading data -- expected %d\n",
id, te->id);
id, te->dumpId);
switch (blkType)
{
@ -863,7 +863,7 @@ _readBlockHeader(ArchiveHandle *AH, int *type, int *id)
if (AH->version < K_VERS_1_3)
*type = BLK_DATA;
else
*type = _ReadByte(AH);;
*type = _ReadByte(AH);
*id = ReadInt(AH);
}

View File

@ -20,7 +20,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_files.c,v 1.23 2003/11/29 19:52:05 pgsql Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_files.c,v 1.24 2003/12/06 03:00:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -172,11 +172,11 @@ _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
{
#ifdef HAVE_LIBZ
if (AH->compression == 0)
sprintf(fn, "%d.dat", te->id);
sprintf(fn, "%d.dat", te->dumpId);
else
sprintf(fn, "%d.dat.gz", te->id);
sprintf(fn, "%d.dat.gz", te->dumpId);
#else
sprintf(fn, "%d.dat", te->id);
sprintf(fn, "%d.dat", te->dumpId);
#endif
ctx->filename = strdup(fn);
}

View File

@ -17,7 +17,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_null.c,v 1.12 2003/11/29 19:52:05 pgsql Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_null.c,v 1.13 2003/12/06 03:00:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -91,7 +91,7 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
if (te->dataDumper)
{
AH->currToc = te;
(*te->dataDumper) ((Archive *) AH, te->oid, te->dataDumperArg);
(*te->dataDumper) ((Archive *) AH, te->dataDumperArg);
AH->currToc = NULL;
}
}

View File

@ -16,7 +16,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_tar.c,v 1.39 2003/11/29 19:52:05 pgsql Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_tar.c,v 1.40 2003/12/06 03:00:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -259,11 +259,11 @@ _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
{
#ifdef HAVE_LIBZ
if (AH->compression == 0)
sprintf(fn, "%d.dat", te->id);
sprintf(fn, "%d.dat", te->dumpId);
else
sprintf(fn, "%d.dat.gz", te->id);
sprintf(fn, "%d.dat.gz", te->dumpId);
#else
sprintf(fn, "%d.dat", te->id);
sprintf(fn, "%d.dat", te->dumpId);
#endif
ctx->filename = strdup(fn);
}

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.106 2003/11/29 22:40:46 pgsql Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.107 2003/12/06 03:00:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -14,10 +14,37 @@
#ifndef PG_DUMP_H
#define PG_DUMP_H
#include "pg_backup.h"
#include "postgres_fe.h"
/*
* The data structures used to store system catalog information
* pg_dump uses two different mechanisms for identifying database objects:
*
* CatalogId represents an object by the tableoid and oid of its defining
* entry in the system catalogs. We need this to interpret pg_depend entries,
* for instance.
*
* DumpId is a simple sequential integer counter assigned as dumpable objects
* are identified during a pg_dump run. We use DumpId internally in preference
* to CatalogId for two reasons: it's more compact, and we can assign DumpIds
* to "objects" that don't have a separate CatalogId. For example, it is
* convenient to consider a table, its data, and its ACL as three separate
* dumpable "objects" with distinct DumpIds --- this lets us reason about the
* order in which to dump these things.
*/
typedef struct
{
Oid tableoid;
Oid oid;
} CatalogId;
typedef int DumpId;
/*
* The data structures used to store system catalog information. Every
* dumpable object is a subclass of DumpableObject.
*
* NOTE: the structures described here live for the entire pg_dump run;
* and in most cases we make a struct for every object we can find in the
@ -25,12 +52,46 @@
* best to store a minimal amount of per-object info in these structs,
* and retrieve additional per-object info when and if we dump a specific
* object. In particular, try to avoid retrieving expensive-to-compute
* information until it's known to be needed.
* information until it's known to be needed. We do, however, have to
* store enough info to determine whether an object should be dumped and
* what order to dump in.
*/
typedef enum
{
/* When modifying this enum, update priority table in pg_dump_sort.c! */
DO_NAMESPACE,
DO_TYPE,
DO_FUNC,
DO_AGG,
DO_OPERATOR,
DO_OPCLASS,
DO_CONVERSION,
DO_TABLE,
DO_ATTRDEF,
DO_INDEX,
DO_RULE,
DO_TRIGGER,
DO_CONSTRAINT,
DO_FK_CONSTRAINT, /* see note for ConstraintInfo */
DO_PROCLANG,
DO_CAST,
DO_TABLE_DATA
} DumpableObjectType;
typedef struct _dumpableObject
{
DumpableObjectType objType;
CatalogId catId; /* zero if not a cataloged object */
DumpId dumpId; /* assigned by AssignDumpId() */
DumpId *dependencies; /* dumpIds of objects this one depends on */
int nDeps; /* number of valid dependencies */
int allocDeps; /* allocated size of dependencies[] */
} DumpableObject;
typedef struct _namespaceInfo
{
char *oid;
DumpableObject dobj;
char *nspname;
char *usename; /* name of owner, or empty string */
char *nspacl;
@ -39,57 +100,56 @@ typedef struct _namespaceInfo
typedef struct _typeInfo
{
char *oid;
DumpableObject dobj;
char *typname; /* name as seen in catalog */
/* Note: format_type might produce something different than typname */
NamespaceInfo *typnamespace; /* link to containing namespace */
char *usename; /* name of owner, or empty string */
char *typelem; /* OID */
char *typrelid; /* OID */
Oid typinput;
Oid typelem;
Oid typrelid;
char typrelkind; /* 'r', 'v', 'c', etc */
char typtype; /* 'b', 'c', etc */
bool isArray; /* true if user-defined array type */
bool isDefined; /* true if typisdefined */
/* If it's a domain, we store links to its constraints here: */
int nDomChecks;
struct _constraintInfo *domChecks;
} TypeInfo;
typedef struct _funcInfo
{
char *oid;
DumpableObject dobj;
char *proname;
NamespaceInfo *pronamespace; /* link to containing namespace */
char *usename; /* name of owner, or empty string */
Oid lang;
int nargs;
char **argtypes; /* OIDs */
char *prorettype; /* OID */
Oid *argtypes;
Oid prorettype;
char *proacl;
bool dumped; /* true if already dumped */
} FuncInfo;
/* AggInfo is a superset of FuncInfo */
typedef struct _aggInfo
{
char *oid;
char *aggname;
char *aggbasetype; /* OID */
NamespaceInfo *aggnamespace; /* link to containing namespace */
char *usename;
char *aggacl;
FuncInfo aggfn;
bool anybasetype; /* is the basetype "any"? */
char *fmtbasetype; /* formatted type name */
} AggInfo;
typedef struct _oprInfo
{
char *oid;
DumpableObject dobj;
char *oprname;
NamespaceInfo *oprnamespace; /* link to containing namespace */
char *usename;
char *oprcode; /* as OID, not regproc name */
Oid oprcode;
} OprInfo;
typedef struct _opclassInfo
{
char *oid;
DumpableObject dobj;
char *opcname;
NamespaceInfo *opcnamespace; /* link to containing namespace */
char *usename;
@ -97,7 +157,7 @@ typedef struct _opclassInfo
typedef struct _convInfo
{
char *oid;
DumpableObject dobj;
char *conname;
NamespaceInfo *connamespace; /* link to containing namespace */
char *usename;
@ -108,7 +168,7 @@ typedef struct _tableInfo
/*
* These fields are collected for every table in the database.
*/
char *oid;
DumpableObject dobj;
char *relname;
NamespaceInfo *relnamespace; /* link to containing namespace */
char *usename; /* name of owner, or empty string */
@ -120,7 +180,7 @@ typedef struct _tableInfo
int ncheck; /* # of CHECK expressions */
int ntrig; /* # of triggers */
/* these two are set only if table is a SERIAL column's sequence: */
char *owning_tab; /* OID of table owning sequence */
Oid owning_tab; /* OID of table owning sequence */
int owning_col; /* attr # of column owning sequence */
bool interesting; /* true if need to collect more data */
@ -143,40 +203,127 @@ typedef struct _tableInfo
bool *attisserial; /* true if attr is serial or bigserial */
/*
* Note: we need to store per-attribute notnull and default stuff for
* all interesting tables so that we can tell which constraints were
* inherited.
* Note: we need to store per-attribute notnull, default, and constraint
* stuff for all interesting tables so that we can tell which constraints
* were inherited.
*/
bool *notnull; /* Not null constraints on attributes */
char **adef_expr; /* DEFAULT expressions */
struct _attrDefInfo **attrdefs; /* DEFAULT expressions */
bool *inhAttrs; /* true if each attribute is inherited */
bool *inhAttrDef; /* true if attr's default is inherited */
bool *inhNotNull; /* true if NOT NULL is inherited */
struct _constraintInfo *checkexprs; /* CHECK constraints */
/*
* Stuff computed only for dumpable tables.
*/
int numParents; /* number of (immediate) parent tables */
int *parentIndexes; /* TableInfo indexes of immediate parents */
char *viewoid; /* OID of view - should be >= oid of table
* important because views may be
* constructed manually from rules, and
* rule may ref things created after the
* base table was created. */
struct _tableInfo **parents; /* TableInfos of immediate parents */
} TableInfo;
typedef struct _attrDefInfo
{
DumpableObject dobj;
TableInfo *adtable; /* link to table of attribute */
int adnum;
char *adef_expr; /* decompiled DEFAULT expression */
bool separate; /* TRUE if must dump as separate item */
} AttrDefInfo;
typedef struct _tableDataInfo
{
DumpableObject dobj;
TableInfo *tdtable; /* link to table to dump */
bool oids; /* include OIDs in data? */
} TableDataInfo;
typedef struct _indxInfo
{
DumpableObject dobj;
char *indexname;
TableInfo *indextable; /* link to table the index is for */
char *indexdef;
int indnkeys;
Oid *indkeys;
bool indisclustered;
/* if there is an associated constraint object, its dumpId: */
DumpId indexconstraint;
} IndxInfo;
typedef struct _ruleInfo
{
DumpableObject dobj;
char *rulename;
TableInfo *ruletable; /* link to table the rule is for */
char ev_type;
bool is_instead;
} RuleInfo;
typedef struct _triggerInfo
{
DumpableObject dobj;
TableInfo *tgtable; /* link to table the trigger is for */
char *tgname;
char *tgfname;
int tgtype;
int tgnargs;
char *tgargs;
bool tgisconstraint;
char *tgconstrname;
Oid tgconstrrelid;
char *tgconstrrelname;
bool tgdeferrable;
bool tginitdeferred;
} TriggerInfo;
/*
* struct ConstraintInfo is used for all constraint types. However we
* use a different objType for foreign key constraints, to make it easier
* to sort them the way we want.
*/
typedef struct _constraintInfo
{
DumpableObject dobj;
char *conname;
TableInfo *contable; /* NULL if domain constraint */
TypeInfo *condomain; /* NULL if table constraint */
char contype;
char *condef; /* definition, if CHECK or FOREIGN KEY */
DumpId conindex; /* identifies associated index if any */
bool coninherited; /* TRUE if appears to be inherited */
bool separate; /* TRUE if must dump as separate item */
} ConstraintInfo;
typedef struct _procLangInfo
{
DumpableObject dobj;
char *lanname;
bool lanpltrusted;
Oid lanplcallfoid;
Oid lanvalidator;
char *lanacl;
} ProcLangInfo;
typedef struct _castInfo
{
DumpableObject dobj;
Oid castsource;
Oid casttarget;
Oid castfunc;
char castcontext;
} CastInfo;
/* InhInfo isn't a DumpableObject, just temporary state */
typedef struct _inhInfo
{
char *inhrelid; /* OID of a child table */
char *inhparent; /* OID of its parent */
Oid inhrelid; /* OID of a child table */
Oid inhparent; /* OID of its parent */
} InhInfo;
/* global decls */
extern bool force_quotes; /* double-quotes for identifiers flag */
extern bool g_verbose; /* verbose flag */
extern Archive *g_fout; /* the script file */
/* placeholders for comment starting and ending delimiters */
extern char g_comment_start[10];
@ -188,9 +335,7 @@ extern char g_opaque_type[10]; /* name for the opaque type */
* common utility functions
*/
extern TableInfo *dumpSchema(Archive *fout,
int *numTablesPtr,
const bool aclsSkip,
extern TableInfo *getSchemaData(int *numTablesPtr,
const bool schemaOnly,
const bool dataOnly);
@ -202,15 +347,28 @@ typedef enum _OidOptions
zeroAsNone = 8
} OidOptions;
extern int findTableByOid(TableInfo *tbinfo, int numTables, const char *oid);
extern char *findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid);
extern int findFuncByOid(FuncInfo *finfo, int numFuncs, const char *oid);
extern int findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid);
extern void AssignDumpId(DumpableObject *dobj);
extern DumpId createDumpId(void);
extern DumpId getMaxDumpId(void);
extern DumpableObject *findObjectByDumpId(DumpId dumpId);
extern DumpableObject *findObjectByCatalogId(CatalogId catalogId);
extern void getDumpableObjects(DumpableObject ***objs, int *numObjs);
extern void addObjectDependency(DumpableObject *dobj, DumpId refId);
extern void removeObjectDependency(DumpableObject *dobj, DumpId refId);
extern TableInfo *findTableByOid(Oid oid);
extern TypeInfo *findTypeByOid(Oid oid);
extern FuncInfo *findFuncByOid(Oid oid);
extern OprInfo *findOprByOid(Oid oid);
extern void check_conn_and_db(void);
extern void exit_nicely(void);
extern void parseNumericArray(const char *str, char **array, int arraysize);
extern void parseOidArray(const char *str, Oid *array, int arraysize);
extern void sortDumpableObjects(DumpableObject **objs, int numObjs);
extern void sortDumpableObjectsByType(DumpableObject **objs, int numObjs);
/*
* version specific routines
@ -224,26 +382,12 @@ extern OpclassInfo *getOpclasses(int *numOpclasses);
extern ConvInfo *getConversions(int *numConversions);
extern TableInfo *getTables(int *numTables);
extern InhInfo *getInherits(int *numInherits);
extern void getIndexes(TableInfo tblinfo[], int numTables);
extern void getConstraints(TableInfo tblinfo[], int numTables);
extern RuleInfo *getRules(int *numRules);
extern void getTriggers(TableInfo tblinfo[], int numTables);
extern ProcLangInfo *getProcLangs(int *numProcLangs);
extern CastInfo *getCasts(int *numCasts);
extern void getTableAttrs(TableInfo *tbinfo, int numTables);
extern void dumpDBComment(Archive *outfile);
extern void dumpNamespaces(Archive *fout,
NamespaceInfo *nsinfo, int numNamespaces);
extern void dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
TypeInfo *tinfo, int numTypes);
extern void dumpProcLangs(Archive *fout, FuncInfo finfo[], int numFuncs);
extern void dumpFuncs(Archive *fout, FuncInfo finfo[], int numFuncs);
extern void dumpCasts(Archive *fout, FuncInfo *finfo, int numFuncs,
TypeInfo *tinfo, int numTypes);
extern void dumpAggs(Archive *fout, AggInfo agginfo[], int numAggregates);
extern void dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators);
extern void dumpOpclasses(Archive *fout,
OpclassInfo *opcinfo, int numOpclasses);
extern void dumpConversions(Archive *fout,
ConvInfo *coninfo, int numConversions);
extern void dumpTables(Archive *fout, TableInfo tblinfo[], int numTables,
const bool aclsSkip,
const bool schemaOnly, const bool dataOnly);
extern void dumpIndexes(Archive *fout, TableInfo *tbinfo, int numTables);
#endif /* PG_DUMP_H */

View File

@ -0,0 +1,727 @@
/*-------------------------------------------------------------------------
*
* pg_dump_sort.c
* Sort the items of a dump into a safe order for dumping
*
*
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.1 2003/12/06 03:00:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "pg_dump.h"
#include "pg_backup_archiver.h"
static char *modulename = gettext_noop("sorter");
/*
* Sort priority for object types. Objects are sorted by priority,
* and within an equal priority level by OID. (This is a relatively
* crude hack to provide semi-reasonable behavior for old databases
* without full dependency info.)
*/
static const int objectTypePriority[] =
{
1, /* DO_NAMESPACE */
2, /* DO_TYPE */
2, /* DO_FUNC */
2, /* DO_AGG */
3, /* DO_OPERATOR */
4, /* DO_OPCLASS */
5, /* DO_CONVERSION */
6, /* DO_TABLE */
7, /* DO_ATTRDEF */
10, /* DO_INDEX */
11, /* DO_RULE */
12, /* DO_TRIGGER */
9, /* DO_CONSTRAINT */
13, /* DO_FK_CONSTRAINT */
2, /* DO_PROCLANG */
2, /* DO_CAST */
8 /* DO_TABLE_DATA */
};
static int DOTypeCompare(const void *p1, const void *p2);
static bool TopoSort(DumpableObject **objs,
int numObjs,
DumpableObject **ordering,
int *nOrdering);
static bool findLoop(DumpableObject *obj,
int depth,
DumpableObject **ordering,
int *nOrdering);
static void repairDependencyLoop(DumpableObject **loop,
int nLoop);
static void describeDumpableObject(DumpableObject *obj,
char *buf, int bufsize);
/*
* Sort the given objects into a type/OID-based ordering
*
* Normally this is just the starting point for the dependency-based
* ordering.
*/
void
sortDumpableObjectsByType(DumpableObject **objs, int numObjs)
{
if (numObjs > 1)
qsort((void *) objs, numObjs, sizeof(DumpableObject *), DOTypeCompare);
}
static int
DOTypeCompare(const void *p1, const void *p2)
{
DumpableObject *obj1 = *(DumpableObject **) p1;
DumpableObject *obj2 = *(DumpableObject **) p2;
int cmpval;
cmpval = objectTypePriority[obj1->objType] -
objectTypePriority[obj2->objType];
if (cmpval != 0)
return cmpval;
return oidcmp(obj1->catId.oid, obj2->catId.oid);
}
/*
* Sort the given objects into a safe dump order using dependency
* information (to the extent we have it available).
*/
void
sortDumpableObjects(DumpableObject **objs, int numObjs)
{
DumpableObject **ordering;
int nOrdering;
ordering = (DumpableObject **) malloc(numObjs * sizeof(DumpableObject *));
if (ordering == NULL)
exit_horribly(NULL, modulename, "out of memory\n");
while (!TopoSort(objs, numObjs, ordering, &nOrdering))
repairDependencyLoop(ordering, nOrdering);
memcpy(objs, ordering, numObjs * sizeof(DumpableObject *));
free(ordering);
}
/*
* TopoSort -- topological sort of a dump list
*
* Generate a re-ordering of the dump list that satisfies all the dependency
* constraints shown in the dump list. (Each such constraint is a fact of a
* partial ordering.) Minimize rearrangement of the list not needed to
* achieve the partial ordering.
*
* This is a lot simpler and slower than, for example, the topological sort
* algorithm shown in Knuth's Volume 1. However, Knuth's method doesn't
* try to minimize the damage to the existing order.
*
* Returns TRUE if able to build an ordering that satisfies all the
* constraints, FALSE if not (there are contradictory constraints).
*
* On success (TRUE result), ordering[] is filled with an array of
* DumpableObject pointers, of length equal to the input list length.
*
* On failure (FALSE result), ordering[] is filled with an array of
* DumpableObject pointers of length *nOrdering, representing a circular set
* of dependency constraints. (If there is more than one cycle in the given
* constraints, one is picked at random to return.)
*
* The caller is responsible for allocating sufficient space at *ordering.
*/
static bool
TopoSort(DumpableObject **objs,
int numObjs,
DumpableObject **ordering, /* output argument */
int *nOrdering) /* output argument */
{
DumpId maxDumpId = getMaxDumpId();
bool result = true;
DumpableObject **topoItems;
DumpableObject *obj;
int *beforeConstraints;
int i,
j,
k,
last;
/* First, create work array with the dump items in their current order */
topoItems = (DumpableObject **) malloc(numObjs * sizeof(DumpableObject *));
if (topoItems == NULL)
exit_horribly(NULL, modulename, "out of memory\n");
memcpy(topoItems, objs, numObjs * sizeof(DumpableObject *));
*nOrdering = numObjs; /* for success return */
/*
* Scan the constraints, and for each item in the array, generate a
* count of the number of constraints that say it must be before
* something else. The count for the item with dumpId j is
* stored in beforeConstraints[j].
*/
beforeConstraints = (int *) malloc((maxDumpId + 1) * sizeof(int));
if (beforeConstraints == NULL)
exit_horribly(NULL, modulename, "out of memory\n");
memset(beforeConstraints, 0, (maxDumpId + 1) * sizeof(int));
for (i = 0; i < numObjs; i++)
{
obj = topoItems[i];
for (j = 0; j < obj->nDeps; j++)
{
k = obj->dependencies[j];
if (k <= 0 || k > maxDumpId)
exit_horribly(NULL, modulename, "invalid dependency %d\n", k);
beforeConstraints[k]++;
}
}
/*--------------------
* Now scan the topoItems array backwards. At each step, output the
* last item that has no remaining before-constraints, and decrease
* the beforeConstraints count of each of the items it was constrained
* against.
* i = index of ordering[] entry we want to output this time
* j = search index for topoItems[]
* k = temp for scanning constraint list for item j
* last = last non-null index in topoItems (avoid redundant searches)
*--------------------
*/
last = numObjs - 1;
for (i = numObjs; --i >= 0;)
{
/* Find next candidate to output */
while (topoItems[last] == NULL)
last--;
for (j = last; j >= 0; j--)
{
obj = topoItems[j];
if (obj != NULL && beforeConstraints[obj->dumpId] == 0)
break;
}
/* If no available candidate, topological sort fails */
if (j < 0)
{
result = false;
break;
}
/* Output candidate, and mark it done by zeroing topoItems[] entry */
ordering[i] = obj = topoItems[j];
topoItems[j] = NULL;
/* Update beforeConstraints counts of its predecessors */
for (k = 0; k < obj->nDeps; k++)
beforeConstraints[obj->dependencies[k]]--;
}
/*
* If we failed, report one of the circular constraint sets
*/
if (!result)
{
for (j = last; j >= 0; j--)
{
ordering[0] = obj = topoItems[j];
if (obj && findLoop(obj, 1, ordering, nOrdering))
break;
}
if (j < 0)
exit_horribly(NULL, modulename,
"could not find dependency loop\n");
}
/* Done */
free(topoItems);
free(beforeConstraints);
return result;
}
/*
* Recursively search for a circular dependency loop
*/
static bool
findLoop(DumpableObject *obj,
int depth,
DumpableObject **ordering, /* output argument */
int *nOrdering) /* output argument */
{
DumpId startPoint = ordering[0]->dumpId;
int j;
int k;
/* See if we've found a loop back to the starting point */
for (j = 0; j < obj->nDeps; j++)
{
if (obj->dependencies[j] == startPoint)
{
*nOrdering = depth;
return true;
}
}
/* Try each outgoing branch */
for (j = 0; j < obj->nDeps; j++)
{
DumpableObject *nextobj = findObjectByDumpId(obj->dependencies[j]);
if (!nextobj)
continue; /* ignore dependencies on undumped objects */
for (k = 0; k < depth; k++)
{
if (ordering[k] == nextobj)
break;
}
if (k < depth)
continue; /* ignore loops not including start point */
ordering[depth] = nextobj;
if (findLoop(nextobj,
depth + 1,
ordering,
nOrdering))
return true;
}
return false;
}
/*
* A user-defined datatype will have a dependency loop with each of its
* I/O functions (since those have the datatype as input or output).
* We want the dump ordering to be the input function, then any other
* I/O functions, then the datatype. So we break the circularity in
* favor of the functions, and add a dependency from any non-input
* function to the input function.
*/
static void
repairTypeFuncLoop(DumpableObject *typeobj, DumpableObject *funcobj)
{
TypeInfo *typeInfo = (TypeInfo *) typeobj;
FuncInfo *inputFuncInfo;
/* remove function's dependency on type */
removeObjectDependency(funcobj, typeobj->dumpId);
/* if this isn't the input function, make it depend on same */
if (funcobj->catId.oid == typeInfo->typinput)
return; /* it is the input function */
inputFuncInfo = findFuncByOid(typeInfo->typinput);
if (inputFuncInfo == NULL)
return;
addObjectDependency(funcobj, inputFuncInfo->dobj.dumpId);
/*
* Make sure the input function's dependency on type gets removed too;
* if it hasn't been done yet, we'd end up with loops involving the
* type and two or more functions, which repairDependencyLoop() is not
* smart enough to handle.
*/
removeObjectDependency(&inputFuncInfo->dobj, typeobj->dumpId);
}
/*
* Because we force a view to depend on its ON SELECT rule, while there
* will be an implicit dependency in the other direction, we need to break
* the loop. We can always do this by removing the implicit dependency.
*/
static void
repairViewRuleLoop(DumpableObject *viewobj,
DumpableObject *ruleobj)
{
/* remove rule's dependency on view */
removeObjectDependency(ruleobj, viewobj->dumpId);
}
/*
* Because we make tables depend on their CHECK constraints, while there
* will be an automatic dependency in the other direction, we need to break
* the loop. If there are no other objects in the loop then we can remove
* the automatic dependency and leave the CHECK constraint non-separate.
*/
static void
repairTableConstraintLoop(DumpableObject *tableobj,
DumpableObject *constraintobj)
{
/* remove constraint's dependency on table */
removeObjectDependency(constraintobj, tableobj->dumpId);
}
/*
* However, if there are other objects in the loop, we must break the loop
* by making the CHECK constraint a separately-dumped object.
*
* Because findLoop() finds shorter cycles before longer ones, it's likely
* that we will have previously fired repairTableConstraintLoop() and
* removed the constraint's dependency on the table. Put it back to ensure
* the constraint won't be emitted before the table...
*/
static void
repairTableConstraintMultiLoop(DumpableObject *tableobj,
DumpableObject *constraintobj)
{
/* remove table's dependency on constraint */
removeObjectDependency(tableobj, constraintobj->dumpId);
/* mark constraint as needing its own dump */
((ConstraintInfo *) constraintobj)->separate = true;
/* put back constraint's dependency on table */
addObjectDependency(constraintobj, tableobj->dumpId);
}
/*
* Attribute defaults behave exactly the same as CHECK constraints...
*/
static void
repairTableAttrDefLoop(DumpableObject *tableobj,
DumpableObject *attrdefobj)
{
/* remove attrdef's dependency on table */
removeObjectDependency(attrdefobj, tableobj->dumpId);
}
static void
repairTableAttrDefMultiLoop(DumpableObject *tableobj,
DumpableObject *attrdefobj)
{
/* remove table's dependency on attrdef */
removeObjectDependency(tableobj, attrdefobj->dumpId);
/* mark attrdef as needing its own dump */
((AttrDefInfo *) attrdefobj)->separate = true;
/* put back attrdef's dependency on table */
addObjectDependency(attrdefobj, tableobj->dumpId);
}
/*
* CHECK constraints on domains work just like those on tables ...
*/
static void
repairDomainConstraintLoop(DumpableObject *domainobj,
DumpableObject *constraintobj)
{
/* remove constraint's dependency on domain */
removeObjectDependency(constraintobj, domainobj->dumpId);
}
static void
repairDomainConstraintMultiLoop(DumpableObject *domainobj,
DumpableObject *constraintobj)
{
/* remove domain's dependency on constraint */
removeObjectDependency(domainobj, constraintobj->dumpId);
/* mark constraint as needing its own dump */
((ConstraintInfo *) constraintobj)->separate = true;
/* put back constraint's dependency on domain */
addObjectDependency(constraintobj, domainobj->dumpId);
}
/*
* Fix a dependency loop, or die trying ...
*
* This routine is mainly concerned with reducing the multiple ways that
* a loop might appear to common cases, which it passes off to the
* "fixer" routines above.
*/
static void
repairDependencyLoop(DumpableObject **loop,
int nLoop)
{
int i,
j;
/* Datatype and one of its I/O functions */
if (nLoop == 2 &&
loop[0]->objType == DO_TYPE &&
loop[1]->objType == DO_FUNC)
{
repairTypeFuncLoop(loop[0], loop[1]);
return;
}
if (nLoop == 2 &&
loop[1]->objType == DO_TYPE &&
loop[0]->objType == DO_FUNC)
{
repairTypeFuncLoop(loop[1], loop[0]);
return;
}
/* View and its ON SELECT rule */
if (nLoop == 2 &&
loop[0]->objType == DO_TABLE &&
loop[1]->objType == DO_RULE &&
((RuleInfo *) loop[1])->ev_type == '1' &&
((RuleInfo *) loop[1])->is_instead)
{
repairViewRuleLoop(loop[0], loop[1]);
return;
}
if (nLoop == 2 &&
loop[1]->objType == DO_TABLE &&
loop[0]->objType == DO_RULE &&
((RuleInfo *) loop[0])->ev_type == '1' &&
((RuleInfo *) loop[0])->is_instead)
{
repairViewRuleLoop(loop[1], loop[0]);
return;
}
/* Table and CHECK constraint */
if (nLoop == 2 &&
loop[0]->objType == DO_TABLE &&
loop[1]->objType == DO_CONSTRAINT &&
((ConstraintInfo *) loop[1])->contype == 'c' &&
((ConstraintInfo *) loop[1])->contable == (TableInfo *) loop[0])
{
repairTableConstraintLoop(loop[0], loop[1]);
return;
}
if (nLoop == 2 &&
loop[1]->objType == DO_TABLE &&
loop[0]->objType == DO_CONSTRAINT &&
((ConstraintInfo *) loop[0])->contype == 'c' &&
((ConstraintInfo *) loop[0])->contable == (TableInfo *) loop[1])
{
repairTableConstraintLoop(loop[1], loop[0]);
return;
}
/* Indirect loop involving table and CHECK constraint */
if (nLoop > 2)
{
for (i = 0; i < nLoop; i++)
{
if (loop[i]->objType == DO_TABLE)
{
for (j = 0; j < nLoop; j++)
{
if (loop[j]->objType == DO_CONSTRAINT &&
((ConstraintInfo *) loop[j])->contype == 'c' &&
((ConstraintInfo *) loop[j])->contable == (TableInfo *) loop[i])
{
repairTableConstraintMultiLoop(loop[i], loop[j]);
return;
}
}
}
}
}
/* Table and attribute default */
if (nLoop == 2 &&
loop[0]->objType == DO_TABLE &&
loop[1]->objType == DO_ATTRDEF &&
((AttrDefInfo *) loop[1])->adtable == (TableInfo *) loop[0])
{
repairTableAttrDefLoop(loop[0], loop[1]);
return;
}
if (nLoop == 2 &&
loop[1]->objType == DO_TABLE &&
loop[0]->objType == DO_ATTRDEF &&
((AttrDefInfo *) loop[0])->adtable == (TableInfo *) loop[1])
{
repairTableAttrDefLoop(loop[1], loop[0]);
return;
}
/* Indirect loop involving table and attribute default */
if (nLoop > 2)
{
for (i = 0; i < nLoop; i++)
{
if (loop[i]->objType == DO_TABLE)
{
for (j = 0; j < nLoop; j++)
{
if (loop[j]->objType == DO_ATTRDEF &&
((AttrDefInfo *) loop[j])->adtable == (TableInfo *) loop[i])
{
repairTableAttrDefMultiLoop(loop[i], loop[j]);
return;
}
}
}
}
}
/* Domain and CHECK constraint */
if (nLoop == 2 &&
loop[0]->objType == DO_TYPE &&
loop[1]->objType == DO_CONSTRAINT &&
((ConstraintInfo *) loop[1])->contype == 'c' &&
((ConstraintInfo *) loop[1])->condomain == (TypeInfo *) loop[0])
{
repairDomainConstraintLoop(loop[0], loop[1]);
return;
}
if (nLoop == 2 &&
loop[1]->objType == DO_TYPE &&
loop[0]->objType == DO_CONSTRAINT &&
((ConstraintInfo *) loop[0])->contype == 'c' &&
((ConstraintInfo *) loop[0])->condomain == (TypeInfo *) loop[1])
{
repairDomainConstraintLoop(loop[1], loop[0]);
return;
}
/* Indirect loop involving domain and CHECK constraint */
if (nLoop > 2)
{
for (i = 0; i < nLoop; i++)
{
if (loop[i]->objType == DO_TYPE)
{
for (j = 0; j < nLoop; j++)
{
if (loop[j]->objType == DO_CONSTRAINT &&
((ConstraintInfo *) loop[j])->contype == 'c' &&
((ConstraintInfo *) loop[j])->condomain == (TypeInfo *) loop[i])
{
repairDomainConstraintMultiLoop(loop[i], loop[j]);
return;
}
}
}
}
}
/*
* If we can't find a principled way to break the loop, complain and
* break it in an arbitrary fashion.
*/
write_msg(modulename, "WARNING: could not resolve dependency loop among these items:\n");
for (i = 0; i < nLoop; i++)
{
char buf[1024];
describeDumpableObject(loop[i], buf, sizeof(buf));
write_msg(modulename, " %s\n", buf);
}
removeObjectDependency(loop[0], loop[1]->dumpId);
}
/*
* Describe a dumpable object usefully for errors
*
* This should probably go somewhere else...
*/
static void
describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
{
switch (obj->objType)
{
case DO_NAMESPACE:
snprintf(buf, bufsize,
"SCHEMA %s (ID %d OID %u)",
((NamespaceInfo *) obj)->nspname,
obj->dumpId, obj->catId.oid);
return;
case DO_TYPE:
snprintf(buf, bufsize,
"TYPE %s (ID %d OID %u)",
((TypeInfo *) obj)->typname,
obj->dumpId, obj->catId.oid);
return;
case DO_FUNC:
snprintf(buf, bufsize,
"FUNCTION %s (ID %d OID %u)",
((FuncInfo *) obj)->proname,
obj->dumpId, obj->catId.oid);
return;
case DO_AGG:
snprintf(buf, bufsize,
"AGGREGATE %s (ID %d OID %u)",
((AggInfo *) obj)->aggfn.proname,
obj->dumpId, obj->catId.oid);
return;
case DO_OPERATOR:
snprintf(buf, bufsize,
"OPERATOR %s (ID %d OID %u)",
((OprInfo *) obj)->oprname,
obj->dumpId, obj->catId.oid);
return;
case DO_OPCLASS:
snprintf(buf, bufsize,
"OPERATOR CLASS %s (ID %d OID %u)",
((OpclassInfo *) obj)->opcname,
obj->dumpId, obj->catId.oid);
return;
case DO_CONVERSION:
snprintf(buf, bufsize,
"CONVERSION %s (ID %d OID %u)",
((ConvInfo *) obj)->conname,
obj->dumpId, obj->catId.oid);
return;
case DO_TABLE:
snprintf(buf, bufsize,
"TABLE %s (ID %d OID %u)",
((TableInfo *) obj)->relname,
obj->dumpId, obj->catId.oid);
return;
case DO_ATTRDEF:
snprintf(buf, bufsize,
"ATTRDEF %s.%s (ID %d OID %u)",
((AttrDefInfo *) obj)->adtable->relname,
((AttrDefInfo *) obj)->adtable->attnames[((AttrDefInfo *) obj)->adnum - 1],
obj->dumpId, obj->catId.oid);
return;
case DO_INDEX:
snprintf(buf, bufsize,
"INDEX %s (ID %d OID %u)",
((IndxInfo *) obj)->indexname,
obj->dumpId, obj->catId.oid);
return;
case DO_RULE:
snprintf(buf, bufsize,
"RULE %s (ID %d OID %u)",
((RuleInfo *) obj)->rulename,
obj->dumpId, obj->catId.oid);
return;
case DO_TRIGGER:
snprintf(buf, bufsize,
"TRIGGER %s (ID %d OID %u)",
((TriggerInfo *) obj)->tgname,
obj->dumpId, obj->catId.oid);
return;
case DO_CONSTRAINT:
snprintf(buf, bufsize,
"CONSTRAINT %s (ID %d OID %u)",
((ConstraintInfo *) obj)->conname,
obj->dumpId, obj->catId.oid);
return;
case DO_FK_CONSTRAINT:
snprintf(buf, bufsize,
"FK CONSTRAINT %s (ID %d OID %u)",
((ConstraintInfo *) obj)->conname,
obj->dumpId, obj->catId.oid);
return;
case DO_PROCLANG:
snprintf(buf, bufsize,
"PROCEDURAL LANGUAGE %s (ID %d OID %u)",
((ProcLangInfo *) obj)->lanname,
obj->dumpId, obj->catId.oid);
return;
case DO_CAST:
snprintf(buf, bufsize,
"CAST %u to %u (ID %d OID %u)",
((CastInfo *) obj)->castsource,
((CastInfo *) obj)->casttarget,
obj->dumpId, obj->catId.oid);
return;
case DO_TABLE_DATA:
snprintf(buf, bufsize,
"TABLE DATA %s (ID %d OID %u)",
((TableDataInfo *) obj)->tdtable->relname,
obj->dumpId, obj->catId.oid);
return;
}
/* shouldn't get here */
snprintf(buf, bufsize,
"object type %d (ID %d OID %u)",
(int) obj->objType,
obj->dumpId, obj->catId.oid);
}

View File

@ -34,7 +34,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_restore.c,v 1.54 2003/11/29 19:52:05 pgsql Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_restore.c,v 1.55 2003/12/06 03:00:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -101,10 +101,7 @@ main(int argc, char **argv)
{"no-owner", 0, NULL, 'O'},
{"no-reconnect", 0, NULL, 'R'},
{"port", 1, NULL, 'p'},
{"oid-order", 0, NULL, 'o'},
{"orig-order", 0, NULL, 'N'},
{"password", 0, NULL, 'W'},
{"rearrange", 0, NULL, 'r'},
{"schema-only", 0, NULL, 's'},
{"superuser", 1, NULL, 'S'},
{"table", 1, NULL, 't'},
@ -147,7 +144,7 @@ main(int argc, char **argv)
}
}
while ((c = getopt_long(argc, argv, "acCd:f:F:h:iI:lL:NoOp:P:rRsS:t:T:uU:vWxX:",
while ((c = getopt_long(argc, argv, "acCd:f:F:h:iI:lL:Op:P:RsS:t:T:uU:vWxX:",
cmdopts, NULL)) != -1)
{
switch (c)
@ -188,12 +185,6 @@ main(int argc, char **argv)
opts->tocFile = strdup(optarg);
break;
case 'N':
opts->origOrder = 1;
break;
case 'o':
opts->oidOrder = 1;
break;
case 'O':
opts->noOwner = 1;
break;
@ -201,9 +192,6 @@ main(int argc, char **argv)
if (strlen(optarg) != 0)
opts->pgport = strdup(optarg);
break;
case 'r':
opts->rearrange = 1;
break;
case 'R':
/* no-op, still accepted for backwards compatibility */
break;
@ -338,19 +326,6 @@ main(int argc, char **argv)
if (opts->tocFile)
SortTocFromFile(AH, opts);
if (opts->oidOrder)
SortTocByOID(AH);
else if (opts->origOrder)
SortTocByID(AH);
if (opts->rearrange)
SortTocByObjectType(AH);
else
{
/* Database MUST be at start (see also SortTocByObjectType) */
MoveToStart(AH, "DATABASE");
}
if (opts->tocSummary)
PrintTOCSummary(AH, opts);
else
@ -385,12 +360,9 @@ usage(const char *progname)
printf(_(" -I, --index=NAME restore named index\n"));
printf(_(" -L, --use-list=FILENAME use specified table of contents for ordering\n"
" output from this file\n"));
printf(_(" -N, --orig-order restore in original dump order\n"));
printf(_(" -o, --oid-order restore in OID order\n"));
printf(_(" -O, --no-owner do not output commands to set object ownership\n"));
printf(_(" -P, --function=NAME(args)\n"
" restore named function\n"));
printf(_(" -r, --rearrange rearrange output to put indexes etc. at end\n"));
printf(_(" -s, --schema-only restore only the schema, no data\n"));
printf(_(" -S, --superuser=NAME specify the superuser user name to use for\n"
" disabling triggers\n"));