PostgreSQL Source Code  git master
function.c File Reference
#include "postgres_fe.h"
#include "pg_upgrade.h"
#include "access/transam.h"
#include "catalog/pg_language_d.h"
Include dependency graph for function.c:

Go to the source code of this file.

Functions

static int library_name_compare (const void *p1, const void *p2)
 
void get_loadable_libraries (void)
 
void check_loadable_libraries (void)
 

Function Documentation

◆ check_loadable_libraries()

void check_loadable_libraries ( void  )

Definition at line 182 of file function.c.

References _, check_ok(), conn, connectToServer(), DbInfo::db_name, ClusterInfo::dbarr, LibraryInfo::dbnum, DbInfoArr::dbs, fopen_priv, fprintf, GET_MAJOR_VERSION, OSInfo::libraries, library_name_compare(), ClusterInfo::major_version, MAXPGPATH, LibraryInfo::name, new_cluster, OSInfo::num_libraries, old_cluster, os_info, pg_fatal, pg_log(), PG_REPORT, PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQescapeStringConn(), PQexec(), PQfinish(), PQresultStatus(), prep_status(), qsort, snprintf, and strerror.

Referenced by check_new_cluster().

183 {
184  PGconn *conn = connectToServer(&new_cluster, "template1");
185  int libnum;
186  int was_load_failure = false;
187  FILE *script = NULL;
188  bool found = false;
189  char output_path[MAXPGPATH];
190 
191  prep_status("Checking for presence of required libraries");
192 
193  snprintf(output_path, sizeof(output_path), "loadable_libraries.txt");
194 
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  */
203 
204  for (libnum = 0; libnum < os_info.num_libraries; libnum++)
205  {
206  char *lib = os_info.libraries[libnum].name;
207  int llen = strlen(lib);
208  char cmd[7 + 2 * MAXPGPATH + 1];
209  PGresult *res;
210 
211  /* Did the library name change? Probe it. */
212  if (libnum == 0 || strcmp(lib, os_info.libraries[libnum - 1].name) != 0)
213  {
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
217  * as a symbolic link to plpython.so. In Postgres 9.1, only the
218  * plpython2.so library was created, and both plpythonu and
219  * plpython2u pointing to it. For this reason, any reference to
220  * library name "plpython" in an old PG <= 9.1 cluster must look
221  * for "plpython2" in the new cluster.
222  *
223  * For this case, we could check pg_pltemplate, but that only
224  * works for languages, and does not help with function shared
225  * objects, so we just do a general fix.
226  */
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);
256  }
257 
258  if (was_load_failure)
259  fprintf(script, _("In database: %s\n"),
261  }
262 
263  PQfinish(conn);
264 
265  if (found)
266  {
267  fclose(script);
268  pg_log(PG_REPORT, "fatal\n");
269  pg_fatal("Your installation references loadable libraries that are missing from the\n"
270  "new installation. You can add these libraries to the new installation,\n"
271  "or remove the functions using them from the old installation. A list of\n"
272  "problem libraries is in the file:\n"
273  " %s\n\n", output_path);
274  }
275  else
276  check_ok();
277 }
char * name
Definition: pg_upgrade.h:301
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6596
uint32 major_version
Definition: pg_upgrade.h:269
int num_libraries
Definition: pg_upgrade.h:316
#define GET_MAJOR_VERSION(v)
Definition: pg_upgrade.h:23
#define pg_fatal(...)
Definition: pg_rewind.h:43
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4098
#define fprintf
Definition: port.h:196
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2693
ClusterInfo new_cluster
Definition: pg_upgrade.c:59
PGconn * conn
Definition: streamutil.c:56
#define MAXPGPATH
void prep_status(const char *fmt,...) pg_attribute_printf(1
ClusterInfo old_cluster
Definition: pg_upgrade.c:59
size_t PQescapeStringConn(PGconn *conn, char *to, const char *from, size_t length, int *error)
Definition: fe-exec.c:3411
static int library_name_compare(const void *p1, const void *p2)
Definition: function.c:30
LibraryInfo * libraries
Definition: pg_upgrade.h:315
static void check_ok(void)
Definition: initdb.c:2079
PGconn * connectToServer(ClusterInfo *cluster, const char *db_name)
Definition: server.c:28
void PQclear(PGresult *res)
Definition: fe-exec.c:695
DbInfoArr dbarr
Definition: pg_upgrade.h:260
void void pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2
#define strerror
Definition: port.h:205
#define fopen_priv(path, mode)
Definition: pg_upgrade.h:382
OSInfo os_info
Definition: pg_upgrade.c:61
char * db_name
Definition: pg_upgrade.h:181
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1940
#define qsort(a, b, c, d)
Definition: port.h:492
DbInfo * dbs
Definition: pg_upgrade.h:192
#define snprintf
Definition: port.h:192
#define _(x)
Definition: elog.c:84

◆ get_loadable_libraries()

void get_loadable_libraries ( void  )

Definition at line 55 of file function.c.

References conn, connectToServer(), DbInfo::db_name, ClusterInfo::dbarr, LibraryInfo::dbnum, DbInfoArr::dbs, executeQueryOrDie(), FirstNormalObjectId, GET_MAJOR_VERSION, OSInfo::libraries, ClusterInfo::major_version, LibraryInfo::name, DbInfoArr::ndbs, OSInfo::num_libraries, old_cluster, os_info, pg_fatal, pg_free(), pg_log(), pg_malloc(), pg_strdup(), PG_WARNING, PQclear(), PQfinish(), PQgetvalue(), and PQntuples().

Referenced by check_and_dump_old_cluster().

56 {
57  PGresult **ress;
58  int totaltups;
59  int dbnum;
60  bool found_public_plpython_handler = false;
61 
62  ress = (PGresult **) pg_malloc(old_cluster.dbarr.ndbs * sizeof(PGresult *));
63  totaltups = 0;
64 
65  /* Fetch all library names, removing duplicates within each DB */
66  for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
67  {
68  DbInfo *active_db = &old_cluster.dbarr.dbs[dbnum];
70 
71  /*
72  * Fetch all libraries containing non-built-in C functions in this DB.
73  */
74  ress[dbnum] = executeQueryOrDie(conn,
75  "SELECT DISTINCT probin "
76  "FROM pg_catalog.pg_proc "
77  "WHERE prolang = %u AND "
78  "probin IS NOT NULL AND "
79  "oid >= %u;",
80  ClanguageId,
82  totaltups += PQntuples(ress[dbnum]);
83 
84  /*
85  * Systems that install plpython before 8.1 have
86  * plpython_call_handler() defined in the "public" schema, causing
87  * pg_dump to dump it. However that function still references
88  * "plpython" (no "2"), so it throws an error on restore. This code
89  * checks for the problem function, reports affected databases to the
90  * user and explains how to remove them. 8.1 git commit:
91  * e0dedd0559f005d60c69c9772163e69c204bac69
92  * http://archives.postgresql.org/pgsql-hackers/2012-03/msg01101.php
93  * http://archives.postgresql.org/pgsql-bugs/2012-05/msg00206.php
94  */
96  {
97  PGresult *res;
98 
99  res = executeQueryOrDie(conn,
100  "SELECT 1 "
101  "FROM pg_catalog.pg_proc p "
102  " JOIN pg_catalog.pg_namespace n "
103  " ON pronamespace = n.oid "
104  "WHERE proname = 'plpython_call_handler' AND "
105  "nspname = 'public' AND "
106  "prolang = %u AND "
107  "probin = '$libdir/plpython' AND "
108  "p.oid >= %u;",
109  ClanguageId,
111  if (PQntuples(res) > 0)
112  {
113  if (!found_public_plpython_handler)
114  {
116  "\nThe old cluster has a \"plpython_call_handler\" function defined\n"
117  "in the \"public\" schema which is a duplicate of the one defined\n"
118  "in the \"pg_catalog\" schema. You can confirm this by executing\n"
119  "in psql:\n"
120  "\n"
121  " \\df *.plpython_call_handler\n"
122  "\n"
123  "The \"public\" schema version of this function was created by a\n"
124  "pre-8.1 install of plpython, and must be removed for pg_upgrade\n"
125  "to complete because it references a now-obsolete \"plpython\"\n"
126  "shared object file. You can remove the \"public\" schema version\n"
127  "of this function by running the following command:\n"
128  "\n"
129  " DROP FUNCTION public.plpython_call_handler()\n"
130  "\n"
131  "in each affected database:\n"
132  "\n");
133  }
134  pg_log(PG_WARNING, " %s\n", active_db->db_name);
135  found_public_plpython_handler = true;
136  }
137  PQclear(res);
138  }
139 
140  PQfinish(conn);
141  }
142 
143  if (found_public_plpython_handler)
144  pg_fatal("Remove the problem functions from the old cluster to continue.\n");
145 
146  os_info.libraries = (LibraryInfo *) pg_malloc(totaltups * sizeof(LibraryInfo));
147  totaltups = 0;
148 
149  for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
150  {
151  PGresult *res = ress[dbnum];
152  int ntups;
153  int rowno;
154 
155  ntups = PQntuples(res);
156  for (rowno = 0; rowno < ntups; rowno++)
157  {
158  char *lib = PQgetvalue(res, rowno, 0);
159 
160  os_info.libraries[totaltups].name = pg_strdup(lib);
161  os_info.libraries[totaltups].dbnum = dbnum;
162 
163  totaltups++;
164  }
165  PQclear(res);
166  }
167 
168  pg_free(ress);
169 
170  os_info.num_libraries = totaltups;
171 }
char * name
Definition: pg_upgrade.h:301
uint32 major_version
Definition: pg_upgrade.h:269
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3164
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
int num_libraries
Definition: pg_upgrade.h:316
PGresult * executeQueryOrDie(PGconn *conn, const char *fmt,...) pg_attribute_printf(2
#define GET_MAJOR_VERSION(v)
Definition: pg_upgrade.h:23
#define pg_fatal(...)
Definition: pg_rewind.h:43
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4098
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2770
#define FirstNormalObjectId
Definition: transam.h:141
PGconn * conn
Definition: streamutil.c:56
ClusterInfo old_cluster
Definition: pg_upgrade.c:59
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
LibraryInfo * libraries
Definition: pg_upgrade.h:315
PGconn * connectToServer(ClusterInfo *cluster, const char *db_name)
Definition: server.c:28
void PQclear(PGresult *res)
Definition: fe-exec.c:695
DbInfoArr dbarr
Definition: pg_upgrade.h:260
void void pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2
void pg_free(void *ptr)
Definition: fe_memutils.c:105
OSInfo os_info
Definition: pg_upgrade.c:61
char * db_name
Definition: pg_upgrade.h:181
DbInfo * dbs
Definition: pg_upgrade.h:192

◆ library_name_compare()

static int library_name_compare ( const void *  p1,
const void *  p2 
)
static

Definition at line 30 of file function.c.

References cmp().

Referenced by check_loadable_libraries().

31 {
32  const char *str1 = ((const LibraryInfo *) p1)->name;
33  const char *str2 = ((const LibraryInfo *) p2)->name;
34  int slen1 = strlen(str1);
35  int slen2 = strlen(str2);
36  int cmp = strcmp(str1, str2);
37 
38  if (slen1 != slen2)
39  return slen1 - slen2;
40  if (cmp != 0)
41  return cmp;
42  else
43  return ((const LibraryInfo *) p1)->dbnum -
44  ((const LibraryInfo *) p2)->dbnum;
45 }
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:742