mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Fix some more omissions in pg_upgrade's tests for non-upgradable types.
Commits 29aeda6e4 et al closed up some oversights involving not checking
for non-upgradable types within container types, such as arrays and
ranges.  However, I only looked at version.c, failing to notice that
there were substantially-equivalent tests in check.c.  (The division
of responsibility between those files is less than clear...)
In addition, because genbki.pl does not guarantee that auto-generated
rowtype OIDs will hold still across versions, we need to consider that
the composite type associated with a system catalog or view is
non-upgradable.  It seems unlikely that someone would have a user
column declared that way, but if they did, trying to read it in another
PG version would likely draw "no such pg_type OID" failures, thanks
to the type OID embedded in composite Datums.
To support the composite and reg*-type cases, extend the recursive
query that does the search to allow any base query that returns
a column of pg_type OIDs, rather than limiting it to exactly one
starting type.
As before, back-patch to all supported branches.
Discussion: https://postgr.es/m/2798740.1619622555@sss.pgh.pa.us
			
			
This commit is contained in:
		@@ -23,6 +23,7 @@ static void check_is_install_user(ClusterInfo *cluster);
 | 
				
			|||||||
static void check_proper_datallowconn(ClusterInfo *cluster);
 | 
					static void check_proper_datallowconn(ClusterInfo *cluster);
 | 
				
			||||||
static void check_for_prepared_transactions(ClusterInfo *cluster);
 | 
					static void check_for_prepared_transactions(ClusterInfo *cluster);
 | 
				
			||||||
static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
 | 
					static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
 | 
				
			||||||
 | 
					static void check_for_composite_data_type_usage(ClusterInfo *cluster);
 | 
				
			||||||
static void check_for_reg_data_type_usage(ClusterInfo *cluster);
 | 
					static void check_for_reg_data_type_usage(ClusterInfo *cluster);
 | 
				
			||||||
static void check_for_jsonb_9_4_usage(ClusterInfo *cluster);
 | 
					static void check_for_jsonb_9_4_usage(ClusterInfo *cluster);
 | 
				
			||||||
static void check_for_pg_role_prefix(ClusterInfo *cluster);
 | 
					static void check_for_pg_role_prefix(ClusterInfo *cluster);
 | 
				
			||||||
@@ -97,6 +98,7 @@ check_and_dump_old_cluster(bool live_check)
 | 
				
			|||||||
	check_is_install_user(&old_cluster);
 | 
						check_is_install_user(&old_cluster);
 | 
				
			||||||
	check_proper_datallowconn(&old_cluster);
 | 
						check_proper_datallowconn(&old_cluster);
 | 
				
			||||||
	check_for_prepared_transactions(&old_cluster);
 | 
						check_for_prepared_transactions(&old_cluster);
 | 
				
			||||||
 | 
						check_for_composite_data_type_usage(&old_cluster);
 | 
				
			||||||
	check_for_reg_data_type_usage(&old_cluster);
 | 
						check_for_reg_data_type_usage(&old_cluster);
 | 
				
			||||||
	check_for_isn_and_int8_passing_mismatch(&old_cluster);
 | 
						check_for_isn_and_int8_passing_mismatch(&old_cluster);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -887,6 +889,63 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * check_for_composite_data_type_usage()
 | 
				
			||||||
 | 
					 *	Check for system-defined composite types used in user tables.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	The OIDs of rowtypes of system catalogs and information_schema views
 | 
				
			||||||
 | 
					 *	can change across major versions; unlike user-defined types, we have
 | 
				
			||||||
 | 
					 *	no mechanism for forcing them to be the same in the new cluster.
 | 
				
			||||||
 | 
					 *	Hence, if any user table uses one, that's problematic for pg_upgrade.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					check_for_composite_data_type_usage(ClusterInfo *cluster)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						bool		found;
 | 
				
			||||||
 | 
						Oid			firstUserOid;
 | 
				
			||||||
 | 
						char		output_path[MAXPGPATH];
 | 
				
			||||||
 | 
						char	   *base_query;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						prep_status("Checking for system-defined composite types in user tables");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snprintf(output_path, sizeof(output_path), "tables_using_composite.txt");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Look for composite types that were made during initdb *or* belong to
 | 
				
			||||||
 | 
						 * information_schema; that's important in case information_schema was
 | 
				
			||||||
 | 
						 * dropped and reloaded.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * The cutoff OID here should match the source cluster's value of
 | 
				
			||||||
 | 
						 * FirstNormalObjectId.  We hardcode it rather than using that C #define
 | 
				
			||||||
 | 
						 * because, if that #define is ever changed, our own version's value is
 | 
				
			||||||
 | 
						 * NOT what to use.  Eventually we may need a test on the source cluster's
 | 
				
			||||||
 | 
						 * version to select the correct value.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						firstUserOid = 16384;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						base_query = psprintf("SELECT t.oid FROM pg_catalog.pg_type t "
 | 
				
			||||||
 | 
											  "LEFT JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid "
 | 
				
			||||||
 | 
											  " WHERE typtype = 'c' AND (t.oid < %u OR nspname = 'information_schema')",
 | 
				
			||||||
 | 
											  firstUserOid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						found = check_for_data_types_usage(cluster, base_query, output_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free(base_query);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (found)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							pg_log(PG_REPORT, "fatal\n");
 | 
				
			||||||
 | 
							pg_fatal("Your installation contains system-defined composite type(s) in user tables.\n"
 | 
				
			||||||
 | 
									 "These type OIDs are not stable across PostgreSQL versions,\n"
 | 
				
			||||||
 | 
									 "so this cluster cannot currently be upgraded.  You can\n"
 | 
				
			||||||
 | 
									 "drop the problem columns and restart the upgrade.\n"
 | 
				
			||||||
 | 
									 "A list of the problem columns is in the file:\n"
 | 
				
			||||||
 | 
									 "    %s\n\n", output_path);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							check_ok();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * check_for_reg_data_type_usage()
 | 
					 * check_for_reg_data_type_usage()
 | 
				
			||||||
 *	pg_upgrade only preserves these system values:
 | 
					 *	pg_upgrade only preserves these system values:
 | 
				
			||||||
@@ -901,46 +960,25 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
 | 
				
			|||||||
static void
 | 
					static void
 | 
				
			||||||
check_for_reg_data_type_usage(ClusterInfo *cluster)
 | 
					check_for_reg_data_type_usage(ClusterInfo *cluster)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int			dbnum;
 | 
						bool		found;
 | 
				
			||||||
	FILE	   *script = NULL;
 | 
					 | 
				
			||||||
	bool		found = false;
 | 
					 | 
				
			||||||
	char		output_path[MAXPGPATH];
 | 
						char		output_path[MAXPGPATH];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	prep_status("Checking for reg* system OID user data types");
 | 
						prep_status("Checking for reg* system OID user data types");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snprintf(output_path, sizeof(output_path), "tables_using_reg.txt");
 | 
						snprintf(output_path, sizeof(output_path), "tables_using_reg.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
 | 
						 * Note: older servers will not have all of these reg* types, so we have
 | 
				
			||||||
		 * be used to define data types of other columns, so we check all
 | 
						 * to write the query like this rather than depending on casts to regtype.
 | 
				
			||||||
		 * relkinds.
 | 
					 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
		res = executeQueryOrDie(conn,
 | 
						found = check_for_data_types_usage(cluster,
 | 
				
			||||||
								"SELECT n.nspname, c.relname, a.attname "
 | 
														   "SELECT oid FROM pg_catalog.pg_type t "
 | 
				
			||||||
								"FROM	pg_catalog.pg_class c, "
 | 
														   "WHERE t.typnamespace = "
 | 
				
			||||||
								"		pg_catalog.pg_namespace n, "
 | 
														   "        (SELECT oid FROM pg_catalog.pg_namespace "
 | 
				
			||||||
								"		pg_catalog.pg_attribute a, "
 | 
														   "         WHERE nspname = 'pg_catalog') "
 | 
				
			||||||
								"		pg_catalog.pg_type t "
 | 
														   "  AND t.typname IN ( "
 | 
				
			||||||
								"WHERE	c.oid = a.attrelid AND "
 | 
						/* pg_class.oid is preserved, so 'regclass' is OK */
 | 
				
			||||||
								"		NOT a.attisdropped AND "
 | 
														   "           'regcollation', "
 | 
				
			||||||
								"       a.atttypid = t.oid AND "
 | 
					 | 
				
			||||||
								"       t.typnamespace = "
 | 
					 | 
				
			||||||
								"           (SELECT oid FROM pg_namespace "
 | 
					 | 
				
			||||||
								"            WHERE nspname = 'pg_catalog') AND"
 | 
					 | 
				
			||||||
								"		t.typname IN ( "
 | 
					 | 
				
			||||||
		/* regclass.oid is preserved, so 'regclass' is OK */
 | 
					 | 
				
			||||||
									   "           'regconfig', "
 | 
														   "           'regconfig', "
 | 
				
			||||||
									   "           'regdictionary', "
 | 
														   "           'regdictionary', "
 | 
				
			||||||
									   "           'regnamespace', "
 | 
														   "           'regnamespace', "
 | 
				
			||||||
@@ -948,40 +986,10 @@ check_for_reg_data_type_usage(ClusterInfo *cluster)
 | 
				
			|||||||
									   "           'regoperator', "
 | 
														   "           'regoperator', "
 | 
				
			||||||
									   "           'regproc', "
 | 
														   "           'regproc', "
 | 
				
			||||||
									   "           'regprocedure' "
 | 
														   "           'regprocedure' "
 | 
				
			||||||
		/* regrole.oid is preserved, so 'regrole' is OK */
 | 
						/* pg_authid.oid is preserved, so 'regrole' is OK */
 | 
				
			||||||
		/* regtype.oid is preserved, so 'regtype' is OK */
 | 
						/* pg_type.oid is (mostly) preserved, so 'regtype' is OK */
 | 
				
			||||||
								"			) AND "
 | 
														   "         )",
 | 
				
			||||||
								"		c.relnamespace = n.oid AND "
 | 
														   output_path);
 | 
				
			||||||
								"		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, strerror(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)
 | 
						if (found)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -1006,75 +1014,13 @@ check_for_reg_data_type_usage(ClusterInfo *cluster)
 | 
				
			|||||||
static void
 | 
					static void
 | 
				
			||||||
check_for_jsonb_9_4_usage(ClusterInfo *cluster)
 | 
					check_for_jsonb_9_4_usage(ClusterInfo *cluster)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int			dbnum;
 | 
					 | 
				
			||||||
	FILE	   *script = NULL;
 | 
					 | 
				
			||||||
	bool		found = false;
 | 
					 | 
				
			||||||
	char		output_path[MAXPGPATH];
 | 
						char		output_path[MAXPGPATH];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	prep_status("Checking for JSONB user data types");
 | 
						prep_status("Checking for JSONB user data types");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snprintf(output_path, sizeof(output_path), "tables_using_jsonb.txt");
 | 
						snprintf(output_path, sizeof(output_path), "tables_using_jsonb.txt");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
 | 
						if (check_for_data_type_usage(cluster, "pg_catalog.jsonb", output_path))
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		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, strerror(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_log(PG_REPORT, "fatal\n");
 | 
				
			||||||
		pg_fatal("Your installation contains one of the JSONB data types in user tables.\n"
 | 
							pg_fatal("Your installation contains one of the JSONB data types in user tables.\n"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -441,6 +441,12 @@ void		pg_putenv(const char *var, const char *val);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* version.c */
 | 
					/* version.c */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool		check_for_data_types_usage(ClusterInfo *cluster,
 | 
				
			||||||
 | 
														   const char *base_query,
 | 
				
			||||||
 | 
														   const char *output_path);
 | 
				
			||||||
 | 
					bool		check_for_data_type_usage(ClusterInfo *cluster,
 | 
				
			||||||
 | 
														  const char *typename,
 | 
				
			||||||
 | 
														  const char *output_path);
 | 
				
			||||||
void new_9_0_populate_pg_largeobject_metadata(ClusterInfo *cluster,
 | 
					void new_9_0_populate_pg_largeobject_metadata(ClusterInfo *cluster,
 | 
				
			||||||
										 bool check_mode);
 | 
															 bool check_mode);
 | 
				
			||||||
void		old_9_3_check_for_line_data_type_usage(ClusterInfo *cluster);
 | 
					void		old_9_3_check_for_line_data_type_usage(ClusterInfo *cluster);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -100,17 +100,22 @@ new_9_0_populate_pg_largeobject_metadata(ClusterInfo *cluster, bool check_mode)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * check_for_data_type_usage
 | 
					 * check_for_data_types_usage()
 | 
				
			||||||
 *	Detect whether there are any stored columns depending on the given type
 | 
					 *	Detect whether there are any stored columns depending on given type(s)
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * If so, write a report to the given file name, and return true.
 | 
					 * If so, write a report to the given file name, and return true.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * We check for the type in tables, matviews, and indexes, but not views;
 | 
					 * base_query should be a SELECT yielding a single column named "oid",
 | 
				
			||||||
 | 
					 * containing the pg_type OIDs of one or more types that are known to have
 | 
				
			||||||
 | 
					 * inconsistent on-disk representations across server versions.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * We check for the type(s) in tables, matviews, and indexes, but not views;
 | 
				
			||||||
 * there's no storage involved in a view.
 | 
					 * there's no storage involved in a view.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static bool
 | 
					bool
 | 
				
			||||||
check_for_data_type_usage(ClusterInfo *cluster, const char *typename,
 | 
					check_for_data_types_usage(ClusterInfo *cluster,
 | 
				
			||||||
						  char *output_path)
 | 
											   const char *base_query,
 | 
				
			||||||
 | 
											   const char *output_path)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	bool		found = false;
 | 
						bool		found = false;
 | 
				
			||||||
	FILE	   *script = NULL;
 | 
						FILE	   *script = NULL;
 | 
				
			||||||
@@ -130,7 +135,7 @@ check_for_data_type_usage(ClusterInfo *cluster, const char *typename,
 | 
				
			|||||||
					i_attname;
 | 
										i_attname;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * The type of interest might be wrapped in a domain, array,
 | 
							 * The type(s) of interest might be wrapped in a domain, array,
 | 
				
			||||||
		 * composite, or range, and these container types can be nested (to
 | 
							 * composite, or range, and these container types can be nested (to
 | 
				
			||||||
		 * varying extents depending on server version, but that's not of
 | 
							 * varying extents depending on server version, but that's not of
 | 
				
			||||||
		 * concern here).  To handle all these cases we need a recursive CTE.
 | 
							 * concern here).  To handle all these cases we need a recursive CTE.
 | 
				
			||||||
@@ -138,8 +143,8 @@ check_for_data_type_usage(ClusterInfo *cluster, const char *typename,
 | 
				
			|||||||
		initPQExpBuffer(&querybuf);
 | 
							initPQExpBuffer(&querybuf);
 | 
				
			||||||
		appendPQExpBuffer(&querybuf,
 | 
							appendPQExpBuffer(&querybuf,
 | 
				
			||||||
						  "WITH RECURSIVE oids AS ( "
 | 
											  "WITH RECURSIVE oids AS ( "
 | 
				
			||||||
		/* the target type itself */
 | 
							/* start with the type(s) returned by base_query */
 | 
				
			||||||
						  "	SELECT '%s'::pg_catalog.regtype AS oid "
 | 
											  "	%s "
 | 
				
			||||||
						  "	UNION ALL "
 | 
											  "	UNION ALL "
 | 
				
			||||||
						  "	SELECT * FROM ( "
 | 
											  "	SELECT * FROM ( "
 | 
				
			||||||
		/* inner WITH because we can only reference the CTE once */
 | 
							/* inner WITH because we can only reference the CTE once */
 | 
				
			||||||
@@ -157,7 +162,7 @@ check_for_data_type_usage(ClusterInfo *cluster, const char *typename,
 | 
				
			|||||||
						  "				  c.oid = a.attrelid AND "
 | 
											  "				  c.oid = a.attrelid AND "
 | 
				
			||||||
						  "				  NOT a.attisdropped AND "
 | 
											  "				  NOT a.attisdropped AND "
 | 
				
			||||||
						  "				  a.atttypid = x.oid ",
 | 
											  "				  a.atttypid = x.oid ",
 | 
				
			||||||
						  typename);
 | 
											  base_query);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Ranges came in in 9.2 */
 | 
							/* Ranges came in in 9.2 */
 | 
				
			||||||
		if (GET_MAJOR_VERSION(cluster->major_version) >= 902)
 | 
							if (GET_MAJOR_VERSION(cluster->major_version) >= 902)
 | 
				
			||||||
@@ -225,6 +230,34 @@ check_for_data_type_usage(ClusterInfo *cluster, const char *typename,
 | 
				
			|||||||
	return found;
 | 
						return found;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * check_for_data_type_usage()
 | 
				
			||||||
 | 
					 *	Detect whether there are any stored columns depending on the given type
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If so, write a report to the given file name, and return true.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * typename should be a fully qualified type name.  This is just a
 | 
				
			||||||
 | 
					 * trivial wrapper around check_for_data_types_usage() to convert a
 | 
				
			||||||
 | 
					 * type name into a base query.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool
 | 
				
			||||||
 | 
					check_for_data_type_usage(ClusterInfo *cluster,
 | 
				
			||||||
 | 
											  const char *typename,
 | 
				
			||||||
 | 
											  const char *output_path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						bool		found;
 | 
				
			||||||
 | 
						char	   *base_query;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						base_query = psprintf("SELECT '%s'::pg_catalog.regtype AS oid",
 | 
				
			||||||
 | 
											  typename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						found = check_for_data_types_usage(cluster, base_query, output_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free(base_query);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return found;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * old_9_3_check_for_line_data_type_usage()
 | 
					 * old_9_3_check_for_line_data_type_usage()
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user