@ -97,27 +97,27 @@ new_9_0_populate_pg_largeobject_metadata(ClusterInfo *cluster, bool check_mode)
/*
* old_9_3_check_for_line_data_type_usage ( )
* 9.3 - > 9.4
* Fully implement the ' line ' data type in 9.4 , which previously returned
* " not enabled " by default and was only functionally enabled with a
* compile - time switch ; 9.4 " line " has different binary and text
* representation formats ; checks tables and indexes .
* 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 .
*
* We check for the type in tables , matviews , and indexes , but not views ;
* there ' s no storage involved in a view .
*/
void
old_9_3_check_for_line_data_type_usage ( ClusterInfo * cluster )
static bool
check_for_data_type_usage ( ClusterInfo * cluster , const char * typename ,
char * output_path )
{
int dbnum ;
FILE * script = NULL ;
bool found = false ;
char output_path [ MAXPGPATH ] ;
prep_status ( " Checking for incompatible \" line \" data type " ) ;
snprintf ( output_path , sizeof ( output_path ) , " tables_using_line.txt " ) ;
FILE * script = NULL ;
int dbnum ;
for ( dbnum = 0 ; dbnum < cluster - > dbarr . ndbs ; dbnum + + )
{
DbInfo * active_db = & cluster - > dbarr . dbs [ dbnum ] ;
PGconn * conn = connectToServer ( cluster , active_db - > db_name ) ;
PQExpBufferData querybuf ;
PGresult * res ;
bool db_used = false ;
int ntups ;
@ -125,50 +125,68 @@ old_9_3_check_for_line_data_type_usage(ClusterInfo *cluster)
int i_nspname ,
i_relname ,
i_attname ;
DbInfo * active_db = & cluster - > dbarr . dbs [ dbnum ] ;
PGconn * conn = connectToServer ( cluster , active_db - > db_name ) ;
/*
* The pg_catalog . line type may be wrapped in a domain or composite
* typ e , or both ( 9.3 did not allow domains on composite types , but
* there may be multi - level composite type ) . To detect these cases
* we need a recursive CTE .
* The type of interest might be wrapped in a domain , array ,
* composi te, or range , and these container types can be nested ( to
* varying extents depending on server version , but that ' s not of
* concern here ) . To handle all these cases we need a recursive CTE .
*/
res = executeQueryOrDie ( conn ,
" WITH RECURSIVE oids AS ( "
/* the pg_catalog.line type itself */
" SELECT 'pg_catalog.line'::pg_catalog.regtype AS oid "
" UNION ALL "
" SELECT * FROM ( "
/* domains on the type */
" WITH x AS (SELECT oid FROM oids) "
" SELECT t.oid FROM pg_catalog.pg_type t, x WHERE typbasetype = x.oid AND typtype = 'd' "
" UNION "
/* composite types containing the type */
" SELECT t.oid FROM pg_catalog.pg_type t, pg_catalog.pg_class c, pg_catalog.pg_attribute a, x "
" WHERE t.typtype = 'c' AND "
" t.oid = c.reltype AND "
" c.oid = a.attrelid AND "
" NOT a.attisdropped AND "
" a.atttypid = x.oid "
" ) foo "
" ) "
" 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 IN (SELECT oid FROM oids) AND "
" c.relkind IN ( "
CppAsString2 ( RELKIND_RELATION ) " , "
CppAsString2 ( RELKIND_MATVIEW ) " , "
CppAsString2 ( RELKIND_INDEX ) " ) AND "
" c.relnamespace = n.oid AND "
initPQExpBuffer ( & querybuf ) ;
appendPQExpBuffer ( & querybuf ,
" WITH RECURSIVE oids AS ( "
/* the target type itself */
" SELECT '%s'::pg_catalog.regtype AS oid "
" UNION ALL "
" SELECT * FROM ( "
/* inner WITH because we can only reference the CTE once */
" WITH x AS (SELECT oid FROM oids) "
/* domains on any type selected so far */
" SELECT t.oid FROM pg_catalog.pg_type t, x WHERE typbasetype = x.oid AND typtype = 'd' "
" UNION ALL "
/* arrays over any type selected so far */
" SELECT t.oid FROM pg_catalog.pg_type t, x WHERE typelem = x.oid AND typtype = 'b' "
" UNION ALL "
/* composite types containing any type selected so far */
" SELECT t.oid FROM pg_catalog.pg_type t, pg_catalog.pg_class c, pg_catalog.pg_attribute a, x "
" WHERE t.typtype = 'c' AND "
" t.oid = c.reltype AND "
" c.oid = a.attrelid AND "
" NOT a.attisdropped AND "
" a.atttypid = x.oid " ,
typename ) ;
/* Ranges came in in 9.2 */
if ( GET_MAJOR_VERSION ( cluster - > major_version ) > = 902 )
appendPQExpBuffer ( & querybuf ,
" UNION ALL "
/* ranges containing any type selected so far */
" SELECT t.oid FROM pg_catalog.pg_type t, pg_catalog.pg_range r, x "
" WHERE t.typtype = 'r' AND r.rngtypid = t.oid AND r.rngsubtype = x.oid " ) ;
appendPQExpBuffer ( & querybuf ,
" ) foo "
" ) "
/* now look for stored columns of any such type */
" 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 IN (SELECT oid FROM oids) AND "
" c.relkind IN ( "
CppAsString2 ( RELKIND_RELATION ) " , "
CppAsString2 ( RELKIND_MATVIEW ) " , "
CppAsString2 ( RELKIND_INDEX ) " ) AND "
" c.relnamespace = n.oid AND "
/* exclude possible orphaned temp tables */
" n.nspname !~ '^pg_temp_' AND "
" n.nspname !~ '^pg_toast_temp_' AND "
" n.nspname NOT IN ('pg_catalog', 'information_schema') " ) ;
" n.nspname !~ '^pg_temp_' AND "
" n.nspname !~ '^pg_toast_temp_' AND "
/* exclude system catalogs, too */
" n.nspname NOT IN ('pg_catalog', 'information_schema') " ) ;
res = executeQueryOrDie ( conn , " %s " , querybuf . data ) ;
ntups = PQntuples ( res ) ;
i_nspname = PQfnumber ( res , " nspname " ) ;
@ -193,13 +211,36 @@ old_9_3_check_for_line_data_type_usage(ClusterInfo *cluster)
PQclear ( res ) ;
termPQExpBuffer ( & querybuf ) ;
PQfinish ( conn ) ;
}
if ( script )
fclose ( script ) ;
if ( found )
return found ;
}
/*
* old_9_3_check_for_line_data_type_usage ( )
* 9.3 - > 9.4
* Fully implement the ' line ' data type in 9.4 , which previously returned
* " not enabled " by default and was only functionally enabled with a
* compile - time switch ; as of 9.4 " line " has a different on - disk
* representation format .
*/
void
old_9_3_check_for_line_data_type_usage ( ClusterInfo * cluster )
{
char output_path [ MAXPGPATH ] ;
prep_status ( " Checking for incompatible \" line \" data type " ) ;
snprintf ( output_path , sizeof ( output_path ) , " tables_using_line.txt " ) ;
if ( check_for_data_type_usage ( cluster , " pg_catalog.line " , output_path ) )
{
pg_log ( PG_REPORT , " fatal \n " ) ;
pg_fatal ( " Your installation contains the \" line \" data type in user tables. This \n "
@ -226,105 +267,17 @@ old_9_3_check_for_line_data_type_usage(ClusterInfo *cluster)
* mid - upgrade . Worse , if there ' s a matview with such a column , the
* DDL reload will silently change it to " text " which won ' t match the
* on - disk storage ( which is like " cstring " ) . So we * must * reject that .
* Also check composite types and domains on the " unknwown " type ( even
* combinations of both ) , in case they are used for table columns .
* We needn ' t check indexes , because " unknown " has no opclasses .
*/
void
old_9_6_check_for_unknown_data_type_usage ( ClusterInfo * cluster )
{
int dbnum ;
FILE * script = NULL ;
bool found = false ;
char output_path [ MAXPGPATH ] ;
prep_status ( " Checking for invalid \" unknown \" user columns " ) ;
snprintf ( output_path , sizeof ( output_path ) , " tables_using_unknown.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 ) ;
/*
* The pg_catalog . unknown type may be wrapped in a domain or composite
* type , or both ( 9.3 did not allow domains on composite types , but
* there may be multi - level composite type ) . To detect these cases
* we need a recursive CTE .
*/
res = executeQueryOrDie ( conn ,
" WITH RECURSIVE oids AS ( "
/* the pg_catalog.unknown type itself */
" SELECT 'pg_catalog.unknown'::pg_catalog.regtype AS oid "
" UNION ALL "
" SELECT * FROM ( "
/* domains on the type */
" WITH x AS (SELECT oid FROM oids) "
" SELECT t.oid FROM pg_catalog.pg_type t, x WHERE typbasetype = x.oid AND typtype = 'd' "
" UNION "
/* composite types containing the type */
" SELECT t.oid FROM pg_catalog.pg_type t, pg_catalog.pg_class c, pg_catalog.pg_attribute a, x "
" WHERE t.typtype = 'c' AND "
" t.oid = c.reltype AND "
" c.oid = a.attrelid AND "
" NOT a.attisdropped AND "
" a.atttypid = x.oid "
" ) foo "
" ) "
" 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 IN (SELECT oid FROM oids) AND "
" c.relkind IN ( "
CppAsString2 ( RELKIND_RELATION ) " , "
CppAsString2 ( RELKIND_MATVIEW ) " ) AND "
" c.relnamespace = n.oid AND "
/* exclude possible orphaned temp tables */
" n.nspname !~ '^pg_temp_' AND "
" n.nspname !~ '^pg_toast_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 )
if ( check_for_data_type_usage ( cluster , " pg_catalog.unknown " , output_path ) )
{
pg_log ( PG_REPORT , " fatal \n " ) ;
pg_fatal ( " Your installation contains the \" unknown \" data type in user tables. This \n "
@ -456,105 +409,18 @@ old_9_6_invalidate_hash_indexes(ClusterInfo *cluster, bool check_mode)
* which does affect the storage ( name is by - ref , but not varlena ) . This
* means user tables using sql_identifier for columns are broken because
* the on - disk format is different .
*
* We need to check all objects that might store sql_identifier on disk ,
* i . e . tables , matviews and indexes . Also check composite types in case
* they are used in this context .
*/
void
old_11_check_for_sql_identifier_data_type_usage ( ClusterInfo * cluster )
{
int dbnum ;
FILE * script = NULL ;
bool found = false ;
char output_path [ MAXPGPATH ] ;
prep_status ( " Checking for invalid \" sql_identifier \" user columns " ) ;
snprintf ( output_path , sizeof ( output_path ) , " tables_using_sql_identifier.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 ) ;
/*
* We need the recursive CTE because the sql_identifier may be wrapped
* either in a domain or composite type , or both ( in arbitrary order ) .
*/
res = executeQueryOrDie ( conn ,
" WITH RECURSIVE oids AS ( "
/* the sql_identifier type itself */
" SELECT 'information_schema.sql_identifier'::pg_catalog.regtype AS oid "
" UNION ALL "
" SELECT * FROM ( "
/* domains on the type */
" WITH x AS (SELECT oid FROM oids) "
" SELECT t.oid FROM pg_catalog.pg_type t, x WHERE typbasetype = x.oid AND typtype = 'd' "
" UNION "
/* composite types containing the type */
" SELECT t.oid FROM pg_catalog.pg_type t, pg_catalog.pg_class c, pg_catalog.pg_attribute a, x "
" WHERE t.typtype = 'c' AND "
" t.oid = c.reltype AND "
" c.oid = a.attrelid AND "
" NOT a.attisdropped AND "
" a.atttypid = x.oid "
" ) foo "
" ) "
" 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 IN (SELECT oid FROM oids) AND "
" c.relkind IN ( "
CppAsString2 ( RELKIND_RELATION ) " , "
CppAsString2 ( RELKIND_MATVIEW ) " , "
CppAsString2 ( RELKIND_INDEX ) " ) AND "
" c.relnamespace = n.oid AND "
/* exclude possible orphaned temp tables */
" n.nspname !~ '^pg_temp_' AND "
" n.nspname !~ '^pg_toast_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 )
if ( check_for_data_type_usage ( cluster , " information_schema.sql_identifier " ,
output_path ) )
{
pg_log ( PG_REPORT , " fatal \n " ) ;
pg_fatal ( " Your installation contains the \" sql_identifier \" data type in user tables \n "