From 4cf31775464638f8621b32d411456f8cbf6cc9a3 Mon Sep 17 00:00:00 2001 From: Daniel Gustafsson Date: Tue, 24 Jul 2018 09:23:42 +0200 Subject: [PATCH] Report which databases contain the missing libraries When a loadable library isn't found in the new cluster during an upgdade, report all databases in the old cluster which contains the library in question. --- src/bin/pg_upgrade/function.c | 72 ++++++++++++++++++++--------------------- src/bin/pg_upgrade/pg_upgrade.h | 7 +++- 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/src/bin/pg_upgrade/function.c b/src/bin/pg_upgrade/function.c index 03fd155dcd..c8592cb08f 100644 --- a/src/bin/pg_upgrade/function.c +++ b/src/bin/pg_upgrade/function.c @@ -28,8 +28,8 @@ static int library_name_compare(const void *p1, const void *p2) { - const char *str1 = *(const char *const *) p1; - const char *str2 = *(const char *const *) p2; + const char *str1 = ((const LibraryInfo *) p1)->name; + const char *str2 = ((const LibraryInfo *) p2)->name; int slen1 = strlen(str1); int slen2 = strlen(str2); @@ -137,18 +137,7 @@ get_loadable_libraries(void) if (found_public_plpython_handler) pg_fatal("Remove the problem functions from the old cluster to continue.\n"); - /* - * Now we want to remove duplicates across DBs and sort the library names - * into order. This avoids multiple probes of the same library, and - * ensures that libraries are probed in a consistent order, which is - * important for reproducible behavior if one library depends on another. - * - * First transfer all the names into one array, then sort, then remove - * duplicates. Note: we strdup each name in the first loop so that we can - * safely clear the PGresults in the same loop. This is a bit wasteful - * but it's unlikely there are enough names to matter. - */ - os_info.libraries = (char **) pg_malloc(totaltups * sizeof(char *)); + os_info.libraries = (LibraryInfo *) pg_malloc(totaltups * sizeof(LibraryInfo)); totaltups = 0; for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++) @@ -162,36 +151,19 @@ get_loadable_libraries(void) { char *lib = PQgetvalue(res, rowno, 0); - os_info.libraries[totaltups++] = pg_strdup(lib); + os_info.libraries[totaltups].name = pg_strdup(lib); + os_info.libraries[totaltups].db = dbnum; + + totaltups++; } PQclear(res); } pg_free(ress); - if (totaltups > 1) - { - int i, - lastnondup; - - qsort((void *) os_info.libraries, totaltups, sizeof(char *), - library_name_compare); - - for (i = 1, lastnondup = 0; i < totaltups; i++) - { - if (strcmp(os_info.libraries[i], - os_info.libraries[lastnondup]) != 0) - os_info.libraries[++lastnondup] = os_info.libraries[i]; - else - pg_free(os_info.libraries[i]); - } - totaltups = lastnondup + 1; - } - os_info.num_libraries = totaltups; } - /* * check_loadable_libraries() * @@ -204,6 +176,7 @@ check_loadable_libraries(void) { PGconn *conn = connectToServer(&new_cluster, "template1"); int libnum; + int lastfail; FILE *script = NULL; bool found = false; char output_path[MAXPGPATH]; @@ -212,13 +185,35 @@ check_loadable_libraries(void) snprintf(output_path, sizeof(output_path), "loadable_libraries.txt"); - for (libnum = 0; libnum < os_info.num_libraries; libnum++) + /* + * Now we want to sort the library names into order. This avoids multiple + * probes of the same library, and ensures that libraries are probed in a + * consistent order, which is important for reproducible behavior if one + * library depends on another. + */ + qsort((void *) os_info.libraries, os_info.num_libraries, + sizeof(LibraryInfo), library_name_compare); + + for (libnum = 0, lastfail = -1; libnum < os_info.num_libraries; libnum++) { - char *lib = os_info.libraries[libnum]; + char *lib = os_info.libraries[libnum].name; int llen = strlen(lib); char cmd[7 + 2 * MAXPGPATH + 1]; PGresult *res; + /* + * If we have already probed for the library, skip re-probing and only + * report the database name. + */ + if (found && lastfail >= 0 && + strcmp(lib, os_info.libraries[lastfail].name) == 0) + { + fprintf(script, _("\t\"%s\"\n"), + old_cluster.dbarr.dbs[os_info.libraries[libnum].db].db_name); + + continue; + } + /* * In Postgres 9.0, Python 3 support was added, and to do that, a * plpython2u language was created with library name plpython2.so as a @@ -248,6 +243,7 @@ check_loadable_libraries(void) if (PQresultStatus(res) != PGRES_COMMAND_OK) { found = true; + lastfail = libnum; if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) pg_fatal("could not open file \"%s\": %s\n", @@ -255,6 +251,8 @@ check_loadable_libraries(void) fprintf(script, _("could not load library \"%s\": %s"), lib, PQerrorMessage(conn)); + fprintf(script, _("library found in databases:\n\t\"%s\"\n"), + old_cluster.dbarr.dbs[os_info.libraries[libnum].db].db_name); } PQclear(res); diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h index 7e5e971294..f12750d930 100644 --- a/src/bin/pg_upgrade/pg_upgrade.h +++ b/src/bin/pg_upgrade/pg_upgrade.h @@ -300,6 +300,11 @@ typedef struct int jobs; } UserOpts; +typedef struct +{ + char *name; + int db; +} LibraryInfo; /* * OSInfo @@ -312,7 +317,7 @@ typedef struct bool user_specified; /* user specified on command-line */ char **old_tablespaces; /* tablespaces */ int num_old_tablespaces; - char **libraries; /* loadable libraries */ + LibraryInfo *libraries; /* loadable libraries */ int num_libraries; ClusterInfo *running_cluster; } OSInfo; -- 2.14.1.145.gb3622a4ee