(unnamed)

text/plain

Filename: (unnamed)
Type: text/plain
Part: 0
Message: Proposed patch: make pg_dump --data-only consider FK constraints
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.499
diff -c -r1.499 pg_dump.c
*** src/bin/pg_dump/pg_dump.c	30 Jul 2008 19:35:13 -0000	1.499
--- src/bin/pg_dump/pg_dump.c	7 Sep 2008 18:03:38 -0000
***************
*** 166,171 ****
--- 166,172 ----
  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,665 ****
--- 660,670 ----
  		guessConstraintInheritance(tblinfo, numTables);
  
  	if (!schemaOnly)
+ 	{
  		getTableData(tblinfo, numTables, oids);
+ 		if (dataOnly)
+ 			getTableDataFKConstraints();
+ 	}
  
  	if (outputBlobs && hasBlobs(g_fout))
  	{
***************
*** 1392,1401 ****
--- 1397,1455 ----
  			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,3631 ****
--- 3680,3686 ----
  				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,3675 ****
  	ConstraintInfo *constrinfo;
  	PQExpBuffer query;
  	PGresult   *res;
! 	int			i_condef,
! 				i_contableoid,
  				i_conoid,
! 				i_conname;
  	int			ntups;
  
  	/* pg_constraint was created in 7.3, so nothing to do if older */
--- 3721,3731 ----
  	ConstraintInfo *constrinfo;
  	PQExpBuffer query;
  	PGresult   *res;
! 	int			i_contableoid,
  				i_conoid,
! 				i_conname,
! 				i_confrelid,
! 				i_condef;
  	int			ntups;
  
  	/* pg_constraint was created in 7.3, so nothing to do if older */
***************
*** 3697,3703 ****
  
  		resetPQExpBuffer(query);
  		appendPQExpBuffer(query,
! 						  "SELECT tableoid, oid, conname, "
  						  "pg_catalog.pg_get_constraintdef(oid) as condef "
  						  "FROM pg_catalog.pg_constraint "
  						  "WHERE conrelid = '%u'::pg_catalog.oid "
--- 3753,3759 ----
  
  		resetPQExpBuffer(query);
  		appendPQExpBuffer(query,
! 						  "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,3716 ****
--- 3767,3773 ----
  		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,3732 ****
--- 3784,3790 ----
  			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,3815 ****
--- 3868,3874 ----
  		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,4793 ****
--- 4847,4853 ----
  				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: src/bin/pg_dump/pg_dump.h
===================================================================
RCS file: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.h,v
retrieving revision 1.140
diff -c -r1.140 pg_dump.h
*** src/bin/pg_dump/pg_dump.h	9 May 2008 23:32:04 -0000	1.140
--- src/bin/pg_dump/pg_dump.h	7 Sep 2008 18:03:38 -0000
***************
*** 280,285 ****
--- 280,286 ----
  	 */
  	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,357 ****
--- 353,359 ----
  	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: src/bin/pg_dump/pg_dump_sort.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/pg_dump/pg_dump_sort.c,v
retrieving revision 1.20
diff -c -r1.20 pg_dump_sort.c
*** src/bin/pg_dump/pg_dump_sort.c	1 Jan 2008 19:45:55 -0000	1.20
--- src/bin/pg_dump/pg_dump_sort.c	7 Sep 2008 18:03:38 -0000
***************
*** 947,952 ****
--- 947,975 ----
  	}
  
  	/*
+ 	 * 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).  Give an appropriate warning 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, "WARNING: 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");
+ 		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,964 ****
  		describeDumpableObject(loop[i], buf, sizeof(buf));
  		write_msg(modulename, "  %s\n", buf);
  	}
! 	removeObjectDependency(loop[0], loop[1]->dumpId);
  }
  
  /*
--- 981,991 ----
  		describeDumpableObject(loop[i], buf, sizeof(buf));
  		write_msg(modulename, "  %s\n", buf);
  	}
! 
! 	if (nLoop > 1)
! 		removeObjectDependency(loop[0], loop[1]->dumpId);
! 	else						/* must be a self-dependency */
! 		removeObjectDependency(loop[0], loop[0]->dumpId);
  }
  
  /*