Skip to content

Commit 09878cd

Browse files
committed
Fix pg_upgrade to detect non-upgradable anyarray usages.
When we changed some built-in functions to use anycompatiblearray instead of anyarray, we created a dump/restore hazard for user-defined operators and aggregates relying on those functions: the user objects have to be modified to change their signatures similarly. This causes pg_upgrade to fail partway through if the source installation contains such objects. We generally try to have pg_upgrade detect such hazards and fail before it does anything exciting, so add logic to detect this case too. Back-patch to v14 where the change was made. Justin Pryzby, reviewed by Andrey Borodin Discussion: https://postgr.es/m/3383880.QJadu78ljV@vejsadalnx
1 parent 8d9f963 commit 09878cd

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

src/bin/pg_upgrade/check.c

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ static void check_proper_datallowconn(ClusterInfo *cluster);
2424
static void check_for_prepared_transactions(ClusterInfo *cluster);
2525
static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
2626
static void check_for_user_defined_postfix_ops(ClusterInfo *cluster);
27+
static void check_for_incompatible_polymorphics(ClusterInfo *cluster);
2728
static void check_for_tables_with_oids(ClusterInfo *cluster);
2829
static void check_for_composite_data_type_usage(ClusterInfo *cluster);
2930
static void check_for_reg_data_type_usage(ClusterInfo *cluster);
@@ -122,6 +123,13 @@ check_and_dump_old_cluster(bool live_check)
122123
if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1300)
123124
check_for_user_defined_postfix_ops(&old_cluster);
124125

