@@ -24,6 +24,7 @@ static void check_for_prepared_transactions(ClusterInfo *cluster);
24
24
static void check_for_isn_and_int8_passing_mismatch (ClusterInfo * cluster );
25
25
static void check_for_user_defined_postfix_ops (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 );
@@ -100,6 +101,7 @@ check_and_dump_old_cluster(bool live_check)
100
101
check_is_install_user (& old_cluster );
101
102
check_proper_datallowconn (& old_cluster );
102
103
check_for_prepared_transactions (& old_cluster );
104
+ check_for_composite_data_type_usage (& old_cluster );
103
105
check_for_reg_data_type_usage (& old_cluster );
104
106
check_for_isn_and_int8_passing_mismatch (& old_cluster );
105
107
@@ -1043,6 +1045,63 @@ check_for_tables_with_oids(ClusterInfo *cluster)
1043
1045
}
1044
1046
1045
1047
1048
+ /*
1049
+ * check_for_composite_data_type_usage()
1050
+ * Check for system-defined composite types used in user tables.
1051
+ *
1052
+ * The OIDs of rowtypes of system catalogs and information_schema views
1053
+ * can change across major versions; unlike user-defined types, we have
1054
+ * no mechanism for forcing them to be the same in the new cluster.
1055
+ * Hence, if any user table uses one, that's problematic for pg_upgrade.
1056
+ */
1057
+ static void
1058
+ check_for_composite_data_type_usage (ClusterInfo * cluster )
1059
+ {
1060
+ bool found ;
1061
+ Oid firstUserOid ;
1062
+ char output_path [MAXPGPATH ];
1063
+ char * base_query ;
1064
+
1065
+ prep_status ("Checking for system-defined composite types in user tables" );
1066
+
1067
+ snprintf (output_path , sizeof (output_path ), "tables_using_composite.txt" );
1068
+
1069
+ /*
1070
+ * Look for composite types that were made during initdb *or* belong to
1071
+ * information_schema; that's important in case information_schema was
1072
+ * dropped and reloaded.
1073
+ *
1074
+ * The cutoff OID here should match the source cluster's value of
1075
+ * FirstNormalObjectId. We hardcode it rather than using that C #define
1076
+ * because, if that #define is ever changed, our own version's value is
1077
+ * NOT what to use. Eventually we may need a test on the source cluster's
1078
+ * version to select the correct value.
1079
+ */
1080
+ firstUserOid = 16384 ;
1081
+
1082
+ base_query = psprintf ("SELECT t.oid FROM pg_catalog.pg_type t "
1083
+ "LEFT JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid "
1084
+ " WHERE typtype = 'c' AND (t.oid < %u OR nspname = 'information_schema')" ,
1085
+ firstUserOid );
1086
+
1087
+ found = check_for_data_types_usage (cluster , base_query , output_path );
1088
+
1089
+ free (base_query );
1090
+
1091
+ if (found )
1092
+ {
1093
+ pg_log (PG_REPORT , "fatal\n" );
1094
+ pg_fatal ("Your installation contains system-defined composite type(s) in user tables.\n"
1095
+ "These type OIDs are not stable across PostgreSQL versions,\n"
1096
+ "so this cluster cannot currently be upgraded. You can\n"
1097
+ "drop the problem columns and restart the upgrade.\n"
1098
+ "A list of the problem columns is in the file:\n"
1099
+ " %s\n\n" , output_path );
1100
+ }
1101
+ else
1102
+ check_ok ();
1103
+ }
1104
+
1046
1105
/*
1047
1106
* check_for_reg_data_type_usage()
1048
1107
* pg_upgrade only preserves these system values:
@@ -1057,88 +1116,36 @@ check_for_tables_with_oids(ClusterInfo *cluster)
1057
1116
static void
1058
1117
check_for_reg_data_type_usage (ClusterInfo * cluster )
1059
1118
{
1060
- int dbnum ;
1061
- FILE * script = NULL ;
1062
- bool found = false;
1119
+ bool found ;
1063
1120
char output_path [MAXPGPATH ];
1064
1121
1065
1122
prep_status ("Checking for reg* data types in user tables" );
1066
1123
1067
1124
snprintf (output_path , sizeof (output_path ), "tables_using_reg.txt" );
1068
1125
1069
- for (dbnum = 0 ; dbnum < cluster -> dbarr .ndbs ; dbnum ++ )
1070
- {
1071
- PGresult * res ;
1072
- bool db_used = false;
1073
- int ntups ;
1074
- int rowno ;
1075
- int i_nspname ,
1076
- i_relname ,
1077
- i_attname ;
1078
- DbInfo * active_db = & cluster -> dbarr .dbs [dbnum ];
1079
- PGconn * conn = connectToServer (cluster , active_db -> db_name );
1080
-
1081
- /*
1082
- * While several relkinds don't store any data, e.g. views, they can
1083
- * be used to define data types of other columns, so we check all
1084
- * relkinds.
1085
- */
1086
- res = executeQueryOrDie (conn ,
1087
- "SELECT n.nspname, c.relname, a.attname "
1088
- "FROM pg_catalog.pg_class c, "
1089
- " pg_catalog.pg_namespace n, "
1090
- " pg_catalog.pg_attribute a, "
1091
- " pg_catalog.pg_type t "
1092
- "WHERE c.oid = a.attrelid AND "
1093
- " NOT a.attisdropped AND "
1094
- " a.atttypid = t.oid AND "
1095
- " t.typnamespace = "
1096
- " (SELECT oid FROM pg_namespace "
1097
- " WHERE nspname = 'pg_catalog') AND"
1098
- " t.typname IN ( "
1099
- /* regclass.oid is preserved, so 'regclass' is OK */
1100
- " 'regcollation', "
1101
- " 'regconfig', "
1102
- " 'regdictionary', "
1103
- " 'regnamespace', "
1104
- " 'regoper', "
1105
- " 'regoperator', "
1106
- " 'regproc', "
1107
- " 'regprocedure' "
1108
- /* regrole.oid is preserved, so 'regrole' is OK */
1109
- /* regtype.oid is preserved, so 'regtype' is OK */
1110
- " ) AND "
1111
- " c.relnamespace = n.oid AND "
1112
- " n.nspname NOT IN ('pg_catalog', 'information_schema')" );
1113
-
1114
- ntups = PQntuples (res );
1115
- i_nspname = PQfnumber (res , "nspname" );
1116
- i_relname = PQfnumber (res , "relname" );
1117
- i_attname = PQfnumber (res , "attname" );
1118
- for (rowno = 0 ; rowno < ntups ; rowno ++ )
1119
- {
1120
- found = true;
1121
- if (script == NULL && (script = fopen_priv (output_path , "w" )) == NULL )
1122
- pg_fatal ("could not open file \"%s\": %s\n" ,
1123
- output_path , strerror (errno ));
1124
- if (!db_used )
1125
- {
1126
- fprintf (script , "In database: %s\n" , active_db -> db_name );
1127
- db_used = true;
1128
- }
1129
- fprintf (script , " %s.%s.%s\n" ,
1130
- PQgetvalue (res , rowno , i_nspname ),
1131
- PQgetvalue (res , rowno , i_relname ),
1132
- PQgetvalue (res , rowno , i_attname ));
1133
- }
1134
-
1135
- PQclear (res );
1136
-
1137
- PQfinish (conn );
1138
- }
1139
-
1140
- if (script )
1141
- fclose (script );
1126
+ /*
1127
+ * Note: older servers will not have all of these reg* types, so we have
1128
+ * to write the query like this rather than depending on casts to regtype.
1129
+ */
1130
+ found = check_for_data_types_usage (cluster ,
1131
+ "SELECT oid FROM pg_catalog.pg_type t "
1132
+ "WHERE t.typnamespace = "
1133
+ " (SELECT oid FROM pg_catalog.pg_namespace "
1134
+ " WHERE nspname = 'pg_catalog') "
1135
+ " AND t.typname IN ( "
1136
+ /* pg_class.oid is preserved, so 'regclass' is OK */
1137
+ " 'regcollation', "
1138
+ " 'regconfig', "
1139
+ " 'regdictionary', "
1140
+ " 'regnamespace', "
1141
+ " 'regoper', "
1142
+ " 'regoperator', "
1143
+ " 'regproc', "
1144
+ " 'regprocedure' "
1145
+ /* pg_authid.oid is preserved, so 'regrole' is OK */
1146
+ /* pg_type.oid is (mostly) preserved, so 'regtype' is OK */
1147
+ " )" ,
1148
+ output_path );
1142
1149
1143
1150
if (found )
1144
1151
{
@@ -1163,75 +1170,13 @@ check_for_reg_data_type_usage(ClusterInfo *cluster)
1163
1170
static void
1164
1171
check_for_jsonb_9_4_usage (ClusterInfo * cluster )
1165
1172
{
1166
- int dbnum ;
1167
- FILE * script = NULL ;
1168
- bool found = false;
1169
1173
char output_path [MAXPGPATH ];
1170
1174
1171
1175
prep_status ("Checking for incompatible \"jsonb\" data type" );
1172
1176
1173
1177
snprintf (output_path , sizeof (output_path ), "tables_using_jsonb.txt" );
1174
1178
1175
- for (dbnum = 0 ; dbnum < cluster -> dbarr .ndbs ; dbnum ++ )
1176
- {
1177
- PGresult * res ;
1178
- bool db_used = false;
1179
- int ntups ;
1180
- int rowno ;
1181
- int i_nspname ,
1182
- i_relname ,
1183
- i_attname ;
1184
- DbInfo * active_db = & cluster -> dbarr .dbs [dbnum ];
1185
- PGconn * conn = connectToServer (cluster , active_db -> db_name );
1186
-
1187
- /*
1188
- * While several relkinds don't store any data, e.g. views, they can
1189
- * be used to define data types of other columns, so we check all
1190
- * relkinds.
1191
- */
1192
- res = executeQueryOrDie (conn ,
1193
- "SELECT n.nspname, c.relname, a.attname "
1194
- "FROM pg_catalog.pg_class c, "
1195
- " pg_catalog.pg_namespace n, "
1196
- " pg_catalog.pg_attribute a "
1197
- "WHERE c.oid = a.attrelid AND "
1198
- " NOT a.attisdropped AND "
1199
- " a.atttypid = 'pg_catalog.jsonb'::pg_catalog.regtype AND "
1200
- " c.relnamespace = n.oid AND "
1201
- /* exclude possible orphaned temp tables */
1202
- " n.nspname !~ '^pg_temp_' AND "
1203
- " n.nspname NOT IN ('pg_catalog', 'information_schema')" );
1204
-
1205
- ntups = PQntuples (res );
1206
- i_nspname = PQfnumber (res , "nspname" );
1207
- i_relname = PQfnumber (res , "relname" );
1208
- i_attname = PQfnumber (res , "attname" );
1209
- for (rowno = 0 ; rowno < ntups ; rowno ++ )
1210
- {
1211
- found = true;
1212
- if (script == NULL && (script = fopen_priv (output_path , "w" )) == NULL )
1213
- pg_fatal ("could not open file \"%s\": %s\n" ,
1214
- output_path , strerror (errno ));
1215
- if (!db_used )
1216
- {
1217
- fprintf (script , "In database: %s\n" , active_db -> db_name );
1218
- db_used = true;
1219
- }
1220
- fprintf (script , " %s.%s.%s\n" ,
1221
- PQgetvalue (res , rowno , i_nspname ),
1222
- PQgetvalue (res , rowno , i_relname ),
1223
- PQgetvalue (res , rowno , i_attname ));
1224
- }
1225
-
1226
- PQclear (res );
1227
-
1228
- PQfinish (conn );
1229
- }
1230
-
1231
- if (script )
1232
- fclose (script );
1233
-
1234
- if (found )
1179
+ if (check_for_data_type_usage (cluster , "pg_catalog.jsonb" , output_path ))
1235
1180
{
1236
1181
pg_log (PG_REPORT , "fatal\n" );
1237
1182
pg_fatal ("Your installation contains the \"jsonb\" data type in user tables.\n"
0 commit comments