* 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 $
*
*-------------------------------------------------------------------------
*/
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,
guessConstraintInheritance(tblinfo, numTables);
if (!schemaOnly)
+ {
getTableData(tblinfo, numTables, oids);
+ if (dataOnly)
+ getTableDataFKConstraints();
+ }
if (outputBlobs && hasBlobs(g_fout))
{
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:
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;
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 */
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 "
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));
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;
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;
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;
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
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
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 */
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
}
/*
+ * 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.
*/
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);
}
/*