@@ -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_user_defined_postfix_ops (ClusterInfo * cluster );
26
+ static void check_for_incompatible_polymorphics (ClusterInfo * cluster );
26
27
static void check_for_tables_with_oids (ClusterInfo * cluster );
27
28
static void check_for_composite_data_type_usage (ClusterInfo * cluster );
28
29
static void check_for_reg_data_type_usage (ClusterInfo * cluster );
@@ -121,6 +122,13 @@ check_and_dump_old_cluster(bool live_check)
121
122
if (GET_MAJOR_VERSION (old_cluster .major_version ) <= 1300 )
122
123
check_for_user_defined_postfix_ops (& old_cluster );
123
124
125
+ /*
126
+ * PG 14 changed polymorphic functions from anyarray to
127
+ * anycompatiblearray.
128
+ */
129
+ if (GET_MAJOR_VERSION (old_cluster .major_version ) <= 1300 )
130
+ check_for_incompatible_polymorphics (& old_cluster );
131
+
124
132
/*
125
133
* Pre-PG 12 allowed tables to be declared WITH OIDS, which is not
126
134
* supported anymore. Verify there are none, iff applicable.
@@ -970,6 +978,132 @@ check_for_user_defined_postfix_ops(ClusterInfo *cluster)
970
978
check_ok ();
971
979
}
972
980
981
+ /*
982
+ * check_for_incompatible_polymorphics()
983
+ *
984
+ * Make sure nothing is using old polymorphic functions with
985
+ * anyarray/anyelement rather than the new anycompatible variants.
986
+ */
987
+ static void
988
+ check_for_incompatible_polymorphics (ClusterInfo * cluster )
989
+ {
990
+ PGresult * res ;
991
+ FILE * script = NULL ;
992
+ char output_path [MAXPGPATH ];
993
+ PQExpBufferData old_polymorphics ;
994
+
995
+ prep_status ("Checking for incompatible polymorphic functions" );
996
+
997
+ snprintf (output_path , sizeof (output_path ),
998
+ "incompatible_polymorphics.txt" );
999
+
1000
+ /* The set of problematic functions varies a bit in different versions */
1001
+ initPQExpBuffer (& old_polymorphics );
1002
+
1003
+ appendPQExpBufferStr (& old_polymorphics ,
1004
+ "'array_append(anyarray,anyelement)'"
1005
+ ", 'array_cat(anyarray,anyarray)'"
1006
+ ", 'array_prepend(anyelement,anyarray)'" );
1007
+
1008
+ if (GET_MAJOR_VERSION (cluster -> major_version ) >= 903 )
1009
+ appendPQExpBufferStr (& old_polymorphics ,
1010
+ ", 'array_remove(anyarray,anyelement)'"
1011
+ ", 'array_replace(anyarray,anyelement,anyelement)'" );
1012
+
1013
+ if (GET_MAJOR_VERSION (cluster -> major_version ) >= 905 )
1014
+ appendPQExpBufferStr (& old_polymorphics ,
1015
+ ", 'array_position(anyarray,anyelement)'"
1016
+ ", 'array_position(anyarray,anyelement,integer)'"
1017
+ ", 'array_positions(anyarray,anyelement)'"
1018
+ ", 'width_bucket(anyelement,anyarray)'" );
1019
+
1020
+ for (int dbnum = 0 ; dbnum < cluster -> dbarr .ndbs ; dbnum ++ )
1021
+ {
1022
+ bool db_used = false;
1023
+ DbInfo * active_db = & cluster -> dbarr .dbs [dbnum ];
1024
+ PGconn * conn = connectToServer (cluster , active_db -> db_name );
1025
+ int ntups ;
1026
+ int i_objkind ,
1027
+ i_objname ;
1028
+
1029
+ /*
1030
+ * The query below hardcodes FirstNormalObjectId as 16384 rather than
1031
+ * interpolating that C #define into the query because, if that
1032
+ * #define is ever changed, the cutoff we want to use is the value
1033
+ * used by pre-version 14 servers, not that of some future version.
1034
+ */
1035
+ res = executeQueryOrDie (conn ,
1036
+ /* Aggregate transition functions */
1037
+ "SELECT 'aggregate' AS objkind, p.oid::regprocedure::text AS objname "
1038
+ "FROM pg_proc AS p "
1039
+ "JOIN pg_aggregate AS a ON a.aggfnoid=p.oid "
1040
+ "JOIN pg_proc AS transfn ON transfn.oid=a.aggtransfn "
1041
+ "WHERE p.oid >= 16384 "
1042
+ "AND a.aggtransfn = ANY(ARRAY[%s]::regprocedure[]) "
1043
+
1044
+ /* Aggregate final functions */
1045
+ "UNION ALL "
1046
+ "SELECT 'aggregate' AS objkind, p.oid::regprocedure::text AS objname "
1047
+ "FROM pg_proc AS p "
1048
+ "JOIN pg_aggregate AS a ON a.aggfnoid=p.oid "
1049
+ "JOIN pg_proc AS finalfn ON finalfn.oid=a.aggfinalfn "
1050
+ "WHERE p.oid >= 16384 "
1051
+ "AND a.aggfinalfn = ANY(ARRAY[%s]::regprocedure[]) "
1052
+
1053
+ /* Operators */
1054
+ "UNION ALL "
1055
+ "SELECT 'operator' AS objkind, op.oid::regoperator::text AS objname "
1056
+ "FROM pg_operator AS op "
1057
+ "WHERE op.oid >= 16384 "
1058
+ "AND oprcode = ANY(ARRAY[%s]::regprocedure[]);" ,
1059
+ old_polymorphics .data ,
1060
+ old_polymorphics .data ,
1061
+ old_polymorphics .data );
1062
+
1063
+ ntups = PQntuples (res );
1064
+
1065
+ i_objkind = PQfnumber (res , "objkind" );
1066
+ i_objname = PQfnumber (res , "objname" );
1067
+
1068
+ for (int rowno = 0 ; rowno < ntups ; rowno ++ )
1069
+ {
1070
+ if (script == NULL &&
1071
+ (script = fopen_priv (output_path , "w" )) == NULL )
1072
+ pg_fatal ("could not open file \"%s\": %s\n" ,
1073
+ output_path , strerror (errno ));
1074
+ if (!db_used )
1075
+ {
1076
+ fprintf (script , "In database: %s\n" , active_db -> db_name );
1077
+ db_used = true;
1078
+ }
1079
+
1080
+ fprintf (script , " %s: %s\n" ,
1081
+ PQgetvalue (res , rowno , i_objkind ),
1082
+ PQgetvalue (res , rowno , i_objname ));
1083
+ }
1084
+
1085
+ PQclear (res );
1086
+ PQfinish (conn );
1087
+ }
1088
+
1089
+ if (script )
1090
+ {
1091
+ fclose (script );
1092
+ pg_log (PG_REPORT , "fatal\n" );
1093
+ pg_fatal ("Your installation contains user-defined objects that refer to internal\n"
1094
+ "polymorphic functions with arguments of type 'anyarray' or 'anyelement'.\n"
1095
+ "These user-defined objects must be dropped before upgrading and restored\n"
1096
+ "afterwards, changing them to refer to the new corresponding functions with\n"
1097
+ "arguments of type 'anycompatiblearray' and 'anycompatible'.\n"
1098
+ "A list of the problematic objects is in the file:\n"
1099
+ " %s\n\n" , output_path );
1100
+ }
1101
+ else
1102
+ check_ok ();
1103
+
1104
+ termPQExpBuffer (& old_polymorphics );
1105
+ }
1106
+
973
1107
/*
974
1108
* Verify that no tables are declared WITH OIDS.
975
1109
*/
0 commit comments