@@ -23,6 +23,7 @@ static void check_is_install_user(ClusterInfo *cluster);
23
23
static void check_proper_datallowconn (ClusterInfo * cluster );
24
24
static void check_for_prepared_transactions (ClusterInfo * cluster );
25
25
static void check_for_isn_and_int8_passing_mismatch (ClusterInfo * cluster );
26
+ static void check_for_composite_data_type_usage (ClusterInfo * cluster );
26
27
static void check_for_reg_data_type_usage (ClusterInfo * cluster );
27
28
static void check_for_jsonb_9_4_usage (ClusterInfo * cluster );
28
29
static void check_for_pg_role_prefix (ClusterInfo * cluster );
@@ -98,6 +99,7 @@ check_and_dump_old_cluster(bool live_check)
98
99
check_is_install_user (& old_cluster );
99
100
check_proper_datallowconn (& old_cluster );
100
101
check_for_prepared_transactions (& old_cluster );
102
+ check_for_composite_data_type_usage (& old_cluster );
101
103
check_for_reg_data_type_usage (& old_cluster );
102
104
check_for_isn_and_int8_passing_mismatch (& old_cluster );
103
105
@@ -897,6 +899,63 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
897
899
}
898
900
899
901
902
+ /*
903
+ * check_for_composite_data_type_usage()
904
+ * Check for system-defined composite types used in user tables.
905
+ *
906
+ * The OIDs of rowtypes of system catalogs and information_schema views
907
+ * can change across major versions; unlike user-defined types, we have
908
+ * no mechanism for forcing them to be the same in the new cluster.
909
+ * Hence, if any user table uses one, that's problematic for pg_upgrade.
910
+ */
911
+ static void
912
+ check_for_composite_data_type_usage (ClusterInfo * cluster )
913
+ {
914
+ bool found ;
915
+ Oid firstUserOid ;
916
+ char output_path [MAXPGPATH ];
917
+ char * base_query ;
918
+
919
+ prep_status ("Checking for system-defined composite types in user tables" );
920
+
921
+ snprintf (output_path , sizeof (output_path ), "tables_using_composite.txt" );
922
+
923
+ /*
924
+ * Look for composite types that were made during initdb *or* belong to
925
+ * information_schema; that's important in case information_schema was
926
+ * dropped and reloaded.
927
+ *
928
+ * The cutoff OID here should match the source cluster's value of
929
+ * FirstNormalObjectId. We hardcode it rather than using that C #define
930
+ * because, if that #define is ever changed, our own version's value is
931
+ * NOT what to use. Eventually we may need a test on the source cluster's
932
+ * version to select the correct value.
933
+ */
934
+ firstUserOid = 16384 ;
935
+
936
+ base_query = psprintf ("SELECT t.oid FROM pg_catalog.pg_type t "
937
+ "LEFT JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid "
938
+ " WHERE typtype = 'c' AND (t.oid < %u OR nspname = 'information_schema')" ,
939
+ firstUserOid );
940
+
941
+ found = check_for_data_types_usage (cluster , base_query , output_path );
942
+
943
+ free (base_query );
944
+
945
+ if (found )
946
+ {
947
+ pg_log (PG_REPORT , "fatal\n" );
948
+ pg_fatal ("Your installation contains system-defined composite type(s) in user tables.\n"
949
+ "These type OIDs are not stable across PostgreSQL versions,\n"
950
+ "so this cluster cannot currently be upgraded. You can\n"
951
+ "drop the problem columns and restart the upgrade.\n"
952
+ "A list of the problem columns is in the file:\n"
953
+ " %s\n\n" , output_path );
954
+ }
955
+ else
956
+ check_ok ();
957
+ }
958
+
900
959
/*
901
960
* check_for_reg_data_type_usage()
902
961
* pg_upgrade only preserves these system values:
@@ -911,87 +970,36 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
911
970
static void
912
971
check_for_reg_data_type_usage (ClusterInfo * cluster )
913
972
{
914
- int dbnum ;
915
- FILE * script = NULL ;
916
- bool found = false;
973
+ bool found ;
917
974
char output_path [MAXPGPATH ];
918
975
919
976
prep_status ("Checking for reg* data types in user tables" );
920
977
921
978
snprintf (output_path , sizeof (output_path ), "tables_using_reg.txt" );
922
979
923
- for (dbnum = 0 ; dbnum < cluster -> dbarr .ndbs ; dbnum ++ )
924
- {
925
- PGresult * res ;
926
- bool db_used = false;
927
- int ntups ;
928
- int rowno ;
929
- int i_nspname ,
930
- i_relname ,
931
- i_attname ;
932
- DbInfo * active_db = & cluster -> dbarr .dbs [dbnum ];
933
- PGconn * conn = connectToServer (cluster , active_db -> db_name );
934
-
935
- /*
936
- * While several relkinds don't store any data, e.g. views, they can
937
- * be used to define data types of other columns, so we check all
938
- * relkinds.
939
- */
940
- res = executeQueryOrDie (conn ,
941
- "SELECT n.nspname, c.relname, a.attname "
942
- "FROM pg_catalog.pg_class c, "
943
- " pg_catalog.pg_namespace n, "
944
- " pg_catalog.pg_attribute a, "
945
- " pg_catalog.pg_type t "
946
- "WHERE c.oid = a.attrelid AND "
947
- " NOT a.attisdropped AND "
948
- " a.atttypid = t.oid AND "
949
- " t.typnamespace = "
950
- " (SELECT oid FROM pg_namespace "
951
- " WHERE nspname = 'pg_catalog') AND"
952
- " t.typname IN ( "
953
- /* regclass.oid is preserved, so 'regclass' is OK */
954
- " 'regconfig', "
955
- " 'regdictionary', "
956
- " 'regnamespace', "
957
- " 'regoper', "
958
- " 'regoperator', "
959
- " 'regproc', "
960
- " 'regprocedure' "
961
- /* regrole.oid is preserved, so 'regrole' is OK */
962
- /* regtype.oid is preserved, so 'regtype' is OK */
963
- " ) AND "
964
- " c.relnamespace = n.oid AND "
965
- " n.nspname NOT IN ('pg_catalog', 'information_schema')" );
966
-
967
- ntups = PQntuples (res );
968
- i_nspname = PQfnumber (res , "nspname" );
969
- i_relname = PQfnumber (res , "relname" );
970
- i_attname = PQfnumber (res , "attname" );
971
- for (rowno = 0 ; rowno < ntups ; rowno ++ )
972
- {
973
- found = true;
974
- if (script == NULL && (script = fopen_priv (output_path , "w" )) == NULL )
975
- pg_fatal ("could not open file \"%s\": %s\n" ,
976
- output_path , strerror (errno ));
977
- if (!db_used )
978
- {
979
- fprintf (script , "Database: %s\n" , active_db -> db_name );
980
- db_used = true;
981
- }
982
- fprintf (script , " %s.%s.%s\n" ,
983
- PQgetvalue (res , rowno , i_nspname ),
984
- PQgetvalue (res , rowno , i_relname ),
985
- PQgetvalue (res , rowno , i_attname ));
986
- }
987
-
988
- PQclear (res );
989
-
990
- PQfinish (conn );
991
- }
992
-
993
- if (script )
994
- fclose (script );
980
+ /*
981
+ * Note: older servers will not have all of these reg* types, so we have
982
+ * to write the query like this rather than depending on casts to regtype.
983
+ */
984
+ found = check_for_data_types_usage (cluster ,
985
+ "SELECT oid FROM pg_catalog.pg_type t "
986
+ "WHERE t.typnamespace = "
987
+ " (SELECT oid FROM pg_catalog.pg_namespace "
988
+ " WHERE nspname = 'pg_catalog') "
989
+ " AND t.typname IN ( "
990
+ /* pg_class.oid is preserved, so 'regclass' is OK */
991
+ " 'regcollation', "
992
+ " 'regconfig', "
993
+ " 'regdictionary', "
994
+ " 'regnamespace', "
995
+ " 'regoper', "
996
+ " 'regoperator', "
997
+ " 'regproc', "
998
+ " 'regprocedure' "
999
+ /* pg_authid.oid is preserved, so 'regrole' is OK */
1000
+ /* pg_type.oid is (mostly) preserved, so 'regtype' is OK */
1001
+ " )" ,
1002
+ output_path );
995
1003
996
1004
if (found )
997
1005
{
@@ -1016,75 +1024,13 @@ check_for_reg_data_type_usage(ClusterInfo *cluster)
1016
1024
static void
1017
1025
check_for_jsonb_9_4_usage (ClusterInfo * cluster )
1018
1026
{
1019
- int dbnum ;
1020
- FILE * script = NULL ;
1021
- bool found = false;
1022
1027
char output_path [MAXPGPATH ];
1023
1028
1024
1029
prep_status ("Checking for incompatible \"jsonb\" data type" );
1025
1030
1026
1031
snprintf (output_path , sizeof (output_path ), "tables_using_jsonb.txt" );
1027
1032
1028
- for (dbnum = 0 ; dbnum < cluster -> dbarr .ndbs ; dbnum ++ )
1029
- {
1030
- PGresult * res ;
1031
- bool db_used = false;
1032
- int ntups ;
1033
- int rowno ;
1034
- int i_nspname ,
1035
- i_relname ,
1036
- i_attname ;
1037
- DbInfo * active_db = & cluster -> dbarr .dbs [dbnum ];
1038
- PGconn * conn = connectToServer (cluster , active_db -> db_name );
1039
-
1040
- /*
1041
- * While several relkinds don't store any data, e.g. views, they can
1042
- * be used to define data types of other columns, so we check all
1043
- * relkinds.
1044
- */
1045
- res = executeQueryOrDie (conn ,
1046
- "SELECT n.nspname, c.relname, a.attname "
1047
- "FROM pg_catalog.pg_class c, "
1048
- " pg_catalog.pg_namespace n, "
1049
- " pg_catalog.pg_attribute a "
1050
- "WHERE c.oid = a.attrelid AND "
1051
- " NOT a.attisdropped AND "
1052
- " a.atttypid = 'pg_catalog.jsonb'::pg_catalog.regtype AND "
1053
- " c.relnamespace = n.oid AND "
1054
- /* exclude possible orphaned temp tables */
1055
- " n.nspname !~ '^pg_temp_' AND "
1056
- " n.nspname NOT IN ('pg_catalog', 'information_schema')" );
1057
-
1058
- ntups = PQntuples (res );
1059
- i_nspname = PQfnumber (res , "nspname" );
1060
- i_relname = PQfnumber (res , "relname" );
1061
- i_attname = PQfnumber (res , "attname" );
1062
- for (rowno = 0 ; rowno < ntups ; rowno ++ )
1063
- {
1064
- found = true;
1065
- if (script == NULL && (script = fopen_priv (output_path , "w" )) == NULL )
1066
- pg_fatal ("could not open file \"%s\": %s\n" ,
1067
- output_path , strerror (errno ));
1068
- if (!db_used )
1069
- {
1070
- fprintf (script , "Database: %s\n" , active_db -> db_name );
1071
- db_used = true;
1072
- }
1073
- fprintf (script , " %s.%s.%s\n" ,
1074
- PQgetvalue (res , rowno , i_nspname ),
1075
- PQgetvalue (res , rowno , i_relname ),
1076
- PQgetvalue (res , rowno , i_attname ));
1077
- }
1078
-
1079
- PQclear (res );
1080
-
1081
- PQfinish (conn );
1082
- }
1083
-
1084
- if (script )
1085
- fclose (script );
1086
-
1087
- if (found )
1033
+ if (check_for_data_type_usage (cluster , "pg_catalog.jsonb" , output_path ))
1088
1034
{
1089
1035
pg_log (PG_REPORT , "fatal\n" );
1090
1036
pg_fatal ("Your installation contains the \"jsonb\" data type in user tables.\n"
0 commit comments