mirror of
https://github.com/postgres/postgres.git
synced 2025-05-09 18:21:05 +03:00
pg_upgrade: report database names with missing extension libs
Previously only the missing library name was reported, forcing users to look in all databases to find the library entries. Discussion: https://postgr.es/m/20180713162815.GA3835@momjian.us Author: Daniel Gustafsson, me
This commit is contained in:
parent
96313bff29
commit
60e3bd1d7f
@ -18,24 +18,30 @@
|
|||||||
/*
|
/*
|
||||||
* qsort comparator for pointers to library names
|
* qsort comparator for pointers to library names
|
||||||
*
|
*
|
||||||
* We sort first by name length, then alphabetically for names of the same
|
* We sort first by name length, then alphabetically for names of the
|
||||||
* length. This is to ensure that, eg, "hstore_plpython" sorts after both
|
* same length, then database array index. This is to ensure that, eg,
|
||||||
* "hstore" and "plpython"; otherwise transform modules will probably fail
|
* "hstore_plpython" sorts after both "hstore" and "plpython"; otherwise
|
||||||
* their LOAD tests. (The backend ought to cope with that consideration,
|
* transform modules will probably fail their LOAD tests. (The backend
|
||||||
* but it doesn't yet, and even when it does it'll still be a good idea
|
* ought to cope with that consideration, but it doesn't yet, and even
|
||||||
* to have a predictable order of probing here.)
|
* when it does it'll still be a good idea to have a predictable order of
|
||||||
|
* probing here.)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
library_name_compare(const void *p1, const void *p2)
|
library_name_compare(const void *p1, const void *p2)
|
||||||
{
|
{
|
||||||
const char *str1 = *(const char *const *) p1;
|
const char *str1 = ((const LibraryInfo *) p1)->name;
|
||||||
const char *str2 = *(const char *const *) p2;
|
const char *str2 = ((const LibraryInfo *) p2)->name;
|
||||||
int slen1 = strlen(str1);
|
int slen1 = strlen(str1);
|
||||||
int slen2 = strlen(str2);
|
int slen2 = strlen(str2);
|
||||||
|
int cmp = strcmp(str1, str2);
|
||||||
|
|
||||||
if (slen1 != slen2)
|
if (slen1 != slen2)
|
||||||
return slen1 - slen2;
|
return slen1 - slen2;
|
||||||
return strcmp(str1, str2);
|
if (cmp != 0)
|
||||||
|
return cmp;
|
||||||
|
else
|
||||||
|
return ((const LibraryInfo *) p1)->dbnum -
|
||||||
|
((const LibraryInfo *) p2)->dbnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -137,18 +143,7 @@ get_loadable_libraries(void)
|
|||||||
if (found_public_plpython_handler)
|
if (found_public_plpython_handler)
|
||||||
pg_fatal("Remove the problem functions from the old cluster to continue.\n");
|
pg_fatal("Remove the problem functions from the old cluster to continue.\n");
|
||||||
|
|
||||||
/*
|
os_info.libraries = (LibraryInfo *) pg_malloc(totaltups * sizeof(LibraryInfo));
|
||||||
* 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 *));
|
|
||||||
totaltups = 0;
|
totaltups = 0;
|
||||||
|
|
||||||
for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
|
for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
|
||||||
@ -162,32 +157,16 @@ get_loadable_libraries(void)
|
|||||||
{
|
{
|
||||||
char *lib = PQgetvalue(res, rowno, 0);
|
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].dbnum = dbnum;
|
||||||
|
|
||||||
|
totaltups++;
|
||||||
}
|
}
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
pg_free(ress);
|
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;
|
os_info.num_libraries = totaltups;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,6 +183,7 @@ check_loadable_libraries(void)
|
|||||||
{
|
{
|
||||||
PGconn *conn = connectToServer(&new_cluster, "template1");
|
PGconn *conn = connectToServer(&new_cluster, "template1");
|
||||||
int libnum;
|
int libnum;
|
||||||
|
int was_load_failure = false;
|
||||||
FILE *script = NULL;
|
FILE *script = NULL;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
char output_path[MAXPGPATH];
|
char output_path[MAXPGPATH];
|
||||||
@ -212,52 +192,72 @@ check_loadable_libraries(void)
|
|||||||
|
|
||||||
snprintf(output_path, sizeof(output_path), "loadable_libraries.txt");
|
snprintf(output_path, sizeof(output_path), "loadable_libraries.txt");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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; libnum < os_info.num_libraries; libnum++)
|
for (libnum = 0; libnum < os_info.num_libraries; libnum++)
|
||||||
{
|
{
|
||||||
char *lib = os_info.libraries[libnum];
|
char *lib = os_info.libraries[libnum].name;
|
||||||
int llen = strlen(lib);
|
int llen = strlen(lib);
|
||||||
char cmd[7 + 2 * MAXPGPATH + 1];
|
char cmd[7 + 2 * MAXPGPATH + 1];
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
|
|
||||||
/*
|
/* Did the library name change? Probe it. */
|
||||||
* In Postgres 9.0, Python 3 support was added, and to do that, a
|
if (libnum == 0 || strcmp(lib, os_info.libraries[libnum - 1].name) != 0)
|
||||||
* plpython2u language was created with library name plpython2.so as a
|
|
||||||
* symbolic link to plpython.so. In Postgres 9.1, only the
|
|
||||||
* plpython2.so library was created, and both plpythonu and plpython2u
|
|
||||||
* pointing to it. For this reason, any reference to library name
|
|
||||||
* "plpython" in an old PG <= 9.1 cluster must look for "plpython2" in
|
|
||||||
* the new cluster.
|
|
||||||
*
|
|
||||||
* For this case, we could check pg_pltemplate, but that only works
|
|
||||||
* for languages, and does not help with function shared objects, so
|
|
||||||
* we just do a general fix.
|
|
||||||
*/
|
|
||||||
if (GET_MAJOR_VERSION(old_cluster.major_version) < 901 &&
|
|
||||||
strcmp(lib, "$libdir/plpython") == 0)
|
|
||||||
{
|
{
|
||||||
lib = "$libdir/plpython2";
|
/*
|
||||||
llen = strlen(lib);
|
* 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
|
||||||
|
* symbolic link to plpython.so. In Postgres 9.1, only the
|
||||||
|
* plpython2.so library was created, and both plpythonu and plpython2u
|
||||||
|
* pointing to it. For this reason, any reference to library name
|
||||||
|
* "plpython" in an old PG <= 9.1 cluster must look for "plpython2" in
|
||||||
|
* the new cluster.
|
||||||
|
*
|
||||||
|
* For this case, we could check pg_pltemplate, but that only works
|
||||||
|
* for languages, and does not help with function shared objects, so
|
||||||
|
* we just do a general fix.
|
||||||
|
*/
|
||||||
|
if (GET_MAJOR_VERSION(old_cluster.major_version) < 901 &&
|
||||||
|
strcmp(lib, "$libdir/plpython") == 0)
|
||||||
|
{
|
||||||
|
lib = "$libdir/plpython2";
|
||||||
|
llen = strlen(lib);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(cmd, "LOAD '");
|
||||||
|
PQescapeStringConn(conn, cmd + strlen(cmd), lib, llen, NULL);
|
||||||
|
strcat(cmd, "'");
|
||||||
|
|
||||||
|
res = PQexec(conn, cmd);
|
||||||
|
|
||||||
|
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
was_load_failure = true;
|
||||||
|
|
||||||
|
if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
|
||||||
|
pg_fatal("could not open file \"%s\": %s\n",
|
||||||
|
output_path, strerror(errno));
|
||||||
|
fprintf(script, _("could not load library \"%s\": %s"),
|
||||||
|
lib,
|
||||||
|
PQerrorMessage(conn));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
was_load_failure = false;
|
||||||
|
|
||||||
|
PQclear(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(cmd, "LOAD '");
|
if (was_load_failure)
|
||||||
PQescapeStringConn(conn, cmd + strlen(cmd), lib, llen, NULL);
|
fprintf(script, _("Database: %s\n"),
|
||||||
strcat(cmd, "'");
|
old_cluster.dbarr.dbs[os_info.libraries[libnum].dbnum].db_name);
|
||||||
|
|
||||||
res = PQexec(conn, cmd);
|
|
||||||
|
|
||||||
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
|
|
||||||
if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
|
|
||||||
pg_fatal("could not open file \"%s\": %s\n",
|
|
||||||
output_path, strerror(errno));
|
|
||||||
fprintf(script, _("could not load library \"%s\": %s"),
|
|
||||||
lib,
|
|
||||||
PQerrorMessage(conn));
|
|
||||||
}
|
|
||||||
|
|
||||||
PQclear(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
|
@ -300,6 +300,11 @@ typedef struct
|
|||||||
int jobs;
|
int jobs;
|
||||||
} UserOpts;
|
} UserOpts;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
int dbnum;
|
||||||
|
} LibraryInfo;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OSInfo
|
* OSInfo
|
||||||
@ -312,7 +317,7 @@ typedef struct
|
|||||||
bool user_specified; /* user specified on command-line */
|
bool user_specified; /* user specified on command-line */
|
||||||
char **old_tablespaces; /* tablespaces */
|
char **old_tablespaces; /* tablespaces */
|
||||||
int num_old_tablespaces;
|
int num_old_tablespaces;
|
||||||
char **libraries; /* loadable libraries */
|
LibraryInfo *libraries; /* loadable libraries */
|
||||||
int num_libraries;
|
int num_libraries;
|
||||||
ClusterInfo *running_cluster;
|
ClusterInfo *running_cluster;
|
||||||
} OSInfo;
|
} OSInfo;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user