OSDN Git Service

Make pg_dump --data-only try to order the table dumps so that foreign keys'
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 8 Sep 2008 15:26:23 +0000 (15:26 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 8 Sep 2008 15:26:23 +0000 (15:26 +0000)
referenced tables are dumped before the referencing tables.  This avoids
failures when the data is loaded with the FK constraints already active.
If no such ordering is possible because of circular or self-referential
constraints, print a NOTICE to warn the user about it.

src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/bin/pg_dump/pg_dump_sort.c

index 56aa5c3..25b0f58 100644 (file)
@@ -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;
index 8fbe982..f443d9d 100644 (file)
@@ -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 */
index e580747..7206d4e 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -947,6 +947,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);
 }
 
 /*