diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 56aa5c3966..25b0f58e7d 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -12,7 +12,7 @@ * by PostgreSQL * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.499 2008/07/30 19:35:13 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.500 2008/09/08 15:26:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -166,6 +166,7 @@ static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId, static void getDependencies(void); static void getDomainConstraints(TypeInfo *tinfo); static void getTableData(TableInfo *tblinfo, int numTables, bool oids); +static void getTableDataFKConstraints(void); static char *format_function_arguments(FuncInfo *finfo, char *funcargs); static char *format_function_arguments_old(FuncInfo *finfo, int nallargs, char **allargtypes, @@ -659,7 +660,11 @@ main(int argc, char **argv) guessConstraintInheritance(tblinfo, numTables); if (!schemaOnly) + { getTableData(tblinfo, numTables, oids); + if (dataOnly) + getTableDataFKConstraints(); + } if (outputBlobs && hasBlobs(g_fout)) { @@ -1392,10 +1397,59 @@ getTableData(TableInfo *tblinfo, int numTables, bool oids) tdinfo->tdtable = &(tblinfo[i]); tdinfo->oids = oids; addObjectDependency(&tdinfo->dobj, tblinfo[i].dobj.dumpId); + + tblinfo[i].dataObj = tdinfo; } } } +/* + * getTableDataFKConstraints - + * add dump-order dependencies reflecting foreign key constraints + * + * This code is executed only in a data-only dump --- in schema+data dumps + * we handle foreign key issues by not creating the FK constraints until + * after the data is loaded. In a data-only dump, however, we want to + * order the table data objects in such a way that a table's referenced + * tables are restored first. (In the presence of circular references or + * self-references this may be impossible; we'll detect and complain about + * that during the dependency sorting step.) + */ +static void +getTableDataFKConstraints(void) +{ + DumpableObject **dobjs; + int numObjs; + int i; + + /* Search through all the dumpable objects for FK constraints */ + getDumpableObjects(&dobjs, &numObjs); + for (i = 0; i < numObjs; i++) + { + if (dobjs[i]->objType == DO_FK_CONSTRAINT) + { + ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i]; + TableInfo *ftable; + + /* Not interesting unless both tables are to be dumped */ + if (cinfo->contable == NULL || + cinfo->contable->dataObj == NULL) + continue; + ftable = findTableByOid(cinfo->confrelid); + if (ftable == NULL || + ftable->dataObj == NULL) + continue; + /* + * Okay, make referencing table's TABLE_DATA object depend on + * the referenced table's TABLE_DATA object. + */ + addObjectDependency(&cinfo->contable->dataObj->dobj, + ftable->dataObj->dobj.dumpId); + } + } + free(dobjs); +} + /* * guessConstraintInheritance: @@ -3626,6 +3680,7 @@ getIndexes(TableInfo tblinfo[], int numTables) constrinfo[j].condomain = NULL; constrinfo[j].contype = contype; constrinfo[j].condef = NULL; + constrinfo[j].confrelid = InvalidOid; constrinfo[j].conindex = indxinfo[j].dobj.dumpId; constrinfo[j].conislocal = true; constrinfo[j].separate = true; @@ -3666,10 +3721,11 @@ getConstraints(TableInfo tblinfo[], int numTables) ConstraintInfo *constrinfo; PQExpBuffer query; PGresult *res; - int i_condef, - i_contableoid, + int i_contableoid, i_conoid, - i_conname; + i_conname, + i_confrelid, + i_condef; int ntups; /* pg_constraint was created in 7.3, so nothing to do if older */ @@ -3697,7 +3753,7 @@ getConstraints(TableInfo tblinfo[], int numTables) resetPQExpBuffer(query); appendPQExpBuffer(query, - "SELECT tableoid, oid, conname, " + "SELECT tableoid, oid, conname, confrelid, " "pg_catalog.pg_get_constraintdef(oid) as condef " "FROM pg_catalog.pg_constraint " "WHERE conrelid = '%u'::pg_catalog.oid " @@ -3711,6 +3767,7 @@ getConstraints(TableInfo tblinfo[], int numTables) i_contableoid = PQfnumber(res, "tableoid"); i_conoid = PQfnumber(res, "oid"); i_conname = PQfnumber(res, "conname"); + i_confrelid = PQfnumber(res, "confrelid"); i_condef = PQfnumber(res, "condef"); constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo)); @@ -3727,6 +3784,7 @@ getConstraints(TableInfo tblinfo[], int numTables) constrinfo[j].condomain = NULL; constrinfo[j].contype = 'f'; constrinfo[j].condef = strdup(PQgetvalue(res, j, i_condef)); + constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid)); constrinfo[j].conindex = 0; constrinfo[j].conislocal = true; constrinfo[j].separate = true; @@ -3810,6 +3868,7 @@ getDomainConstraints(TypeInfo *tinfo) constrinfo[i].condomain = tinfo; constrinfo[i].contype = 'c'; constrinfo[i].condef = strdup(PQgetvalue(res, i, i_consrc)); + constrinfo[i].confrelid = InvalidOid; constrinfo[i].conindex = 0; constrinfo[i].conislocal = true; constrinfo[i].separate = false; @@ -4788,6 +4847,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) constrs[j].condomain = NULL; constrs[j].contype = 'c'; constrs[j].condef = strdup(PQgetvalue(res, j, 3)); + constrs[j].confrelid = InvalidOid; constrs[j].conindex = 0; constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't'); constrs[j].separate = false; diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 8fbe98221b..f443d9de59 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2008, 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.140 2008/05/09 23:32:04 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.141 2008/09/08 15:26:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -280,6 +280,7 @@ typedef struct _tableInfo */ int numParents; /* number of (immediate) parent tables */ struct _tableInfo **parents; /* TableInfos of immediate parents */ + struct _tableDataInfo *dataObj; /* TableDataInfo, if dumping its data */ } TableInfo; typedef struct _attrDefInfo @@ -352,6 +353,7 @@ typedef struct _constraintInfo TypeInfo *condomain; /* NULL if table constraint */ char contype; char *condef; /* definition, if CHECK or FOREIGN KEY */ + Oid confrelid; /* referenced table, if FOREIGN KEY */ DumpId conindex; /* identifies associated index if any */ bool conislocal; /* TRUE if constraint has local definition */ bool separate; /* TRUE if must dump as separate item */ diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c index e5807475e4..7206d4eef4 100644 --- a/src/bin/pg_dump/pg_dump_sort.c +++ b/src/bin/pg_dump/pg_dump_sort.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.20 2008/01/01 19:45:55 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.21 2008/09/08 15:26:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -946,6 +946,30 @@ repairDependencyLoop(DumpableObject **loop, } } + /* + * If all the objects are TABLE_DATA items, what we must have is a + * circular set of foreign key constraints (or a single self-referential + * table). Print an appropriate complaint and break the loop arbitrarily. + */ + for (i = 0; i < nLoop; i++) + { + if (loop[i]->objType != DO_TABLE_DATA) + break; + } + if (i >= nLoop) + { + write_msg(NULL, "NOTICE: there are circular foreign-key constraints among these table(s):\n"); + for (i = 0; i < nLoop; i++) + write_msg(NULL, " %s\n", loop[i]->name); + write_msg(NULL, "You may not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints.\n"); + write_msg(NULL, "Consider using a full dump instead of a --data-only dump to avoid this problem.\n"); + if (nLoop > 1) + removeObjectDependency(loop[0], loop[1]->dumpId); + else /* must be a self-dependency */ + removeObjectDependency(loop[0], loop[0]->dumpId); + return; + } + /* * If we can't find a principled way to break the loop, complain and break * it in an arbitrary fashion. @@ -958,7 +982,11 @@ repairDependencyLoop(DumpableObject **loop, describeDumpableObject(loop[i], buf, sizeof(buf)); write_msg(modulename, " %s\n", buf); } - removeObjectDependency(loop[0], loop[1]->dumpId); + + if (nLoop > 1) + removeObjectDependency(loop[0], loop[1]->dumpId); + else /* must be a self-dependency */ + removeObjectDependency(loop[0], loop[0]->dumpId); } /*