@@ -23,6 +23,7 @@ static void check_proper_datallowconn(ClusterInfo *cluster);
23
23
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_tables_with_oids (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
@@ -1000,6 +1002,63 @@ check_for_tables_with_oids(ClusterInfo *cluster)
1000
1002
}
1001
1003
1002
1004
1005
+ /*
1006
+ * check_for_composite_data_type_usage()
1007
+ * Check for system-defined composite types used in user tables.
1008
+ *
1009
+ * The OIDs of rowtypes of system catalogs and information_schema views
1010
+ * can change across major versions; unlike user-defined types, we have
1011
+ * no mechanism for forcing them to be the same in the new cluster.
1012
+ * Hence, if any user table uses one, that's problematic for pg_upgrade.
1013
+ */
1014
+ static void
1015
+ check_for_composite_data_type_usage (ClusterInfo * cluster )
1016
+ {
1017
+ bool found ;
1018
+ Oid firstUserOid ;
1019
+ char output_path [MAXPGPATH ];
1020
+ char * base_query ;
1021
+
1022
+ prep_status ("Checking for system-defined composite types in user tables" );
1023
+
1024
+ snprintf (output_path , sizeof (output_path ), "tables_using_composite.txt" );
1025
+
1026
+ /*
1027
+ * Look for composite types that were made during initdb *or* belong to
1028
+ * information_schema; that's important in case information_schema was
1029
+ * dropped and reloaded.
1030
+ *
1031
+ * The cutoff OID here should match the source cluster's value of
1032
+ * FirstNormalObjectId. We hardcode it rather than using that C #define
1033
+ * because, if that #define is ever changed, our own version's value is
1034
+ * NOT what to use. Eventually we may need a test on the source cluster's
1035
+ * version to select the correct value.
1036
+ */
1037
+ firstUserOid = 16384 ;
1038
+
1039
+ base_query = psprintf ("SELECT t.oid FROM pg_catalog.pg_type t "
1040
+ "LEFT JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid "
1041
+ " WHERE typtype = 'c' AND (t.oid < %u OR nspname = 'information_schema')" ,
1042
+ firstUserOid );
1043
+
1044
+ found = check_for_data_types_usage (cluster , base_query , output_path );
1045
+
1046
+ free (base_query );
1047
+
1048
+ if (found )
1049
+ {
1050
+ pg_log (PG_REPORT , "fatal\n" );
1051
+ pg_fatal ("Your installation contains system-defined composite type(s) in user tables.\n"
1052
+ "These type OIDs are not stable across PostgreSQL versions,\n"
1053
+ "so this cluster cannot currently be upgraded. You can\n"
1054
+ "drop the problem columns and restart the upgrade.\n"
1055
+ "A list of the problem columns is in the file:\n"
1056
+ " %s\n\n" , output_path );
1057
+ }
1058
+ else
1059
+ check_ok ();
1060
+ }
1061
+
1003
1062
/*
1004
1063
* check_for_reg_data_type_usage()
1005
1064
* pg_upgrade only preserves these system values:
@@ -1014,88 +1073,36 @@ check_for_tables_with_oids(ClusterInfo *cluster)
1014
1073
static void
1015
1074
check_for_reg_data_type_usage (ClusterInfo * cluster )
1016
1075
{
1017
- int dbnum ;
1018
- FILE * script = NULL ;
1019
- bool found = false;
1076
+ bool found ;
1020
1077
char output_path [MAXPGPATH ];
1021
1078
1022
1079
prep_status ("Checking for reg* data types in user tables" );
1023
1080
1024
1081
snprintf (output_path , sizeof (output_path ), "tables_using_reg.txt" );
1025
1082
1026
- for (dbnum = 0 ; dbnum < cluster -> dbarr .ndbs ; dbnum ++ )
1027
- {
1028
- PGresult * res ;
1029
- bool db_used = false;
1030
- int ntups ;
1031
- int rowno ;
1032
- int i_nspname ,
1033
- i_relname ,
1034
- i_attname ;
1035
- DbInfo * active_db = & cluster -> dbarr .dbs [dbnum ];
1036
- PGconn * conn = connectToServer (cluster , active_db -> db_name );
1037
-
1038
- /*
1039
- * While several relkinds don't store any data, e.g. views, they can
1040
- * be used to define data types of other columns, so we check all
1041
- * relkinds.
1042
- */
1043
- res = executeQueryOrDie (conn ,
1044
- "SELECT n.nspname, c.relname, a.attname "
1045
- "FROM pg_catalog.pg_class c, "
1046
- " pg_catalog.pg_namespace n, "
1047
- " pg_catalog.pg_attribute a, "
1048
- " pg_catalog.pg_type t "
1049
- "WHERE c.oid = a.attrelid AND "
1050
- " NOT a.attisdropped AND "
1051
- " a.atttypid = t.oid AND "
1052
- " t.typnamespace = "
1053
- " (SELECT oid FROM pg_namespace "
1054
- " WHERE nspname = 'pg_catalog') AND"
1055
- " t.typname IN ( "
1056
- /* regclass.oid is preserved, so 'regclass' is OK */
1057
- " 'regcollation', "
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 , "In 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 );
1083
+ /*
1084
+ * Note: older servers will not have all of these reg* types, so we have
1085
+ * to write the query like this rather than depending on casts to regtype.
1086
+ */
1087
+ found = check_for_data_types_usage (cluster ,
1088
+ "SELECT oid FROM pg_catalog.pg_type t "
1089
+ "WHERE t.typnamespace = "
1090
+ " (SELECT oid FROM pg_catalog.pg_namespace "
1091
+ " WHERE nspname = 'pg_catalog') "
1092
+ " AND t.typname IN ( "
1093
+ /* pg_class.oid is preserved, so 'regclass' is OK */
1094
+ " 'regcollation', "
1095
+ " 'regconfig', "
1096
+ " 'regdictionary', "
1097
+ " 'regnamespace', "
1098
+ " 'regoper', "
1099
+ " 'regoperator', "
1100
+ " 'regproc', "
1101
+ " 'regprocedure' "
1102
+ /* pg_authid.oid is preserved, so 'regrole' is OK */
1103
+ /* pg_type.oid is (mostly) preserved, so 'regtype' is OK */
1104
+ " )" ,
1105
+ output_path );
1099
1106
1100
1107
if (found )
1101
1108
{
@@ -1120,75 +1127,13 @@ check_for_reg_data_type_usage(ClusterInfo *cluster)
1120
1127
static void
1121
1128
check_for_jsonb_9_4_usage (ClusterInfo * cluster )
1122
1129
{
1123
- int dbnum ;
1124
- FILE * script = NULL ;
1125
- bool found = false;
1126
1130
char output_path [MAXPGPATH ];
1127
1131
1128
1132
prep_status ("Checking for incompatible \"jsonb\" data type" );
1129
1133
1130
1134
snprintf (output_path , sizeof (output_path ), "tables_using_jsonb.txt" );
1131
1135
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 , "In 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 )
1136
+ if (check_for_data_type_usage (cluster , "pg_catalog.jsonb" , output_path ))
1192
1137
{
1193
1138
pg_log (PG_REPORT , "fatal\n" );
1194
1139
pg_fatal ("Your installation contains the \"jsonb\" data type in user tables.\n"
0 commit comments