Skip to content

Commit 60e3bd1

Browse files
committed
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
1 parent 96313bf commit 60e3bd1

File tree

2 files changed

+85
-80
lines changed

2 files changed

+85
-80
lines changed

src/bin/pg_upgrade/function.c

Lines changed: 79 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,30 @@
1818
/*
1919
* qsort comparator for pointers to library names
2020
*
21-
* We sort first by name length, then alphabetically for names of the same
22-
* length. This is to ensure that, eg, "hstore_plpython" sorts after both
23-
* "hstore" and "plpython"; otherwise transform modules will probably fail
24-
* their LOAD tests. (The backend ought to cope with that consideration,
25-
* but it doesn't yet, and even when it does it'll still be a good idea
26-
* to have a predictable order of probing here.)
21+
* We sort first by name length, then alphabetically for names of the
22+
* same length, then database array index. This is to ensure that, eg,
23+
* "hstore_plpython" sorts after both "hstore" and "plpython"; otherwise
24+
* transform modules will probably fail their LOAD tests. (The backend
25+
* ought to cope with that consideration, but it doesn't yet, and even
26+
* when it does it'll still be a good idea to have a predictable order of
27+
* probing here.)
2728
*/
2829
static int
2930
library_name_compare(const void *p1, const void *p2)
3031
{
31-
const char *str1 = *(const char *const *) p1;
32-
const char *str2 = *(const char *const *) p2;
32+
const char *str1 = ((const LibraryInfo *) p1)->name;
33+
const char *str2 = ((const LibraryInfo *) p2)->name;
3334
int slen1 = strlen(str1);
3435
int slen2 = strlen(str2);
35-
36+
int cmp = strcmp(str1, str2);
37+
3638
if (slen1 != slen2)
3739
return slen1 - slen2;
38-
return strcmp(str1, str2);
40+
if (cmp != 0)
41+
return cmp;
42+
else
43+
return ((const LibraryInfo *) p1)->dbnum -
44+
((const LibraryInfo *) p2)->dbnum;
3945
}
4046

4147

@@ -137,18 +143,7 @@ get_loadable_libraries(void)
137143
if (found_public_plpython_handler)
138144
pg_fatal("Remove the problem functions from the old cluster to continue.\n");
139145

140-
/*
141-
* Now we want to remove duplicates across DBs and sort the library names
142-
* into order. This avoids multiple probes of the same library, and
143-
* ensures that libraries are probed in a consistent order, which is
144-
* important for reproducible behavior if one library depends on another.
145-
*
146-
* First transfer all the names into one array, then sort, then remove
147-
* duplicates. Note: we strdup each name in the first loop so that we can
148-
* safely clear the PGresults in the same loop. This is a bit wasteful
149-
* but it's unlikely there are enough names to matter.
150-
*/
151-
os_info.libraries = (char **) pg_malloc(totaltups * sizeof(char *));
146+
os_info.libraries = (LibraryInfo *) pg_malloc(totaltups * sizeof(LibraryInfo));
152147
totaltups = 0;
153148

154149
for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
@@ -162,32 +157,16 @@ get_loadable_libraries(void)
162157
{
163158
char *lib = PQgetvalue(res, rowno, 0);
164159

165-
os_info.libraries[totaltups++] = pg_strdup(lib);
160+
os_info.libraries[totaltups].name = pg_strdup(lib);
161+
os_info.libraries[totaltups].dbnum = dbnum;
162+
163+
totaltups++;
166164
}
167165
PQclear(res);
168166
}
169167

170168
pg_free(ress);
171169

172-
if (totaltups > 1)
173-
{
174-
int i,
175-
lastnondup;
176-
177-
qsort((void *) os_info.libraries, totaltups, sizeof(char *),
178-
library_name_compare);
179-
180-
for (i = 1, lastnondup = 0; i < totaltups; i++)
181-
{
182-
if (strcmp(os_info.libraries[i],
183-
os_info.libraries[lastnondup]) != 0)
184-
os_info.libraries[++lastnondup] = os_info.libraries[i];
185-
else
186-
pg_free(os_info.libraries[i]);
187-
}
188-
totaltups = lastnondup + 1;
189-
}
190-
191170
os_info.num_libraries = totaltups;
192171
}
193172

