PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
function.c File Reference
#include "postgres_fe.h"
#include "pg_upgrade.h"
#include "access/transam.h"
#include "catalog/pg_language.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

void check_loadable_libraries ( void  )

Definition at line 203 of file function.c.

References _, check_ok(), conn, connectToServer(), fopen_priv(), GET_MAJOR_VERSION, OSInfo::libraries, ClusterInfo::major_version, MAXPGPATH, new_cluster, NULL, OSInfo::num_libraries, old_cluster, os_info, pg_fatal(), pg_log(), PG_REPORT, PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQescapeStringConn(), PQexec(), PQfinish(), PQresultStatus(), prep_status(), snprintf(), and strerror().

Referenced by check_new_cluster().

204 {
205  PGconn *conn = connectToServer(&new_cluster, "template1");
206  int libnum;
207  FILE *script = NULL;
208  bool found = false;
209  char output_path[MAXPGPATH];
210 
211  prep_status("Checking for presence of required libraries");
212 
213  snprintf(output_path, sizeof(output_path), "loadable_libraries.txt");
214 
215  for (libnum = 0; libnum < os_info.num_libraries; libnum++)
216  {
217  char *lib = os_info.libraries[libnum];
218  int llen = strlen(lib);
219  char cmd[7 + 2 * MAXPGPATH + 1];
220  PGresult *res;
221 
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  */
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)
249  {
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\":\n%s\n"),
256  lib,
257  PQerrorMessage(conn));
258  }
259 
260  PQclear(res);
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 * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6014
uint32 major_version
Definition: pg_upgrade.h:272
int num_libraries
Definition: pg_upgrade.h:314
#define GET_MAJOR_VERSION(v)
Definition: pg_upgrade.h:29
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3547
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void pg_fatal(const char *fmt,...)
Definition: logging.c:83
FILE * fopen_priv(const char *path, const char *mode)
Definition: file.c:321
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2596
ClusterInfo new_cluster
Definition: pg_upgrade.c:56
PGconn * conn
Definition: streamutil.c:42
#define MAXPGPATH
char ** libraries
Definition: pg_upgrade.h:313
void prep_status(const char *fmt,...) pg_attribute_printf(1
ClusterInfo old_cluster
Definition: pg_upgrade.c:56
size_t PQescapeStringConn(PGconn *conn, char *to, const char *from, size_t length, int *error)
Definition: fe-exec.c:3314
void pg_log(eLogType type, const char *fmt,...)
Definition: logging.c:69
static void check_ok(void)
Definition: initdb.c:2023
PGconn * connectToServer(ClusterInfo *cluster, const char *db_name)
Definition: server.c:27
void PQclear(PGresult *res)
Definition: fe-exec.c:650
#define NULL
Definition: c.h:229
const char * strerror(int errnum)
Definition: strerror.c:19
OSInfo os_info
Definition: pg_upgrade.c:58
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1846
#define _(x)
Definition: elog.c:84
void get_loadable_libraries ( void  )

Definition at line 49 of file function.c.

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

Referenced by check_and_dump_old_cluster().

50 {
51  PGresult **ress;
52  int totaltups;
53  int dbnum;
54  bool found_public_plpython_handler = false;
55 
56  ress = (PGresult **) pg_malloc(old_cluster.dbarr.ndbs * sizeof(PGresult *));
57  totaltups = 0;
58 
59  /* Fetch all library names, removing duplicates within each DB */
60  for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
61  {
62  DbInfo *active_db = &old_cluster.dbarr.dbs[dbnum];
64 
65  /*
66  * Fetch all libraries containing non-built-in C functions in this DB.
67  */
68  ress[dbnum] = executeQueryOrDie(conn,
69  "SELECT DISTINCT probin "
70  "FROM pg_catalog.pg_proc "
71  "WHERE prolang = %u AND "
72  "probin IS NOT NULL AND "
73  "oid >= %u;",
76  totaltups += PQntuples(ress[dbnum]);
77 
78  /*
79  * Systems that install plpython before 8.1 have
80  * plpython_call_handler() defined in the "public" schema, causing
81  * pg_dump to dump it. However that function still references
82  * "plpython" (no "2"), so it throws an error on restore. This code
83  * checks for the problem function, reports affected databases to the
84  * user and explains how to remove them. 8.1 git commit:
85  * e0dedd0559f005d60c69c9772163e69c204bac69
86  * http://archives.postgresql.org/pgsql-hackers/2012-03/msg01101.php
87  * http://archives.postgresql.org/pgsql-bugs/2012-05/msg00206.php
88  */
90  {
91  PGresult *res;
92 
93  res = executeQueryOrDie(conn,
94  "SELECT 1 "
95  "FROM pg_catalog.pg_proc p "
96  " JOIN pg_catalog.pg_namespace n "
97  " ON pronamespace = n.oid "
98  "WHERE proname = 'plpython_call_handler' AND "
99  "nspname = 'public' AND "
100  "prolang = %u AND "
101  "probin = '$libdir/plpython' AND "
102  "p.oid >= %u;",
103  ClanguageId,
105  if (PQntuples(res) > 0)
106  {
107  if (!found_public_plpython_handler)
108  {
110  "\nThe old cluster has a \"plpython_call_handler\" function defined\n"
111  "in the \"public\" schema which is a duplicate of the one defined\n"
112  "in the \"pg_catalog\" schema. You can confirm this by executing\n"
113  "in psql:\n"
114  "\n"
115  " \\df *.plpython_call_handler\n"
116  "\n"
117  "The \"public\" schema version of this function was created by a\n"
118  "pre-8.1 install of plpython, and must be removed for pg_upgrade\n"
119  "to complete because it references a now-obsolete \"plpython\"\n"
120  "shared object file. You can remove the \"public\" schema version\n"
121  "of this function by running the following command:\n"
122  "\n"
123  " DROP FUNCTION public.plpython_call_handler()\n"
124  "\n"
125  "in each affected database:\n"
126  "\n");
127  }
128  pg_log(PG_WARNING, " %s\n", active_db->db_name);
129  found_public_plpython_handler = true;
130  }
131  PQclear(res);
132  }
133 
134  PQfinish(conn);
135  }
136 
137  if (found_public_plpython_handler)
138  pg_fatal("Remove the problem functions from the old cluster to continue.\n");
139 
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 *));
152  totaltups = 0;
153 
154  for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
155  {
156  PGresult *res = ress[dbnum];
157  int ntups;
158  int rowno;
159 
160  ntups = PQntuples(res);
161  for (rowno = 0; rowno < ntups; rowno++)
162  {
163  char *lib = PQgetvalue(res, rowno, 0);
164 
165  os_info.libraries[totaltups++] = pg_strdup(lib);
166  }
167  PQclear(res);
168  }
169 
170  pg_free(ress);
171 
172  if (totaltups > 1)
173  {
174  int i,
175  lastnondup;
176 
177  qsort((void *) os_info.libraries, totaltups, sizeof(char *),
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
187  }
188  totaltups = lastnondup + 1;
189  }
190 
191  os_info.num_libraries = totaltups;
192 }
uint32 major_version
Definition: pg_upgrade.h:272
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3067
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
int num_libraries
Definition: pg_upgrade.h:314
PGresult * executeQueryOrDie(PGconn *conn, const char *fmt,...) pg_attribute_printf(2
#define GET_MAJOR_VERSION(v)
Definition: pg_upgrade.h:29
#define ClanguageId
Definition: pg_language.h:77
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3547
void pg_fatal(const char *fmt,...)
Definition: logging.c:83
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2673
#define FirstNormalObjectId
Definition: transam.h:94
PGconn * conn
Definition: streamutil.c:42
char ** libraries
Definition: pg_upgrade.h:313
ClusterInfo old_cluster
Definition: pg_upgrade.c:56
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
static int library_name_compare(const void *p1, const void *p2)
Definition: function.c:29
void pg_log(eLogType type, const char *fmt,...)
Definition: logging.c:69
PGconn * connectToServer(ClusterInfo *cluster, const char *db_name)
Definition: server.c:27
void PQclear(PGresult *res)
Definition: fe-exec.c:650
DbInfoArr dbarr
Definition: pg_upgrade.h:263
void pg_free(void *ptr)
Definition: fe_memutils.c:105
int i
OSInfo os_info
Definition: pg_upgrade.c:58
char * db_name
Definition: pg_upgrade.h:185
#define qsort(a, b, c, d)
Definition: port.h:440
DbInfo * dbs
Definition: pg_upgrade.h:196
static int library_name_compare ( const void *  p1,
const void *  p2 
)
static

Definition at line 29 of file function.c.

Referenced by get_loadable_libraries().

30 {
31  const char *str1 = *(const char *const *) p1;
32  const char *str2 = *(const char *const *) p2;
33  int slen1 = strlen(str1);
34  int slen2 = strlen(str2);
35 
36  if (slen1 != slen2)
37  return slen1 - slen2;
38  return strcmp(str1, str2);
39 }