@@ -28,6 +28,7 @@ static void check_proper_datallowconn(ClusterInfo *cluster);
2828static void check_for_prepared_transactions (ClusterInfo * cluster );
2929static void check_for_isn_and_int8_passing_mismatch (ClusterInfo * cluster );
3030static void check_for_user_defined_postfix_ops (ClusterInfo * cluster );
31+ static void check_for_incompatible_polymorphics (ClusterInfo * cluster );
3132static void check_for_tables_with_oids (ClusterInfo * cluster );
3233static void check_for_composite_data_type_usage (ClusterInfo * cluster );
3334static void check_for_reg_data_type_usage (ClusterInfo * cluster );
@@ -157,6 +158,13 @@ check_and_dump_old_cluster(bool live_check, char **sequence_script_file_name)
157158 check_for_removed_data_type_usage (& old_cluster , "12" , "tinterval" );
158159 }
159160
161+ /*
162+ * PG 14 changed polymorphic functions from anyarray to
163+ * anycompatiblearray.
164+ */
165+ if (GET_MAJOR_VERSION (old_cluster .major_version ) <= 1300 )
166+ check_for_incompatible_polymorphics (& old_cluster );
167+
160168 /*
161169 * Pre-PG 12 allowed tables to be declared WITH OIDS, which is not
162170 * supported anymore. Verify there are none, iff applicable.
@@ -1178,6 +1186,132 @@ check_for_user_defined_postfix_ops(ClusterInfo *cluster)
11781186 check_ok ();
11791187}
11801188
1189+ /*
1190+ * check_for_incompatible_polymorphics()
1191+ *
1192+ * Make sure nothing is using old polymorphic functions with
1193+ * anyarray/anyelement rather than the new anycompatible variants.
1194+ */
1195+ static void
1196+ check_for_incompatible_polymorphics (ClusterInfo * cluster )
1197+ {
1198+ PGresult * res ;
1199+ FILE * script = NULL ;
1200+ char output_path [MAXPGPATH ];
1201+ PQExpBufferData old_polymorphics ;
1202+
1203+ prep_status ("Checking for incompatible polymorphic functions" );
1204+
1205+ snprintf (output_path , sizeof (output_path ),
1206+ "incompatible_polymorphics.txt" );
1207+
1208+ /* The set of problematic functions varies a bit in different versions */
1209+ initPQExpBuffer (& old_polymorphics );
1210+
1211+ appendPQExpBufferStr (& old_polymorphics ,
1212+ "'array_append(anyarray,anyelement)'"
1213+ ", 'array_cat(anyarray,anyarray)'"
1214+ ", 'array_prepend(anyelement,anyarray)'" );
1215+
1216+ if (GET_MAJOR_VERSION (cluster -> major_version ) >= 903 )
1217+ appendPQExpBufferStr (& old_polymorphics ,
1218+ ", 'array_remove(anyarray,anyelement)'"
1219+ ", 'array_replace(anyarray,anyelement,anyelement)'" );
1220+
1221+ if (GET_MAJOR_VERSION (cluster -> major_version ) >= 905 )
1222+ appendPQExpBufferStr (& old_polymorphics ,
1223+ ", 'array_position(anyarray,anyelement)'"
1224+ ", 'array_position(anyarray,anyelement,integer)'"
1225+ ", 'array_positions(anyarray,anyelement)'"
1226+ ", 'width_bucket(anyelement,anyarray)'" );
1227+
1228+ for (int dbnum = 0 ; dbnum < cluster -> dbarr .ndbs ; dbnum ++ )
1229+ {
1230+ bool db_used = false;
1231+ DbInfo * active_db = & cluster -> dbarr .dbs [dbnum ];
1232+ PGconn * conn = connectToServer (cluster , active_db -> db_name );
1233+ int ntups ;
1234+ int i_objkind ,
1235+ i_objname ;
1236+
1237+ /*
1238+ * The query below hardcodes FirstNormalObjectId as 16384 rather than
1239+ * interpolating that C #define into the query because, if that
1240+ * #define is ever changed, the cutoff we want to use is the value
1241+ * used by pre-version 14 servers, not that of some future version.
1242+ */
1243+ res = executeQueryOrDie (conn ,
1244+ /* Aggregate transition functions */
1245+ "SELECT 'aggregate' AS objkind, p.oid::regprocedure::text AS objname "
1246+ "FROM pg_proc AS p "
1247+ "JOIN pg_aggregate AS a ON a.aggfnoid=p.oid "
1248+ "JOIN pg_proc AS transfn ON transfn.oid=a.aggtransfn "
1249+ "WHERE p.oid >= 16384 "
1250+ "AND a.aggtransfn = ANY(ARRAY[%s]::regprocedure[]) "
1251+
1252+ /* Aggregate final functions */
1253+ "UNION ALL "
1254+ "SELECT 'aggregate' AS objkind, p.oid::regprocedure::text AS objname "
1255+ "FROM pg_proc AS p "
1256+ "JOIN pg_aggregate AS a ON a.aggfnoid=p.oid "
1257+ "JOIN pg_proc AS finalfn ON finalfn.oid=a.aggfinalfn "
1258+ "WHERE p.oid >= 16384 "
1259+ "AND a.aggfinalfn = ANY(ARRAY[%s]::regprocedure[]) "
1260+
1261+ /* Operators */
1262+ "UNION ALL "
1263+ "SELECT 'operator' AS objkind, op.oid::regoperator::text AS objname "
1264+ "FROM pg_operator AS op "
1265+ "WHERE op.oid >= 16384 "
1266+ "AND oprcode = ANY(ARRAY[%s]::regprocedure[]);" ,
1267+ old_polymorphics .data ,
1268+ old_polymorphics .data ,
1269+ old_polymorphics .data );
1270+
1271+ ntups = PQntuples (res );
1272+
1273+ i_objkind = PQfnumber (res , "objkind" );
1274+ i_objname = PQfnumber (res , "objname" );
1275+
1276+ for (int rowno = 0 ; rowno < ntups ; rowno ++ )
1277+ {
1278+ if (script == NULL &&
1279+ (script = fopen_priv (output_path , "w" )) == NULL )
1280+ pg_fatal ("could not open file \"%s\": %s\n" ,
1281+ output_path , strerror (errno ));
1282+ if (!db_used )
1283+ {
1284+ fprintf (script , "In database: %s\n" , active_db -> db_name );
1285+ db_used = true;
1286+ }
1287+
1288+ fprintf (script , " %s: %s\n" ,
1289+ PQgetvalue (res , rowno , i_objkind ),
1290+ PQgetvalue (res , rowno , i_objname ));
1291+ }
1292+
1293+ PQclear (res );
1294+ PQfinish (conn );
1295+ }
1296+
1297+ if (script )
1298+ {
1299+ fclose (script );
1300+ pg_log (PG_REPORT , "fatal\n" );
1301+ pg_fatal ("Your installation contains user-defined objects that refer to internal\n"
1302+ "polymorphic functions with arguments of type 'anyarray' or 'anyelement'.\n"
1303+ "These user-defined objects must be dropped before upgrading and restored\n"
1304+ "afterwards, changing them to refer to the new corresponding functions with\n"
1305+ "arguments of type 'anycompatiblearray' and 'anycompatible'.\n"
1306+ "A list of the problematic objects is in the file:\n"
1307+ " %s\n\n" , output_path );
1308+ }
1309+ else
1310+ check_ok ();
1311+
1312+ termPQExpBuffer (& old_polymorphics );
1313+ }
1314+
11811315/*
11821316 * Verify that no tables are declared WITH OIDS.
11831317 */
0 commit comments