On Mon, Sep 29, 2014 at 12:30:40PM -0400, Tom Lane wrote:
> Bruce Momjian <br...@momjian.us> writes:
> > On Thu, Sep 25, 2014 at 02:39:37PM -0400, Tom Lane wrote:
> >> BTW, it seems like there is consensus that we ought to reorder the items
> >> in a jsonb object to have keys first and then values, independently of the
> >> other issues under discussion.  This means we *will* be breaking on-disk
> >> compatibility with 9.4beta2, which means pg_upgrade will need to be taught
> >> to refuse an upgrade if the database contains any jsonb columns.  Bruce,
> >> do you have time to crank out a patch for that?
> 
> > Yes, I can do that easily.  Tell me when you want it --- I just need a
> > catalog version number to trigger on.
> 
> Done --- 201409291 is the cutover point.

Attached patch applied to head, and backpatched to 9.4.  I think we need
to keep this in all future pg_ugprade versions in case someone from the
beta tries to jump versions, e.g. 9.4 beta1 to 9.5.

-- 
  Bruce Momjian  <br...@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

  + Everyone has their own god. +
diff --git a/contrib/pg_upgrade/check.c b/contrib/pg_upgrade/check.c
new file mode 100644
index 88fe12d..bbfcab7
*** a/contrib/pg_upgrade/check.c
--- b/contrib/pg_upgrade/check.c
*************** static void check_is_install_user(Cluste
*** 24,29 ****
--- 24,30 ----
  static void check_for_prepared_transactions(ClusterInfo *cluster);
  static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
  static void check_for_reg_data_type_usage(ClusterInfo *cluster);
+ static void check_for_jsonb_9_4_usage(ClusterInfo *cluster);
  static void get_bin_version(ClusterInfo *cluster);
  static char *get_canonical_locale_name(int category, const char *locale);
  
*************** check_and_dump_old_cluster(bool live_che
*** 99,104 ****
--- 100,108 ----
  	check_for_prepared_transactions(&old_cluster);
  	check_for_reg_data_type_usage(&old_cluster);
  	check_for_isn_and_int8_passing_mismatch(&old_cluster);
+ 	if (GET_MAJOR_VERSION(old_cluster.major_version) == 904 &&
+ 		old_cluster.controldata.cat_ver < JSONB_FORMAT_CHANGE_CAT_VER)
+ 		check_for_jsonb_9_4_usage(&old_cluster);
  
  	/* Pre-PG 9.4 had a different 'line' data type internal format */
  	if (GET_MAJOR_VERSION(old_cluster.major_version) <= 903)
*************** check_for_reg_data_type_usage(ClusterInf
*** 911,916 ****
--- 915,1010 ----
  				 "    %s\n\n", output_path);
  	}
  	else
+ 		check_ok();
+ }
+ 
+ 
+ /*
+  * check_for_jsonb_9_4_usage()
+  *
+  *	JSONB changed its storage format during 9.4 beta, so check for it.
+  */
+ static void
+ check_for_jsonb_9_4_usage(ClusterInfo *cluster)
+ {
+ 	int			dbnum;
+ 	FILE	   *script = NULL;
+ 	bool		found = false;
+ 	char		output_path[MAXPGPATH];
+ 
+ 	prep_status("Checking for JSONB user data types");
+ 
+ 	snprintf(output_path, sizeof(output_path), "tables_using_jsonb.txt");
+ 
+ 	for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
+ 	{
+ 		PGresult   *res;
+ 		bool		db_used = false;
+ 		int			ntups;
+ 		int			rowno;
+ 		int			i_nspname,
+ 					i_relname,
+ 					i_attname;
+ 		DbInfo	   *active_db = &cluster->dbarr.dbs[dbnum];
+ 		PGconn	   *conn = connectToServer(cluster, active_db->db_name);
+ 
+ 		/*
+ 		 * While several relkinds don't store any data, e.g. views, they can
+ 		 * be used to define data types of other columns, so we check all
+ 		 * relkinds.
+ 		 */
+ 		res = executeQueryOrDie(conn,
+ 								"SELECT n.nspname, c.relname, a.attname "
+ 								"FROM	pg_catalog.pg_class c, "
+ 								"		pg_catalog.pg_namespace n, "
+ 								"		pg_catalog.pg_attribute a "
+ 								"WHERE	c.oid = a.attrelid AND "
+ 								"		NOT a.attisdropped AND "
+ 								"		a.atttypid = 'pg_catalog.jsonb'::pg_catalog.regtype AND "
+ 								"		c.relnamespace = n.oid AND "
+ 		/* exclude possible orphaned temp tables */
+ 								"  		n.nspname !~ '^pg_temp_' AND "
+ 							  "		n.nspname NOT IN ('pg_catalog', 'information_schema')");
+ 
+ 		ntups = PQntuples(res);
+ 		i_nspname = PQfnumber(res, "nspname");
+ 		i_relname = PQfnumber(res, "relname");
+ 		i_attname = PQfnumber(res, "attname");
+ 		for (rowno = 0; rowno < ntups; rowno++)
+ 		{
+ 			found = true;
+ 			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
+ 				pg_fatal("Could not open file \"%s\": %s\n",
+ 						 output_path, getErrorText(errno));
+ 			if (!db_used)
+ 			{
+ 				fprintf(script, "Database: %s\n", active_db->db_name);
+ 				db_used = true;
+ 			}
+ 			fprintf(script, "  %s.%s.%s\n",
+ 					PQgetvalue(res, rowno, i_nspname),
+ 					PQgetvalue(res, rowno, i_relname),
+ 					PQgetvalue(res, rowno, i_attname));
+ 		}
+ 
+ 		PQclear(res);
+ 
+ 		PQfinish(conn);
+ 	}
+ 
+ 	if (script)
+ 		fclose(script);
+ 
+ 	if (found)
+ 	{
+ 		pg_log(PG_REPORT, "fatal\n");
+ 		pg_fatal("Your installation contains one of the JSONB data types in user tables.\n"
+ 		 "The internal format of JSONB changed during 9.4 beta so this cluster cannot currently\n"
+ 				 "be upgraded.  You can remove the problem tables and restart the upgrade.  A list\n"
+ 				 "of the problem columns is in the file:\n"
+ 				 "    %s\n\n", output_path);
+ 	}
+ 	else
  		check_ok();
  }
  
diff --git a/contrib/pg_upgrade/pg_upgrade.h b/contrib/pg_upgrade/pg_upgrade.h
new file mode 100644
index 0207391..56a7505
*** a/contrib/pg_upgrade/pg_upgrade.h
--- b/contrib/pg_upgrade/pg_upgrade.h
*************** extern char *output_files[];
*** 122,127 ****
--- 122,132 ----
  #define LARGE_OBJECT_SIZE_PG_CONTROL_VER 942
  
  /*
+  * change in JSONB format during 9.4 beta
+  */
+ #define JSONB_FORMAT_CHANGE_CAT_VER 201409291
+ 
+ /*
   * Each relation is represented by a relinfo structure.
   */
  typedef struct
-- 
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