126+
/*
127+
* PG 14 changed polymorphic functions from anyarray to
128+
* anycompatiblearray.
129+
*/
130+
if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1300)
131+
check_for_incompatible_polymorphics(&old_cluster);
132+
125133
/*
126134
* Pre-PG 12 allowed tables to be declared WITH OIDS, which is not
127135
* supported anymore. Verify there are none, iff applicable.
@@ -999,6 +1007,133 @@ check_for_user_defined_postfix_ops(ClusterInfo *cluster)
9991007
check_ok();
10001008
}
10011009

1010+
/*
1011+
* check_for_incompatible_polymorphics()
1012+
*
1013+
* Make sure nothing is using old polymorphic functions with
1014+
* anyarray/anyelement rather than the new anycompatible variants.
1015+
*/
1016+
static void
1017+
check_for_incompatible_polymorphics(ClusterInfo *cluster)
1018+
{
1019+
PGresult *res;
1020+
FILE *script = NULL;
1021+
char output_path[MAXPGPATH];
1022+
PQExpBufferData old_polymorphics;
1023+
1024+
prep_status("Checking for incompatible polymorphic functions");
1025+
1026+
snprintf(output_path, sizeof(output_path), "%s/%s",
1027+
log_opts.basedir,
1028+
"incompatible_polymorphics.txt");
1029+
1030+
/* The set of problematic functions varies a bit in different versions */
1031+
initPQExpBuffer(&old_polymorphics);
1032+
1033+
appendPQExpBufferStr(&old_polymorphics,
1034+
"'array_append(anyarray,anyelement)'"
1035+
", 'array_cat(anyarray,anyarray)'"
1036+
", 'array_prepend(anyelement,anyarray)'");
1037+
1038+
if (GET_MAJOR_VERSION(cluster->major_version) >= 903)
1039+
appendPQExpBufferStr(&old_polymorphics,
1040+
", 'array_remove(anyarray,anyelement)'"
1041+
", 'array_replace(anyarray,anyelement,anyelement)'");
1042+
1043+
if (GET_MAJOR_VERSION(cluster->major_version) >= 905)
1044+
appendPQExpBufferStr(&old_polymorphics,
1045+
", 'array_position(anyarray,anyelement)'"
1046+
", 'array_position(anyarray,anyelement,integer)'"
1047+
", 'array_positions(anyarray,anyelement)'"
1048+
", 'width_bucket(anyelement,anyarray)'");
1049+
1050+
for (int dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
1051+
{
1052+
bool db_used = false;
1053+
DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
1054+
PGconn *conn = connectToServer(cluster, active_db->db_name);
1055+
int ntups;
1056+
int i_objkind,
1057+
i_objname;
1058+
1059+
/*
1060+
* The query below hardcodes FirstNormalObjectId as 16384 rather than
1061+
* interpolating that C #define into the query because, if that
1062+
* #define is ever changed, the cutoff we want to use is the value
1063+
* used by pre-version 14 servers, not that of some future version.
1064+
*/
1065+
res = executeQueryOrDie(conn,
1066+
/* Aggregate transition functions */
1067+
"SELECT 'aggregate' AS objkind, p.oid::regprocedure::text AS objname "
1068+
"FROM pg_proc AS p "
1069+
"JOIN pg_aggregate AS a ON a.aggfnoid=p.oid "
1070+
"JOIN pg_proc AS transfn ON transfn.oid=a.aggtransfn "
1071+
"WHERE p.oid >= 16384 "
1072+
"AND a.aggtransfn = ANY(ARRAY[%s]::regprocedure[]) "
1073+
1074+
/* Aggregate final functions */
1075+
"UNION ALL "
1076+
"SELECT 'aggregate' AS objkind, p.oid::regprocedure::text AS objname "
1077+
"FROM pg_proc AS p "
1078+
"JOIN pg_aggregate AS a ON a.aggfnoid=p.oid "
1079+
"JOIN pg_proc AS finalfn ON finalfn.oid=a.aggfinalfn "
1080+
"WHERE p.oid >= 16384 "
1081+
"AND a.aggfinalfn = ANY(ARRAY[%s]::regprocedure[]) "
1082+
1083+
/* Operators */
1084+
"UNION ALL "
1085+
"SELECT 'operator' AS objkind, op.oid::regoperator::text AS objname "
1086+
"FROM pg_operator AS op "
1087+
"WHERE op.oid >= 16384 "
1088+
"AND oprcode = ANY(ARRAY[%s]::regprocedure[]);",
1089+
old_polymorphics.data,
1090+
old_polymorphics.data,
1091+
old_polymorphics.data);
1092+
1093+
ntups = PQntuples(res);
1094+
1095+
i_objkind = PQfnumber(res, "objkind");
1096+
i_objname = PQfnumber(res, "objname");
1097+
1098+
for (int rowno = 0; rowno < ntups; rowno++)
1099+
{
1100+
if (script == NULL &&
1101+
(script = fopen_priv(output_path, "w")) == NULL)
1102+
pg_fatal("could not open file \"%s\": %s\n",
1103+
output_path, strerror(errno));
1104+
if (!db_used)
1105+
{
1106+
fprintf(script, "In database: %s\n", active_db->db_name);
1107+
db_used = true;
1108+
}
1109+
1110+
fprintf(script, " %s: %s\n",
1111+
PQgetvalue(res, rowno, i_objkind),
1112+
PQgetvalue(res, rowno, i_objname));
1113+
}
1114+
1115+
PQclear(res);
1116+
PQfinish(conn);
1117+
}
1118+
1119+
if (script)
1120+
{
1121+
fclose(script);
1122+
pg_log(PG_REPORT, "fatal\n");
1123+
pg_fatal("Your installation contains user-defined objects that refer to internal\n"
1124+
"polymorphic functions with arguments of type 'anyarray' or 'anyelement'.\n"
1125+
"These user-defined objects must be dropped before upgrading and restored\n"
1126+
"afterwards, changing them to refer to the new corresponding functions with\n"
1127+
"arguments of type 'anycompatiblearray' and 'anycompatible'.\n"
1128+
"A list of the problematic objects is in the file:\n"
1129+
" %s\n\n", output_path);
1130+
}
1131+
else
1132+
check_ok();
1133+
1134+
termPQExpBuffer(&old_polymorphics);
1135+
}
1136+
10021137
/*
10031138
* Verify that no tables are declared WITH OIDS.
10041139
*/

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy