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 */
2829static int
2930library_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 );
0 commit comments