@@ -24,6 +24,7 @@ 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
26
static void check_for_tables_with_oids (ClusterInfo * cluster );
27
+ static void check_for_composite_data_type_usage (ClusterInfo * cluster );
27
28
static void check_for_reg_data_type_usage (ClusterInfo * cluster );
28
29
static void check_for_jsonb_9_4_usage (ClusterInfo * cluster );
29
30
static void check_for_pg_role_prefix (ClusterInfo * cluster );
@@ -99,6 +100,7 @@ check_and_dump_old_cluster(bool live_check)
99
100
check_is_install_user (& old_cluster );
100
101
check_proper_datallowconn (& old_cluster );
101
102
check_for_prepared_transactions (& old_cluster );
103
+ check_for_composite_data_type_usage (& old_cluster );
102
104
check_for_reg_data_type_usage (& old_cluster );
103
105
check_for_isn_and_int8_passing_mismatch (& old_cluster );
104
106
@@ -1001,6 +1003,63 @@ check_for_tables_with_oids(ClusterInfo *cluster)
1001
1003
}
1002
1004
1003
1005
1006
+ /*
1007
+ * check_for_composite_data_type_usage()
1008
+ * Check for system-defined composite types used in user tables.
1009
+ *
1010
+ * The OIDs of rowtypes of system catalogs and information_schema views
1011
+ * can change across major versions; unlike user-defined types, we have
1012
+ * no mechanism for forcing them to be the same in the new cluster.
1013
+ * Hence, if any user table uses one, that's problematic for pg_upgrade.
1014
+ */
1015
+ static void
1016
+ check_for_composite_data_type_usage (ClusterInfo * cluster )
1017
+ {
1018
+ bool found ;
1019
+ Oid firstUserOid ;
1020
+ char output_path [MAXPGPATH ];
1021
+ char * base_query ;
1022
+
1023
+ prep_status ("Checking for system-defined composite types in user tables" );
1024
+
1025
+ snprintf (output_path , sizeof (output_path ), "tables_using_composite.txt" );
1026
+
1027
+ /*
1028
+ * Look for composite types that were made during initdb *or* belong to
1029
+ * information_schema; that's important in case information_schema was
1030
+ * dropped and reloaded.
1031
+ *
1032
+ * The cutoff OID here should match the source cluster's value of
1033
+ * FirstNormalObjectId. We hardcode it rather than using that C #define
1034
+ * because, if that #define is ever changed, our own version's value is
1035
+ * NOT what to use. Eventually we may need a test on the source cluster's
1036
+ * version to select the correct value.
1037
+ */
1038
+ firstUserOid = 16384 ;
1039
+
1040
+ base_query = psprintf ("SELECT t.oid FROM pg_catalog.pg_type t "
1041
+ "LEFT JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid "
1042
+ " WHERE typtype = 'c' AND (t.oid < %u OR nspname = 'information_schema')" ,
1043
+ firstUserOid );
1044
+
1045
+ found = check_for_data_types_usage (cluster , base_query , output_path );
1046
+
1047
+ free (base_query );
1048
+
1049
+ if (found )
1050
+ {
1051
+ pg_log (PG_REPORT , "fatal\n" );
1052
+ pg_fatal ("Your installation contains system-defined composite type(s) in user tables.\n"
1053
+ "These type OIDs are not stable across PostgreSQL versions,\n"
1054
+ "so this cluster cannot currently be upgraded. You can\n"
1055
+ "drop the problem columns and restart the upgrade.\n"
1056
+ "A list of the problem columns is in the file:\n"
1057
+ " %s\n\n" , output_path );
1058
+ }
1059
+ else
1060
+ check_ok ();
1061
+ }
1062
+
1004
1063
/*
1005
1064
* check_for_reg_data_type_usage()
1006
1065
* pg_upgrade only preserves these system values:
@@ -1015,87 +1074,36 @@ check_for_tables_with_oids(ClusterInfo *cluster)
1015
1074
static void
1016
1075
check_for_reg_data_type_usage (ClusterInfo * cluster )
1017
1076
{
1018
- int dbnum ;
1019
- FILE * script = NULL ;
1020
- bool found = false;
1077
+ bool found ;
1021
1078
char output_path [MAXPGPATH ];
1022
1079
1023
1080
prep_status ("Checking for reg* data types in user tables" );
1024
1081
1025
1082
snprintf (output_path , sizeof (output_path ), "tables_using_reg.txt" );
1026
1083
1027
- for (dbnum = 0 ; dbnum < cluster -> dbarr .ndbs ; dbnum ++ )
1028
- {
1029
- PGresult * res ;
1030
- bool db_used = false;
1031
- int ntups ;
1032
- int rowno ;
1033
- int i_nspname ,
1034
- i_relname ,
1035
- i_attname ;
1036
- DbInfo * active_db = & cluster -> dbarr .dbs [dbnum ];
1037
- PGconn * conn = connectToServer (cluster , active_db -> db_name );
1038
-
1039
- /*
1040
- * While several relkinds don't store any data, e.g. views, they can
1041
- * be used to define data types of other columns, so we check all
1042
- * relkinds.
1043
- */
1044
- res = executeQueryOrDie (conn ,
1045
- "SELECT n.nspname, c.relname, a.attname "
1046
- "FROM pg_catalog.pg_class c, "
1047
- " pg_catalog.pg_namespace n, "
1048
- " pg_catalog.pg_attribute a, "
1049
- " pg_catalog.pg_type t "
1050
- "WHERE c.oid = a.attrelid AND "
1051
- " NOT a.attisdropped AND "
1052
- " a.atttypid = t.oid AND "
1053
- " t.typnamespace = "
1054
- " (SELECT oid FROM pg_namespace "
1055
- " WHERE nspname = 'pg_catalog') AND"
1056
- " t.typname IN ( "
1057
- /* regclass.oid is preserved, so 'regclass' is OK */
1058
- " 'regconfig', "
1059
- " 'regdictionary', "
1060
- " 'regnamespace', "
1061
- " 'regoper', "
1062
- " 'regoperator', "
1063
- " 'regproc', "
1064
- " 'regprocedure' "
1065
- /* regrole.oid is preserved, so 'regrole' is OK */
1066
- /* regtype.oid is preserved, so 'regtype' is OK */
1067
- " ) AND "
1068
- " c.relnamespace = n.oid AND "
1069
- " n.nspname NOT IN ('pg_catalog', 'information_schema')" );
1070
-
1071
- ntups = PQntuples (res );
1072
- i_nspname = PQfnumber (res , "nspname" );
1073
- i_relname = PQfnumber (res , "relname" );
1074
- i_attname = PQfnumber (res , "attname" );
1075
- for (rowno = 0 ; rowno < ntups ; rowno ++ )
1076
- {
1077
- found = true;
1078
- if (script == NULL && (script = fopen_priv (output_path , "w" )) == NULL )
1079
- pg_fatal ("could not open file \"%s\": %s\n" ,
1080
- output_path , strerror (errno ));
1081
- if (!db_used )
1082
- {
1083
- fprintf (script , "Database: %s\n" , active_db -> db_name );
1084
- db_used = true;
1085
- }
1086
- fprintf (script , " %s.%s.%s\n" ,
1087
- PQgetvalue (res , rowno , i_nspname ),
1088
- PQgetvalue (res , rowno , i_relname ),
1089
- PQgetvalue (res , rowno , i_attname ));
1090
- }
1091
-
1092
- PQclear (res );
1093
-
1094
- PQfinish (conn );
1095
- }
1096
-
1097
- if (script )
1098
- fclose (script );
1084
+ /*
1085
+ * Note: older servers will not have all of these reg* types, so we have
1086
+ * to write the query like this rather than depending on casts to regtype.
1087
+ */
1088
+ found = check_for_data_types_usage (cluster ,
1089
+ "SELECT oid FROM pg_catalog.pg_type t "
1090
+ "WHERE t.typnamespace = "
1091
+ " (SELECT oid FROM pg_catalog.pg_namespace "
1092
+ " WHERE nspname = 'pg_catalog') "
1093
+ " AND t.typname IN ( "
1094
+ /* pg_class.oid is preserved, so 'regclass' is OK */
1095
+ " 'regcollation', "
1096
+ " 'regconfig', "
1097
+ " 'regdictionary', "
1098
+ " 'regnamespace', "
1099
+ " 'regoper', "
1100
+ " 'regoperator', "
1101
+ " 'regproc', "
1102
+ " 'regprocedure' "
1103
+ /* pg_authid.oid is preserved, so 'regrole' is OK */
1104
+ /* pg_type.oid is (mostly) preserved, so 'regtype' is OK */
1105
+ " )" ,
1106
+ output_path );
1099
1107
1100
1108
if (found )
1101
1109
{
@@ -1120,75 +1128,13 @@ check_for_reg_data_type_usage(ClusterInfo *cluster)
1120
1128
static void
1121
1129
check_for_jsonb_9_4_usage (ClusterInfo * cluster )
1122
1130
{
1123
- int dbnum ;
1124
- FILE * script = NULL ;
1125
- bool found = false;
1126
1131
char output_path [MAXPGPATH ];
1127
1132
1128
1133
prep_status ("Checking for incompatible \"jsonb\" data type" );
1129
1134
1130
1135
snprintf (output_path , sizeof (output_path ), "tables_using_jsonb.txt" );
1131
1136
1132
- for (dbnum = 0 ; dbnum < cluster -> dbarr .ndbs ; dbnum ++ )
1133
- {
1134
- PGresult * res ;
1135
- bool db_used = false;
1136
- int ntups ;
1137
- int rowno ;
1138
- int i_nspname ,
1139
- i_relname ,
1140
- i_attname ;
1141
- DbInfo * active_db = & cluster -> dbarr .dbs [dbnum ];
1142
- PGconn * conn = connectToServer (cluster , active_db -> db_name );
1143
-
1144
- /*
1145
- * While several relkinds don't store any data, e.g. views, they can
1146
- * be used to define data types of other columns, so we check all
1147
- * relkinds.
1148
- */
1149
- res = executeQueryOrDie (conn ,
1150
- "SELECT n.nspname, c.relname, a.attname "
1151
- "FROM pg_catalog.pg_class c, "
1152
- " pg_catalog.pg_namespace n, "
1153
- " pg_catalog.pg_attribute a "
1154
- "WHERE c.oid = a.attrelid AND "
1155
- " NOT a.attisdropped AND "
1156
- " a.atttypid = 'pg_catalog.jsonb'::pg_catalog.regtype AND "
1157
- " c.relnamespace = n.oid AND "
1158
- /* exclude possible orphaned temp tables */
1159
- " n.nspname !~ '^pg_temp_' AND "
1160
- " n.nspname NOT IN ('pg_catalog', 'information_schema')" );
1161
-
1162
- ntups = PQntuples (res );
1163
- i_nspname = PQfnumber (res , "nspname" );
1164
- i_relname = PQfnumber (res , "relname" );
1165
- i_attname = PQfnumber (res , "attname" );
1166
- for (rowno = 0 ; rowno < ntups ; rowno ++ )
1167
- {
1168
- found = true;
1169
- if (script == NULL && (script = fopen_priv (output_path , "w" )) == NULL )
1170
- pg_fatal ("could not open file \"%s\": %s\n" ,
1171
- output_path , strerror (errno ));
1172
- if (!db_used )
1173
- {
1174
- fprintf (script , "Database: %s\n" , active_db -> db_name );
1175
- db_used = true;
1176
- }
1177
- fprintf (script , " %s.%s.%s\n" ,
1178
- PQgetvalue (res , rowno , i_nspname ),
1179
- PQgetvalue (res , rowno , i_relname ),
1180
- PQgetvalue (res , rowno , i_attname ));
1181
- }
1182
-
1183
- PQclear (res );
1184
-
1185
- PQfinish (conn );
1186
- }
1187
-
1188
- if (script )
1189
- fclose (script );
1190
-
1191
- if (found )
1137
+ if (check_for_data_type_usage (cluster , "pg_catalog.jsonb" , output_path ))
1192
1138
{
1193
1139
pg_log (PG_REPORT , "fatal\n" );
1194
1140
pg_fatal ("Your installation contains the \"jsonb\" data type in user tables.\n"
0 commit comments