@@ -204,6 +183,7 @@ check_loadable_libraries(void)
204183
{
205184
PGconn *conn = connectToServer(&new_cluster, "template1");
206185
int libnum;
186+
int was_load_failure = false;
207187
FILE *script = NULL;
208188
bool found = false;
209189
char output_path[MAXPGPATH];
@@ -212,52 +192,72 @@ check_loadable_libraries(void)
212192

213193
snprintf(output_path, sizeof(output_path), "loadable_libraries.txt");
214194

195+
/*
196+
* Now we want to sort the library names into order. This avoids multiple
197+
* probes of the same library, and ensures that libraries are probed in a
198+
* consistent order, which is important for reproducible behavior if one
199+
* library depends on another.
200+
*/
201+
qsort((void *) os_info.libraries, os_info.num_libraries,
202+
sizeof(LibraryInfo), library_name_compare);
203+
215204
for (libnum = 0; libnum < os_info.num_libraries; libnum++)
216205
{
217-
char *lib = os_info.libraries[libnum];
206+
char *lib = os_info.libraries[libnum].name;
218207
int llen = strlen(lib);
219208
char cmd[7 + 2 * MAXPGPATH + 1];
220209
PGresult *res;
221210

222-
/*
223-
* In Postgres 9.0, Python 3 support was added, and to do that, a
224-
* plpython2u language was created with library name plpython2.so as a
225-
* symbolic link to plpython.so. In Postgres 9.1, only the
226-
* plpython2.so library was created, and both plpythonu and plpython2u
227-
* pointing to it. For this reason, any reference to library name
228-
* "plpython" in an old PG <= 9.1 cluster must look for "plpython2" in
229-
* the new cluster.
230-
*
231-
* For this case, we could check pg_pltemplate, but that only works
232-
* for languages, and does not help with function shared objects, so
233-
* we just do a general fix.
234-
*/
235-
if (GET_MAJOR_VERSION(old_cluster.major_version) < 901 &&
236-
strcmp(lib, "$libdir/plpython") == 0)
237-
{
238-
lib = "$libdir/plpython2";
239-
llen = strlen(lib);
240-
}
241-
242-
strcpy(cmd, "LOAD '");
243-
PQescapeStringConn(conn, cmd + strlen(cmd), lib, llen, NULL);
244-
strcat(cmd, "'");
245-
246-
res = PQexec(conn, cmd);
247-
248-
if (PQresultStatus(res) != PGRES_COMMAND_OK)
211+
/* Did the library name change? Probe it. */
212+
if (libnum == 0 || strcmp(lib, os_info.libraries[libnum - 1].name) != 0)
249213
{
250-
found = true;
251-
252-
if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
253-
pg_fatal("could not open file \"%s\": %s\n",
254-
output_path, strerror(errno));
255-
fprintf(script, _("could not load library \"%s\": %s"),
256-
lib,
257-
PQerrorMessage(conn));
214+
/*
215+
* In Postgres 9.0, Python 3 support was added, and to do that, a
216+
* plpython2u language was created with library name plpython2.so as a
217+
* symbolic link to plpython.so. In Postgres 9.1, only the
218+
* plpython2.so library was created, and both plpythonu and plpython2u
219+
* pointing to it. For this reason, any reference to library name
220+
* "plpython" in an old PG <= 9.1 cluster must look for "plpython2" in
221+
* the new cluster.
222+
*
223+
* For this case, we could check pg_pltemplate, but that only works
224+
* for languages, and does not help with function shared objects, so
225+
* we just do a general fix.
226+
*/
227+
if (GET_MAJOR_VERSION(old_cluster.major_version) < 901 &&
228+
strcmp(lib, "$libdir/plpython") == 0)
229+
{
230+
lib = "$libdir/plpython2";
231+
llen = strlen(lib);
232+
}
233+
234+
strcpy(cmd, "LOAD '");
235+
PQescapeStringConn(conn, cmd + strlen(cmd), lib, llen, NULL);
236+
strcat(cmd, "'");
237+
238+
res = PQexec(conn, cmd);
239+
240+
if (PQresultStatus(res) != PGRES_COMMAND_OK)
241+
{
242+
found = true;
243+
was_load_failure = true;
244+
245+
if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
246+
pg_fatal("could not open file \"%s\": %s\n",
247+
output_path, strerror(errno));
248+
fprintf(script, _("could not load library \"%s\": %s"),
249+
lib,
250+
PQerrorMessage(conn));
251+
}
252+
else
253+
was_load_failure = false;
254+
255+
PQclear(res);
258256
}
259257

260-
PQclear(res);
258+
if (was_load_failure)
259+
fprintf(script, _("Database: %s\n"),
260+
old_cluster.dbarr.dbs[os_info.libraries[libnum].dbnum].db_name);
261261
}
262262

263263
PQfinish(conn);

src/bin/pg_upgrade/pg_upgrade.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,11 @@ typedef struct
300300
int jobs;
301301
} UserOpts;
302302

303+
typedef struct
304+
{
305+
char *name;
306+
int dbnum;
307+
} LibraryInfo;
303308

304309
/*
305310
* OSInfo
@@ -312,7 +317,7 @@ typedef struct
312317
bool user_specified; /* user specified on command-line */
313318
char **old_tablespaces; /* tablespaces */
314319
int num_old_tablespaces;
315-
char **libraries; /* loadable libraries */
320+
LibraryInfo *libraries; /* loadable libraries */
316321
int num_libraries;
317322
ClusterInfo *running_cluster;
318323
} OSInfo;

0 commit comments

Comments
 (0)