I wrote:
> The fact that SEQUENCE SET is considered pre-data has bitten us several
> times already, eg
> http://archives.postgresql.org/pgsql-bugs/2012-05/msg00084.php

> I think it may be time to bite the bullet and change that (including
> breaking dumpSequence() into two separate functions).  I'm a little bit
> worried about the compatibility implications of back-patching such a
> change, though.  Is it likely that anybody out there is depending on the
> fact that, eg, pg_dump --section=pre-data currently includes SEQUENCE SET
> items?  Personally I think it's more likely that that'd be seen as a
> bug, but ...

Specifically, I'm thinking this, which looks rather bulky but most of
the diff is from reindenting the guts of dumpSequence().

                        regards, tom lane

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 4223b415362f4673097b6950c1c1f8b8349ca7d7..82330cbd915d7d23f7976253f5135beeec1abcf9 100644
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
*************** static void dumpTable(Archive *fout, Tab
*** 192,197 ****
--- 192,198 ----
  static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
  static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
  static void dumpSequence(Archive *fout, TableInfo *tbinfo);
+ static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
  static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
  static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
  static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
*************** makeTableDataInfo(TableInfo *tbinfo, boo
*** 1640,1648 ****
  	/* Skip VIEWs (no data to dump) */
  	if (tbinfo->relkind == RELKIND_VIEW)
  		return;
- 	/* Skip SEQUENCEs (handled elsewhere) */
- 	if (tbinfo->relkind == RELKIND_SEQUENCE)
- 		return;
  	/* Skip FOREIGN TABLEs (no data to dump) */
  	if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
  		return;
--- 1641,1646 ----
*************** dumpDumpableObject(Archive *fout, Dumpab
*** 7318,7324 ****
  			dumpCast(fout, (CastInfo *) dobj);
  			break;
  		case DO_TABLE_DATA:
! 			dumpTableData(fout, (TableDataInfo *) dobj);
  			break;
  		case DO_DUMMY_TYPE:
  			/* table rowtypes and array types are never dumped separately */
--- 7316,7325 ----
  			dumpCast(fout, (CastInfo *) dobj);
  			break;
  		case DO_TABLE_DATA:
! 			if (((TableDataInfo *) dobj)->tdtable->relkind == RELKIND_SEQUENCE)
! 				dumpSequenceData(fout, (TableDataInfo *) dobj);
! 			else
! 				dumpTableData(fout, (TableDataInfo *) dobj);
  			break;
  		case DO_DUMMY_TYPE:
  			/* table rowtypes and array types are never dumped separately */
*************** collectSecLabels(Archive *fout, SecLabel
*** 12226,12238 ****
  static void
  dumpTable(Archive *fout, TableInfo *tbinfo)
  {
! 	if (tbinfo->dobj.dump)
  	{
  		char	   *namecopy;
  
  		if (tbinfo->relkind == RELKIND_SEQUENCE)
  			dumpSequence(fout, tbinfo);
! 		else if (!dataOnly)
  			dumpTableSchema(fout, tbinfo);
  
  		/* Handle the ACL here */
--- 12227,12239 ----
  static void
  dumpTable(Archive *fout, TableInfo *tbinfo)
  {
! 	if (tbinfo->dobj.dump && !dataOnly)
  	{
  		char	   *namecopy;
  
  		if (tbinfo->relkind == RELKIND_SEQUENCE)
  			dumpSequence(fout, tbinfo);
! 		else
  			dumpTableSchema(fout, tbinfo);
  
  		/* Handle the ACL here */
*************** findLastBuiltinOid_V70(Archive *fout)
*** 13347,13366 ****
  	return last_oid;
  }
  
  static void
  dumpSequence(Archive *fout, TableInfo *tbinfo)
  {
  	PGresult   *res;
  	char	   *startv,
- 			   *last,
  			   *incby,
  			   *maxv = NULL,
  			   *minv = NULL,
  			   *cache;
  	char		bufm[100],
  				bufx[100];
! 	bool		cycled,
! 				called;
  	PQExpBuffer query = createPQExpBuffer();
  	PQExpBuffer delqry = createPQExpBuffer();
  	PQExpBuffer labelq = createPQExpBuffer();
--- 13348,13369 ----
  	return last_oid;
  }
  
+ /*
+  * dumpSequence
+  *	  write the declaration (not data) of one user-defined sequence
+  */
  static void
  dumpSequence(Archive *fout, TableInfo *tbinfo)
  {
  	PGresult   *res;
  	char	   *startv,
  			   *incby,
  			   *maxv = NULL,
  			   *minv = NULL,
  			   *cache;
  	char		bufm[100],
  				bufx[100];
! 	bool		cycled;
  	PQExpBuffer query = createPQExpBuffer();
  	PQExpBuffer delqry = createPQExpBuffer();
  	PQExpBuffer labelq = createPQExpBuffer();
*************** dumpSequence(Archive *fout, TableInfo *t
*** 13375,13381 ****
  	{
  		appendPQExpBuffer(query,
  						  "SELECT sequence_name, "
! 						  "start_value, last_value, increment_by, "
  				   "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
  				   "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
  						  "     ELSE max_value "
--- 13378,13384 ----
  	{
  		appendPQExpBuffer(query,
  						  "SELECT sequence_name, "
! 						  "start_value, increment_by, "
  				   "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
  				   "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
  						  "     ELSE max_value "
*************** dumpSequence(Archive *fout, TableInfo *t
*** 13384,13390 ****
  				   "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
  						  "     ELSE min_value "
  						  "END AS min_value, "
! 						  "cache_value, is_cycled, is_called from %s",
  						  bufx, bufm,
  						  fmtId(tbinfo->dobj.name));
  	}
--- 13387,13393 ----
  				   "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
  						  "     ELSE min_value "
  						  "END AS min_value, "
! 						  "cache_value, is_cycled FROM %s",
  						  bufx, bufm,
  						  fmtId(tbinfo->dobj.name));
  	}
*************** dumpSequence(Archive *fout, TableInfo *t
*** 13392,13398 ****
  	{
  		appendPQExpBuffer(query,
  						  "SELECT sequence_name, "
! 						  "0 AS start_value, last_value, increment_by, "
  				   "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
  				   "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
  						  "     ELSE max_value "
--- 13395,13401 ----
  	{
  		appendPQExpBuffer(query,
  						  "SELECT sequence_name, "
! 						  "0 AS start_value, increment_by, "
  				   "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
  				   "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
  						  "     ELSE max_value "
*************** dumpSequence(Archive *fout, TableInfo *t
*** 13401,13407 ****
  				   "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
  						  "     ELSE min_value "
  						  "END AS min_value, "
! 						  "cache_value, is_cycled, is_called from %s",
  						  bufx, bufm,
  						  fmtId(tbinfo->dobj.name));
  	}
--- 13404,13410 ----
  				   "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
  						  "     ELSE min_value "
  						  "END AS min_value, "
! 						  "cache_value, is_cycled FROM %s",
  						  bufx, bufm,
  						  fmtId(tbinfo->dobj.name));
  	}
*************** dumpSequence(Archive *fout, TableInfo *t
*** 13428,13592 ****
  #endif
  
  	startv = PQgetvalue(res, 0, 1);
! 	last = PQgetvalue(res, 0, 2);
! 	incby = PQgetvalue(res, 0, 3);
  	if (!PQgetisnull(res, 0, 4))
! 		maxv = PQgetvalue(res, 0, 4);
! 	if (!PQgetisnull(res, 0, 5))
! 		minv = PQgetvalue(res, 0, 5);
! 	cache = PQgetvalue(res, 0, 6);
! 	cycled = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
! 	called = (strcmp(PQgetvalue(res, 0, 8), "t") == 0);
  
  	/*
! 	 * The logic we use for restoring sequences is as follows:
! 	 *
! 	 * Add a CREATE SEQUENCE statement as part of a "schema" dump (use
! 	 * last_val for start if called is false, else use min_val for start_val).
! 	 * Also, if the sequence is owned by a column, add an ALTER SEQUENCE OWNED
! 	 * BY command for it.
! 	 *
! 	 * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
  	 */
! 	if (!dataOnly)
! 	{
! 		/*
! 		 * DROP must be fully qualified in case same name appears in
! 		 * pg_catalog
! 		 */
! 		appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
! 						  fmtId(tbinfo->dobj.namespace->dobj.name));
! 		appendPQExpBuffer(delqry, "%s;\n",
! 						  fmtId(tbinfo->dobj.name));
  
! 		resetPQExpBuffer(query);
  
! 		if (binary_upgrade)
! 		{
! 			binary_upgrade_set_pg_class_oids(fout, query,
! 											 tbinfo->dobj.catId.oid, false);
! 			binary_upgrade_set_type_oids_by_rel_oid(fout, query,
! 													tbinfo->dobj.catId.oid);
! 		}
  
! 		appendPQExpBuffer(query,
! 						  "CREATE SEQUENCE %s\n",
! 						  fmtId(tbinfo->dobj.name));
  
! 		if (fout->remoteVersion >= 80400)
! 			appendPQExpBuffer(query, "    START WITH %s\n", startv);
! 		else
! 		{
! 			/*
! 			 * Versions before 8.4 did not remember the true start value.  If
! 			 * is_called is false then the sequence has never been incremented
! 			 * so we can use last_val.	Otherwise punt and let it default.
! 			 */
! 			if (!called)
! 				appendPQExpBuffer(query, "    START WITH %s\n", last);
! 		}
  
! 		appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
  
! 		if (minv)
! 			appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
! 		else
! 			appendPQExpBuffer(query, "    NO MINVALUE\n");
  
! 		if (maxv)
! 			appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
! 		else
! 			appendPQExpBuffer(query, "    NO MAXVALUE\n");
  
! 		appendPQExpBuffer(query,
! 						  "    CACHE %s%s",
! 						  cache, (cycled ? "\n    CYCLE" : ""));
  
! 		appendPQExpBuffer(query, ";\n");
  
! 		appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
  
! 		/* binary_upgrade:	no need to clear TOAST table oid */
  
! 		if (binary_upgrade)
! 			binary_upgrade_extension_member(query, &tbinfo->dobj,
! 											labelq->data);
  
! 		ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
! 					 tbinfo->dobj.name,
! 					 tbinfo->dobj.namespace->dobj.name,
! 					 NULL,
! 					 tbinfo->rolname,
! 					 false, "SEQUENCE", SECTION_PRE_DATA,
! 					 query->data, delqry->data, NULL,
! 					 NULL, 0,
! 					 NULL, NULL);
  
! 		/*
! 		 * If the sequence is owned by a table column, emit the ALTER for it
! 		 * as a separate TOC entry immediately following the sequence's own
! 		 * entry.  It's OK to do this rather than using full sorting logic,
! 		 * because the dependency that tells us it's owned will have forced
! 		 * the table to be created first.  We can't just include the ALTER in
! 		 * the TOC entry because it will fail if we haven't reassigned the
! 		 * sequence owner to match the table's owner.
! 		 *
! 		 * We need not schema-qualify the table reference because both
! 		 * sequence and table must be in the same schema.
! 		 */
! 		if (OidIsValid(tbinfo->owning_tab))
! 		{
! 			TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
  
! 			if (owning_tab && owning_tab->dobj.dump)
! 			{
! 				resetPQExpBuffer(query);
! 				appendPQExpBuffer(query, "ALTER SEQUENCE %s",
! 								  fmtId(tbinfo->dobj.name));
! 				appendPQExpBuffer(query, " OWNED BY %s",
! 								  fmtId(owning_tab->dobj.name));
! 				appendPQExpBuffer(query, ".%s;\n",
  						fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
  
! 				ArchiveEntry(fout, nilCatalogId, createDumpId(),
! 							 tbinfo->dobj.name,
! 							 tbinfo->dobj.namespace->dobj.name,
! 							 NULL,
! 							 tbinfo->rolname,
! 							 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
! 							 query->data, "", NULL,
! 							 &(tbinfo->dobj.dumpId), 1,
! 							 NULL, NULL);
! 			}
  		}
- 
- 		/* Dump Sequence Comments and Security Labels */
- 		dumpComment(fout, labelq->data,
- 					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
- 					tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
- 		dumpSecLabel(fout, labelq->data,
- 					 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
- 					 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
  	}
  
! 	if (!schemaOnly)
! 	{
! 		resetPQExpBuffer(query);
! 		appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
! 		appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
! 		appendPQExpBuffer(query, ", %s, %s);\n",
! 						  last, (called ? "true" : "false"));
! 
! 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
! 					 tbinfo->dobj.name,
! 					 tbinfo->dobj.namespace->dobj.name,
! 					 NULL,
! 					 tbinfo->rolname,
! 					 false, "SEQUENCE SET", SECTION_PRE_DATA,
! 					 query->data, "", NULL,
! 					 &(tbinfo->dobj.dumpId), 1,
! 					 NULL, NULL);
! 	}
  
  	PQclear(res);
  
--- 13431,13550 ----
  #endif
  
  	startv = PQgetvalue(res, 0, 1);
! 	incby = PQgetvalue(res, 0, 2);
! 	if (!PQgetisnull(res, 0, 3))
! 		maxv = PQgetvalue(res, 0, 3);
  	if (!PQgetisnull(res, 0, 4))
! 		minv = PQgetvalue(res, 0, 4);
! 	cache = PQgetvalue(res, 0, 5);
! 	cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
  
  	/*
! 	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
! 					  fmtId(tbinfo->dobj.namespace->dobj.name));
! 	appendPQExpBuffer(delqry, "%s;\n",
! 					  fmtId(tbinfo->dobj.name));
  
! 	resetPQExpBuffer(query);
  
! 	if (binary_upgrade)
! 	{
! 		binary_upgrade_set_pg_class_oids(fout, query,
! 										 tbinfo->dobj.catId.oid, false);
! 		binary_upgrade_set_type_oids_by_rel_oid(fout, query,
! 												tbinfo->dobj.catId.oid);
! 	}
  
! 	appendPQExpBuffer(query,
! 					  "CREATE SEQUENCE %s\n",
! 					  fmtId(tbinfo->dobj.name));
  
! 	if (fout->remoteVersion >= 80400)
! 		appendPQExpBuffer(query, "    START WITH %s\n", startv);
  
! 	appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
  
! 	if (minv)
! 		appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
! 	else
! 		appendPQExpBuffer(query, "    NO MINVALUE\n");
  
! 	if (maxv)
! 		appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
! 	else
! 		appendPQExpBuffer(query, "    NO MAXVALUE\n");
  
! 	appendPQExpBuffer(query,
! 					  "    CACHE %s%s",
! 					  cache, (cycled ? "\n    CYCLE" : ""));
  
! 	appendPQExpBuffer(query, ";\n");
  
! 	appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
  
! 	/* binary_upgrade:	no need to clear TOAST table oid */
  
! 	if (binary_upgrade)
! 		binary_upgrade_extension_member(query, &tbinfo->dobj,
! 										labelq->data);
  
! 	ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
! 				 tbinfo->dobj.name,
! 				 tbinfo->dobj.namespace->dobj.name,
! 				 NULL,
! 				 tbinfo->rolname,
! 				 false, "SEQUENCE", SECTION_PRE_DATA,
! 				 query->data, delqry->data, NULL,
! 				 NULL, 0,
! 				 NULL, NULL);
  
! 	/*
! 	 * If the sequence is owned by a table column, emit the ALTER for it as a
! 	 * separate TOC entry immediately following the sequence's own entry.
! 	 * It's OK to do this rather than using full sorting logic, because the
! 	 * dependency that tells us it's owned will have forced the table to be
! 	 * created first.  We can't just include the ALTER in the TOC entry
! 	 * because it will fail if we haven't reassigned the sequence owner to
! 	 * match the table's owner.
! 	 *
! 	 * We need not schema-qualify the table reference because both sequence
! 	 * and table must be in the same schema.
! 	 */
! 	if (OidIsValid(tbinfo->owning_tab))
! 	{
! 		TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
  
! 		if (owning_tab && owning_tab->dobj.dump)
! 		{
! 			resetPQExpBuffer(query);
! 			appendPQExpBuffer(query, "ALTER SEQUENCE %s",
! 							  fmtId(tbinfo->dobj.name));
! 			appendPQExpBuffer(query, " OWNED BY %s",
! 							  fmtId(owning_tab->dobj.name));
! 			appendPQExpBuffer(query, ".%s;\n",
  						fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
  
! 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
! 						 tbinfo->dobj.name,
! 						 tbinfo->dobj.namespace->dobj.name,
! 						 NULL,
! 						 tbinfo->rolname,
! 						 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
! 						 query->data, "", NULL,
! 						 &(tbinfo->dobj.dumpId), 1,
! 						 NULL, NULL);
  		}
  	}
  
! 	/* Dump Sequence Comments and Security Labels */
! 	dumpComment(fout, labelq->data,
! 				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
! 				tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
! 	dumpSecLabel(fout, labelq->data,
! 				 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
! 				 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
  
  	PQclear(res);
  
*************** dumpSequence(Archive *fout, TableInfo *t
*** 13595,13600 ****
--- 13553,13613 ----
  	destroyPQExpBuffer(labelq);
  }
  
+ /*
+  * dumpSequenceData
+  *	  write the data of one user-defined sequence
+  */
+ static void
+ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
+ {
+ 	TableInfo  *tbinfo = tdinfo->tdtable;
+ 	PGresult   *res;
+ 	char	   *last;
+ 	bool		called;
+ 	PQExpBuffer query = createPQExpBuffer();
+ 
+ 	/* Make sure we are in proper schema */
+ 	selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
+ 
+ 	appendPQExpBuffer(query,
+ 					  "SELECT last_value, is_called FROM %s",
+ 					  fmtId(tbinfo->dobj.name));
+ 
+ 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+ 
+ 	if (PQntuples(res) != 1)
+ 	{
+ 		write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
+ 								 "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
+ 								 PQntuples(res)),
+ 				  tbinfo->dobj.name, PQntuples(res));
+ 		exit_nicely(1);
+ 	}
+ 
+ 	last = PQgetvalue(res, 0, 0);
+ 	called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
+ 
+ 	resetPQExpBuffer(query);
+ 	appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
+ 	appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
+ 	appendPQExpBuffer(query, ", %s, %s);\n",
+ 					  last, (called ? "true" : "false"));
+ 
+ 	ArchiveEntry(fout, nilCatalogId, createDumpId(),
+ 				 tbinfo->dobj.name,
+ 				 tbinfo->dobj.namespace->dobj.name,
+ 				 NULL,
+ 				 tbinfo->rolname,
+ 				 false, "SEQUENCE SET", SECTION_DATA,
+ 				 query->data, "", NULL,
+ 				 &(tbinfo->dobj.dumpId), 1,
+ 				 NULL, NULL);
+ 
+ 	PQclear(res);
+ 
+ 	destroyPQExpBuffer(query);
+ }
+ 
  static void
  dumpTrigger(Archive *fout, TriggerInfo *tginfo)
  {
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to