|
|
|
/*
|
|
|
|
* function.c
|
|
|
|
*
|
|
|
|
* server-side function support
|
|
|
|
*
|
|
|
|
* Copyright (c) 2010-2022, PostgreSQL Global Development Group
|
|
|
|
* src/bin/pg_upgrade/function.c
|
|
|
|
*/
|
|
|
|
|
Create libpgcommon, and move pg_malloc et al to it
libpgcommon is a new static library to allow sharing code among the
various frontend programs and backend; this lets us eliminate duplicate
implementations of common routines. We avoid libpgport, because that's
intended as a place for porting issues; per discussion, it seems better
to keep them separate.
The first use case, and the only implemented by this patch, is pg_malloc
and friends, which many frontend programs were already using.
At the same time, we can use this to provide palloc emulation functions
for the frontend; this way, some palloc-using files in the backend can
also be used by the frontend cleanly. To do this, we change palloc() in
the backend to be a function instead of a macro on top of
MemoryContextAlloc(). This was previously believed to cause loss of
performance, but this implementation has been tweaked by Tom and Andres
so that on modern compilers it provides a slight improvement over the
previous one.
This lets us clean up some places that were already with
localized hacks.
Most of the pg_malloc/palloc changes in this patch were authored by
Andres Freund. Zoltán Böszörményi also independently provided a form of
that. libpgcommon infrastructure was authored by Álvaro.
13 years ago
|
|
|
#include "postgres_fe.h"
|
|
|
|
|
|
|
|
#include "access/transam.h"
|
|
|
|
#include "catalog/pg_language_d.h"
|
|
|
|
#include "pg_upgrade.h"
|
Enforce a specific order for probing library loadability in pg_upgrade.
pg_upgrade checks whether all the shared libraries used in the old cluster
are also available in the new one by issuing LOAD for each library name.
Previously, it cared not what order it did the LOADs in. Ideally it
should not have to care, but currently the transform modules in contrib
fail unless both the language and datatype modules they depend on are
loaded first. A backend-side solution for that looks possible but
probably not back-patchable, so as a stopgap measure, let's do the LOAD
tests in order by library name length. That should fix the problem for
reasonably-named transform modules, eg "hstore_plpython" will be loaded
after both "hstore" and "plpython". (Yeah, it's a hack.)
In a larger sense, having a predictable order of these probes is a good
thing, since it will make upgrades predictably work or not work in the
face of inter-library dependencies. Also, this patch replaces O(N^2)
de-duplication logic with O(N log N) logic, which could matter in
installations with very many databases. So I don't foresee reverting this
even after we have a proper fix for the library-dependency problem.
In passing, improve a couple of SQL queries used here.
Per complaint from Andrew Dunstan that pg_upgrade'ing the transform contrib
modules failed. Back-patch to 9.5 where transform modules were introduced.
Discussion: <f7ac29f3-515c-2a44-21c5-ec925053265f@dunslane.net>
9 years ago
|
|
|
|
|
|
|
/*
|
|
|
|
* qsort comparator for pointers to library names
|
|
|
|
*
|
|
|
|
* We sort first by name length, then alphabetically for names of the
|
|
|
|
* same length, then database array index. This is to ensure that, eg,
|
|
|
|
* "hstore_plpython" sorts after both "hstore" and "plpython"; otherwise
|
|
|
|
* transform modules will probably fail their LOAD tests. (The backend
|
|
|
|
* ought to cope with that consideration, but it doesn't yet, and even
|
|
|
|
* when it does it'll still be a good idea to have a predictable order of
|
|
|
|
* probing here.)
|
Enforce a specific order for probing library loadability in pg_upgrade.
pg_upgrade checks whether all the shared libraries used in the old cluster
are also available in the new one by issuing LOAD for each library name.
Previously, it cared not what order it did the LOADs in. Ideally it
should not have to care, but currently the transform modules in contrib
fail unless both the language and datatype modules they depend on are
loaded first. A backend-side solution for that looks possible but
probably not back-patchable, so as a stopgap measure, let's do the LOAD
tests in order by library name length. That should fix the problem for
reasonably-named transform modules, eg "hstore_plpython" will be loaded
after both "hstore" and "plpython". (Yeah, it's a hack.)
In a larger sense, having a predictable order of these probes is a good
thing, since it will make upgrades predictably work or not work in the
face of inter-library dependencies. Also, this patch replaces O(N^2)
de-duplication logic with O(N log N) logic, which could matter in
installations with very many databases. So I don't foresee reverting this
even after we have a proper fix for the library-dependency problem.
In passing, improve a couple of SQL queries used here.
Per complaint from Andrew Dunstan that pg_upgrade'ing the transform contrib
modules failed. Back-patch to 9.5 where transform modules were introduced.
Discussion: <f7ac29f3-515c-2a44-21c5-ec925053265f@dunslane.net>
9 years ago
|
|
|
*/
|
|
|
|
static int
|
|
|
|
library_name_compare(const void *p1, const void *p2)
|
|
|
|
{
|
|
|
|
const char *str1 = ((const LibraryInfo *) p1)->name;
|
|
|
|
const char *str2 = ((const LibraryInfo *) p2)->name;
|
Enforce a specific order for probing library loadability in pg_upgrade.
pg_upgrade checks whether all the shared libraries used in the old cluster
are also available in the new one by issuing LOAD for each library name.
Previously, it cared not what order it did the LOADs in. Ideally it
should not have to care, but currently the transform modules in contrib
fail unless both the language and datatype modules they depend on are
loaded first. A backend-side solution for that looks possible but
probably not back-patchable, so as a stopgap measure, let's do the LOAD
tests in order by library name length. That should fix the problem for
reasonably-named transform modules, eg "hstore_plpython" will be loaded
after both "hstore" and "plpython". (Yeah, it's a hack.)
In a larger sense, having a predictable order of these probes is a good
thing, since it will make upgrades predictably work or not work in the
face of inter-library dependencies. Also, this patch replaces O(N^2)
de-duplication logic with O(N log N) logic, which could matter in
installations with very many databases. So I don't foresee reverting this
even after we have a proper fix for the library-dependency problem.
In passing, improve a couple of SQL queries used here.
Per complaint from Andrew Dunstan that pg_upgrade'ing the transform contrib
modules failed. Back-patch to 9.5 where transform modules were introduced.
Discussion: <f7ac29f3-515c-2a44-21c5-ec925053265f@dunslane.net>
9 years ago
|
|
|
int slen1 = strlen(str1);
|
|
|
|
int slen2 = strlen(str2);
|
|
|
|
int cmp = strcmp(str1, str2);
|
|
|
|
|
Enforce a specific order for probing library loadability in pg_upgrade.
pg_upgrade checks whether all the shared libraries used in the old cluster
are also available in the new one by issuing LOAD for each library name.
Previously, it cared not what order it did the LOADs in. Ideally it
should not have to care, but currently the transform modules in contrib
fail unless both the language and datatype modules they depend on are
loaded first. A backend-side solution for that looks possible but
probably not back-patchable, so as a stopgap measure, let's do the LOAD
tests in order by library name length. That should fix the problem for
reasonably-named transform modules, eg "hstore_plpython" will be loaded
after both "hstore" and "plpython". (Yeah, it's a hack.)
In a larger sense, having a predictable order of these probes is a good
thing, since it will make upgrades predictably work or not work in the
face of inter-library dependencies. Also, this patch replaces O(N^2)
de-duplication logic with O(N log N) logic, which could matter in
installations with very many databases. So I don't foresee reverting this
even after we have a proper fix for the library-dependency problem.
In passing, improve a couple of SQL queries used here.
Per complaint from Andrew Dunstan that pg_upgrade'ing the transform contrib
modules failed. Back-patch to 9.5 where transform modules were introduced.
Discussion: <f7ac29f3-515c-2a44-21c5-ec925053265f@dunslane.net>
9 years ago
|
|
|
if (slen1 != slen2)
|
|
|
|
return slen1 - slen2;
|
|
|
|
if (cmp != 0)
|
|
|
|
return cmp;
|
|
|
|
else
|
|
|
|
return ((const LibraryInfo *) p1)->dbnum -
|
|
|
|
((const LibraryInfo *) p2)->dbnum;
|
Enforce a specific order for probing library loadability in pg_upgrade.
pg_upgrade checks whether all the shared libraries used in the old cluster
are also available in the new one by issuing LOAD for each library name.
Previously, it cared not what order it did the LOADs in. Ideally it
should not have to care, but currently the transform modules in contrib
fail unless both the language and datatype modules they depend on are
loaded first. A backend-side solution for that looks possible but
probably not back-patchable, so as a stopgap measure, let's do the LOAD
tests in order by library name length. That should fix the problem for
reasonably-named transform modules, eg "hstore_plpython" will be loaded
after both "hstore" and "plpython". (Yeah, it's a hack.)
In a larger sense, having a predictable order of these probes is a good
thing, since it will make upgrades predictably work or not work in the
face of inter-library dependencies. Also, this patch replaces O(N^2)
de-duplication logic with O(N log N) logic, which could matter in
installations with very many databases. So I don't foresee reverting this
even after we have a proper fix for the library-dependency problem.
In passing, improve a couple of SQL queries used here.
Per complaint from Andrew Dunstan that pg_upgrade'ing the transform contrib
modules failed. Back-patch to 9.5 where transform modules were introduced.
Discussion: <f7ac29f3-515c-2a44-21c5-ec925053265f@dunslane.net>
9 years ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_loadable_libraries()
|
|
|
|
*
|
|
|
|
* Fetch the names of all old libraries containing C-language functions.
|
|
|
|
* We will later check that they all exist in the new installation.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
get_loadable_libraries(void)
|
|
|
|
{
|
|
|
|
PGresult **ress;
|
|
|
|
int totaltups;
|
|
|
|
int dbnum;
|
|
|
|
|
|
|
|
ress = (PGresult **) pg_malloc(old_cluster.dbarr.ndbs * sizeof(PGresult *));
|
|
|
|
totaltups = 0;
|
|
|
|
|
|
|
|
/* Fetch all library names, removing duplicates within each DB */
|
|
|
|
for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
|
|
|
|
{
|
|
|
|
DbInfo *active_db = &old_cluster.dbarr.dbs[dbnum];
|
|
|
|
PGconn *conn = connectToServer(&old_cluster, active_db->db_name);
|
|
|
|
|
|
|
|
/*
|
Enforce a specific order for probing library loadability in pg_upgrade.
pg_upgrade checks whether all the shared libraries used in the old cluster
are also available in the new one by issuing LOAD for each library name.
Previously, it cared not what order it did the LOADs in. Ideally it
should not have to care, but currently the transform modules in contrib
fail unless both the language and datatype modules they depend on are
loaded first. A backend-side solution for that looks possible but
probably not back-patchable, so as a stopgap measure, let's do the LOAD
tests in order by library name length. That should fix the problem for
reasonably-named transform modules, eg "hstore_plpython" will be loaded
after both "hstore" and "plpython". (Yeah, it's a hack.)
In a larger sense, having a predictable order of these probes is a good
thing, since it will make upgrades predictably work or not work in the
face of inter-library dependencies. Also, this patch replaces O(N^2)
de-duplication logic with O(N log N) logic, which could matter in
installations with very many databases. So I don't foresee reverting this
even after we have a proper fix for the library-dependency problem.
In passing, improve a couple of SQL queries used here.
Per complaint from Andrew Dunstan that pg_upgrade'ing the transform contrib
modules failed. Back-patch to 9.5 where transform modules were introduced.
Discussion: <f7ac29f3-515c-2a44-21c5-ec925053265f@dunslane.net>
9 years ago
|
|
|
* Fetch all libraries containing non-built-in C functions in this DB.
|
|
|
|
*/
|
|
|
|
ress[dbnum] = executeQueryOrDie(conn,
|
|
|
|
"SELECT DISTINCT probin "
|
Enforce a specific order for probing library loadability in pg_upgrade.
pg_upgrade checks whether all the shared libraries used in the old cluster
are also available in the new one by issuing LOAD for each library name.
Previously, it cared not what order it did the LOADs in. Ideally it
should not have to care, but currently the transform modules in contrib
fail unless both the language and datatype modules they depend on are
loaded first. A backend-side solution for that looks possible but
probably not back-patchable, so as a stopgap measure, let's do the LOAD
tests in order by library name length. That should fix the problem for
reasonably-named transform modules, eg "hstore_plpython" will be loaded
after both "hstore" and "plpython". (Yeah, it's a hack.)
In a larger sense, having a predictable order of these probes is a good
thing, since it will make upgrades predictably work or not work in the
face of inter-library dependencies. Also, this patch replaces O(N^2)
de-duplication logic with O(N log N) logic, which could matter in
installations with very many databases. So I don't foresee reverting this
even after we have a proper fix for the library-dependency problem.
In passing, improve a couple of SQL queries used here.
Per complaint from Andrew Dunstan that pg_upgrade'ing the transform contrib
modules failed. Back-patch to 9.5 where transform modules were introduced.
Discussion: <f7ac29f3-515c-2a44-21c5-ec925053265f@dunslane.net>
9 years ago
|
|
|
"FROM pg_catalog.pg_proc "
|
|
|
|
"WHERE prolang = %u AND "
|
|
|
|
"probin IS NOT NULL AND "
|
|
|
|
"oid >= %u;",
|
Enforce a specific order for probing library loadability in pg_upgrade.
pg_upgrade checks whether all the shared libraries used in the old cluster
are also available in the new one by issuing LOAD for each library name.
Previously, it cared not what order it did the LOADs in. Ideally it
should not have to care, but currently the transform modules in contrib
fail unless both the language and datatype modules they depend on are
loaded first. A backend-side solution for that looks possible but
probably not back-patchable, so as a stopgap measure, let's do the LOAD
tests in order by library name length. That should fix the problem for
reasonably-named transform modules, eg "hstore_plpython" will be loaded
after both "hstore" and "plpython". (Yeah, it's a hack.)
In a larger sense, having a predictable order of these probes is a good
thing, since it will make upgrades predictably work or not work in the
face of inter-library dependencies. Also, this patch replaces O(N^2)
de-duplication logic with O(N log N) logic, which could matter in
installations with very many databases. So I don't foresee reverting this
even after we have a proper fix for the library-dependency problem.
In passing, improve a couple of SQL queries used here.
Per complaint from Andrew Dunstan that pg_upgrade'ing the transform contrib
modules failed. Back-patch to 9.5 where transform modules were introduced.
Discussion: <f7ac29f3-515c-2a44-21c5-ec925053265f@dunslane.net>
9 years ago
|
|
|
ClanguageId,
|
|
|
|
FirstNormalObjectId);
|
|
|
|
totaltups += PQntuples(ress[dbnum]);
|
|
|
|
|
|
|
|
PQfinish(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
os_info.libraries = (LibraryInfo *) pg_malloc(totaltups * sizeof(LibraryInfo));
|
|
|
|
totaltups = 0;
|
|
|
|
|
|
|
|
for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
|
|
|
|
{
|
|
|
|
PGresult *res = ress[dbnum];
|
|
|
|
int ntups;
|
|
|
|
int rowno;
|
|
|
|
|
|
|
|
ntups = PQntuples(res);
|
|
|
|
for (rowno = 0; rowno < ntups; rowno++)
|
|
|
|
{
|
|
|
|
char *lib = PQgetvalue(res, rowno, 0);
|
|
|
|
|
|
|
|
os_info.libraries[totaltups].name = pg_strdup(lib);
|
|
|
|
os_info.libraries[totaltups].dbnum = dbnum;
|
|
|
|
|
|
|
|
totaltups++;
|
|
|
|
}
|
|
|
|
PQclear(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
pg_free(ress);
|
Enforce a specific order for probing library loadability in pg_upgrade.
pg_upgrade checks whether all the shared libraries used in the old cluster
are also available in the new one by issuing LOAD for each library name.
Previously, it cared not what order it did the LOADs in. Ideally it
should not have to care, but currently the transform modules in contrib
fail unless both the language and datatype modules they depend on are
loaded first. A backend-side solution for that looks possible but
probably not back-patchable, so as a stopgap measure, let's do the LOAD
tests in order by library name length. That should fix the problem for
reasonably-named transform modules, eg "hstore_plpython" will be loaded
after both "hstore" and "plpython". (Yeah, it's a hack.)
In a larger sense, having a predictable order of these probes is a good
thing, since it will make upgrades predictably work or not work in the
face of inter-library dependencies. Also, this patch replaces O(N^2)
de-duplication logic with O(N log N) logic, which could matter in
installations with very many databases. So I don't foresee reverting this
even after we have a proper fix for the library-dependency problem.
In passing, improve a couple of SQL queries used here.
Per complaint from Andrew Dunstan that pg_upgrade'ing the transform contrib
modules failed. Back-patch to 9.5 where transform modules were introduced.
Discussion: <f7ac29f3-515c-2a44-21c5-ec925053265f@dunslane.net>
9 years ago
|
|
|
|
|
|
|
os_info.num_libraries = totaltups;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check_loadable_libraries()
|
|
|
|
*
|
|
|
|
* Check that the new cluster contains all required libraries.
|
|
|
|
* We do this by actually trying to LOAD each one, thereby testing
|
|
|
|
* compatibility as well as presence.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
check_loadable_libraries(void)
|
|
|
|
{
|
|
|
|
PGconn *conn = connectToServer(&new_cluster, "template1");
|
|
|
|
int libnum;
|
|
|
|
int was_load_failure = false;
|
|
|
|
FILE *script = NULL;
|
|
|
|
bool found = false;
|
|
|
|
char output_path[MAXPGPATH];
|
|
|
|
|
|
|
|
prep_status("Checking for presence of required libraries");
|
|
|
|
|
pg_upgrade: Move all the files generated internally to a subdirectory
Historically, the location of any files generated by pg_upgrade, as of
the per-database logs and internal dumps, has been the current working
directory, leaving all those files behind when using --retain or on a
failure.
Putting all those contents in a targeted subdirectory makes the whole
easier to debug, and simplifies the code in charge of cleaning up the
logs. Note that another reason is that this facilitates the move of
pg_upgrade to TAP with a fixed location for all the logs to grab if the
test fails repeatedly.
Initially, we thought about being able to specify the output directory
with a new option, but we have settled on using a subdirectory located
at the root of the new cluster's data folder, "pg_upgrade_output.d",
instead, as at the end the new data directory is the location of all the
data generated by pg_upgrade. There is a take with group permissions
here though: if the new data folder has been initialized with this
option, we need to create all the files and paths with the correct
permissions or a base backup taken after a pg_upgrade --retain would
fail, meaning that GetDataDirectoryCreatePerm() has to be called before
creating the log paths, before a couple of sanity checks on the clusters
and before getting the socket directory for the cluster's host settings.
The idea of the new location is based on a suggestion from Peter
Eisentraut.
Also thanks to Andrew Dunstan, Peter Eisentraut, Daniel Gustafsson, Tom
Lane and Bruce Momjian for the discussion (in alphabetical order).
Author: Justin Pryzby
Discussion: https://postgr.es/m/20211212025017.GN17618@telsasoft.com
4 years ago
|
|
|
snprintf(output_path, sizeof(output_path), "%s/%s",
|
|
|
|
log_opts.basedir, "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++)
|
|
|
|
{
|
|
|
|
char *lib = os_info.libraries[libnum].name;
|
|
|
|
int llen = strlen(lib);
|
|
|
|
char cmd[7 + 2 * MAXPGPATH + 1];
|
|
|
|
PGresult *res;
|
|
|
|
|
|
|
|
/* Did the library name change? Probe it. */
|
|
|
|
if (libnum == 0 || strcmp(lib, os_info.libraries[libnum - 1].name) != 0)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (was_load_failure)
|
|
|
|
fprintf(script, _("In database: %s\n"),
|
|
|
|
old_cluster.dbarr.dbs[os_info.libraries[libnum].dbnum].db_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
PQfinish(conn);
|
|
|
|
|
|
|
|
if (found)
|
|
|
|
{
|
|
|
|
fclose(script);
|
|
|
|
pg_log(PG_REPORT, "fatal\n");
|
|
|
|
pg_fatal("Your installation references loadable libraries that are missing from the\n"
|
|
|
|
"new installation. You can add these libraries to the new installation,\n"
|
|
|
|
"or remove the functions using them from the old installation. A list of\n"
|
|
|
|
"problem libraries is in the file:\n"
|
|
|
|
" %s\n\n", output_path);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
check_ok();
|
|
|
|
}
|