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