mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-03-01 19:45:33 +08:00
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
This commit is contained in:
parent
8d9f9634ef
commit
09878cdd48
@ -24,6 +24,7 @@ static void check_proper_datallowconn(ClusterInfo *cluster);
|
||||
static void check_for_prepared_transactions(ClusterInfo *cluster);
|
||||
static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
|
||||
static void check_for_user_defined_postfix_ops(ClusterInfo *cluster);
|
||||
static void check_for_incompatible_polymorphics(ClusterInfo *cluster);
|
||||
static void check_for_tables_with_oids(ClusterInfo *cluster);
|
||||
static void check_for_composite_data_type_usage(ClusterInfo *cluster);
|
||||
static void check_for_reg_data_type_usage(ClusterInfo *cluster);
|
||||
@ -122,6 +123,13 @@ check_and_dump_old_cluster(bool live_check)
|
||||
if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1300)
|
||||
check_for_user_defined_postfix_ops(&old_cluster);
|
||||
|
||||
/*
|
||||
* PG 14 changed polymorphic functions from anyarray to
|
||||
* anycompatiblearray.
|
||||
*/
|
||||
if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1300)
|
||||
check_for_incompatible_polymorphics(&old_cluster);
|
||||
|
||||
/*
|
||||
* Pre-PG 12 allowed tables to be declared WITH OIDS, which is not
|
||||
* supported anymore. Verify there are none, iff applicable.
|
||||
@ -999,6 +1007,133 @@ check_for_user_defined_postfix_ops(ClusterInfo *cluster)
|
||||
check_ok();
|
||||
}
|
||||
|
||||
/*
|
||||
* check_for_incompatible_polymorphics()
|
||||
*
|
||||
* Make sure nothing is using old polymorphic functions with
|
||||
* anyarray/anyelement rather than the new anycompatible variants.
|
||||
*/
|
||||
static void
|
||||
check_for_incompatible_polymorphics(ClusterInfo *cluster)
|
||||
{
|
||||
PGresult *res;
|
||||
FILE *script = NULL;
|
||||
char output_path[MAXPGPATH];
|
||||
PQExpBufferData old_polymorphics;
|
||||
|
||||
prep_status("Checking for incompatible polymorphic functions");
|
||||
|
||||
snprintf(output_path, sizeof(output_path), "%s/%s",
|
||||
log_opts.basedir,
|
||||
"incompatible_polymorphics.txt");
|
||||
|
||||
/* The set of problematic functions varies a bit in different versions */
|
||||
initPQExpBuffer(&old_polymorphics);
|
||||
|
||||
appendPQExpBufferStr(&old_polymorphics,
|
||||
"'array_append(anyarray,anyelement)'"
|
||||
", 'array_cat(anyarray,anyarray)'"
|
||||
", 'array_prepend(anyelement,anyarray)'");
|
||||
|
||||
if (GET_MAJOR_VERSION(cluster->major_version) >= 903)
|
||||
appendPQExpBufferStr(&old_polymorphics,
|
||||
", 'array_remove(anyarray,anyelement)'"
|
||||
", 'array_replace(anyarray,anyelement,anyelement)'");
|
||||
|
||||
if (GET_MAJOR_VERSION(cluster->major_version) >= 905)
|
||||
appendPQExpBufferStr(&old_polymorphics,
|
||||
", 'array_position(anyarray,anyelement)'"
|
||||
", 'array_position(anyarray,anyelement,integer)'"
|
||||
", 'array_positions(anyarray,anyelement)'"
|
||||
", 'width_bucket(anyelement,anyarray)'");
|
||||
|
||||
for (int dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
|
||||
{
|
||||
bool db_used = false;
|
||||
DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
|
||||
PGconn *conn = connectToServer(cluster, active_db->db_name);
|
||||
int ntups;
|
||||
int i_objkind,
|
||||
i_objname;
|
||||
|
||||
/*
|
||||
* The query below hardcodes FirstNormalObjectId as 16384 rather than
|
||||
* interpolating that C #define into the query because, if that
|
||||
* #define is ever changed, the cutoff we want to use is the value
|
||||
* used by pre-version 14 servers, not that of some future version.
|
||||
*/
|
||||
res = executeQueryOrDie(conn,
|
||||
/* Aggregate transition functions */
|
||||
"SELECT 'aggregate' AS objkind, p.oid::regprocedure::text AS objname "
|
||||
"FROM pg_proc AS p "
|
||||
"JOIN pg_aggregate AS a ON a.aggfnoid=p.oid "
|
||||
"JOIN pg_proc AS transfn ON transfn.oid=a.aggtransfn "
|
||||
"WHERE p.oid >= 16384 "
|
||||
"AND a.aggtransfn = ANY(ARRAY[%s]::regprocedure[]) "
|
||||
|
||||
/* Aggregate final functions */
|
||||
"UNION ALL "
|
||||
"SELECT 'aggregate' AS objkind, p.oid::regprocedure::text AS objname "
|
||||
"FROM pg_proc AS p "
|
||||
"JOIN pg_aggregate AS a ON a.aggfnoid=p.oid "
|
||||
"JOIN pg_proc AS finalfn ON finalfn.oid=a.aggfinalfn "
|
||||
"WHERE p.oid >= 16384 "
|
||||
"AND a.aggfinalfn = ANY(ARRAY[%s]::regprocedure[]) "
|
||||
|
||||
/* Operators */
|
||||
"UNION ALL "
|
||||
"SELECT 'operator' AS objkind, op.oid::regoperator::text AS objname "
|
||||
"FROM pg_operator AS op "
|
||||
"WHERE op.oid >= 16384 "
|
||||
"AND oprcode = ANY(ARRAY[%s]::regprocedure[]);",
|
||||
old_polymorphics.data,
|
||||
old_polymorphics.data,
|
||||
old_polymorphics.data);
|
||||
|
||||
ntups = PQntuples(res);
|
||||
|
||||
i_objkind = PQfnumber(res, "objkind");
|
||||
i_objname = PQfnumber(res, "objname");
|
||||
|
||||
for (int rowno = 0; rowno < ntups; rowno++)
|
||||
{
|
||||
if (script == NULL &&
|
||||
(script = fopen_priv(output_path, "w")) == NULL)
|
||||
pg_fatal("could not open file \"%s\": %s\n",
|
||||
output_path, strerror(errno));
|
||||
if (!db_used)
|
||||
{
|
||||
fprintf(script, "In database: %s\n", active_db->db_name);
|
||||
db_used = true;
|
||||
}
|
||||
|
||||
fprintf(script, " %s: %s\n",
|
||||
PQgetvalue(res, rowno, i_objkind),
|
||||
PQgetvalue(res, rowno, i_objname));
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
PQfinish(conn);
|
||||
}
|
||||
|
||||
if (script)
|
||||
{
|
||||
fclose(script);
|
||||
pg_log(PG_REPORT, "fatal\n");
|
||||
pg_fatal("Your installation contains user-defined objects that refer to internal\n"
|
||||
"polymorphic functions with arguments of type 'anyarray' or 'anyelement'.\n"
|
||||
"These user-defined objects must be dropped before upgrading and restored\n"
|
||||
"afterwards, changing them to refer to the new corresponding functions with\n"
|
||||
"arguments of type 'anycompatiblearray' and 'anycompatible'.\n"
|
||||
"A list of the problematic objects is in the file:\n"
|
||||
" %s\n\n", output_path);
|
||||
}
|
||||
else
|
||||
check_ok();
|
||||
|
||||
termPQExpBuffer(&old_polymorphics);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that no tables are declared WITH OIDS.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user