@ -24,6 +24,7 @@ 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_user_defined_postfix_ops ( ClusterInfo * cluster ) ;
static void check_for_user_defined_postfix_ops ( ClusterInfo * cluster ) ;
static void check_for_tables_with_oids ( ClusterInfo * cluster ) ;
static void check_for_tables_with_oids ( 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 ) ;
@ -100,6 +101,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 ) ;
@ -1043,6 +1045,63 @@ check_for_tables_with_oids(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 :
@ -1057,88 +1116,36 @@ check_for_tables_with_oids(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* data types in user tables " ) ;
prep_status ( " Checking for reg* data types in user tables " ) ;
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 + + )
/*
{
* Note : older servers will not have all of these reg * types , so we have
PGresult * res ;
* to write the query like this rather than depending on casts to regtype .
bool db_used = false ;
*/
int ntups ;
found = check_for_data_types_usage ( cluster ,
int rowno ;
" SELECT oid FROM pg_catalog.pg_type t "
int i_nspname ,
" WHERE t.typnamespace = "
i_relname ,
" (SELECT oid FROM pg_catalog.pg_namespace "
i_attname ;
" WHERE nspname = 'pg_catalog') "
DbInfo * active_db = & cluster - > dbarr . dbs [ dbnum ] ;
" AND t.typname IN ( "
PGconn * conn = connectToServer ( cluster , active_db - > db_name ) ;
/* pg_class.oid is preserved, so 'regclass' is OK */
" 'regcollation', "
/*
" 'regconfig', "
* While several relkinds don ' t store any data , e . g . views , they can
" 'regdictionary', "
* be used to define data types of other columns , so we check all
" 'regnamespace', "
* relkinds .
" 'regoper', "
*/
" 'regoperator', "
res = executeQueryOrDie ( conn ,
" 'regproc', "
" SELECT n.nspname, c.relname, a.attname "
" 'regprocedure' "
" FROM pg_catalog.pg_class c, "
/* pg_authid.oid is preserved, so 'regrole' is OK */
" pg_catalog.pg_namespace n, "
/* pg_type.oid is (mostly) preserved, so 'regtype' is OK */
" pg_catalog.pg_attribute a, "
" ) " ,
" pg_catalog.pg_type t "
output_path ) ;
" WHERE c.oid = a.attrelid AND "
" NOT a.attisdropped AND "
" 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 */
" 'regcollation', "
" 'regconfig', "
" 'regdictionary', "
" 'regnamespace', "
" 'regoper', "
" 'regoperator', "
" 'regproc', "
" 'regprocedure' "
/* regrole.oid is preserved, so 'regrole' is OK */
/* regtype.oid is preserved, so 'regtype' is OK */
" ) AND "
" c.relnamespace = n.oid 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 , " In 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 )
{
{
@ -1163,75 +1170,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 incompatible \" jsonb \" data type " ) ;
prep_status ( " Checking for incompatible \" jsonb \" data type " ) ;
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 , " In 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 the \" jsonb \" data type in user tables. \n "
pg_fatal ( " Your installation contains the \" jsonb \" data type in user tables. \n "