PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
function.c
Go to the documentation of this file.
1 /*
2  * function.c
3  *
4  * server-side function support
5  *
6  * Copyright (c) 2010-2017, PostgreSQL Global Development Group
7  * src/bin/pg_upgrade/function.c
8  */
9 
10 #include "postgres_fe.h"
11 
12 #include "pg_upgrade.h"
13 
14 #include "access/transam.h"
15 #include "catalog/pg_language.h"
16 
17 
18 /*
19  * qsort comparator for pointers to library names
20  *
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.)
27  */
28 static int
29 library_name_compare(const void *p1, const void *p2)
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 }
40 
41 
42 /*
43  * get_loadable_libraries()
44  *
45  * Fetch the names of all old libraries containing C-language functions.
46  * We will later check that they all exist in the new installation.
47  */
48 void
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 }
193 
194 
195 /*
196  * check_loadable_libraries()
197  *
198  * Check that the new cluster contains all required libraries.
199  * We do this by actually trying to LOAD each one, thereby testing
200  * compatibility as well as presence.
201  */
202 void
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:6011
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
void check_loadable_libraries(void)
Definition: function.c:203
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:3568
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void pg_fatal(const char *fmt,...)
Definition: logging.c:83
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2673
FILE * fopen_priv(const char *path, const char *mode)
Definition: file.c:321
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2596
#define FirstNormalObjectId
Definition: transam.h:94
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
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
size_t PQescapeStringConn(PGconn *conn, char *to, const char *from, size_t length, int *error)
Definition: fe-exec.c:3314
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
static void check_ok(void)
Definition: initdb.c:2008
PGconn * connectToServer(ClusterInfo *cluster, const char *db_name)
Definition: server.c:27
void PQclear(PGresult *res)
Definition: fe-exec.c:650
void get_loadable_libraries(void)
Definition: function.c:49
DbInfoArr dbarr
Definition: pg_upgrade.h:263
#define NULL
Definition: c.h:229
void pg_free(void *ptr)
Definition: fe_memutils.c:105
int i
const char * strerror(int errnum)
Definition: strerror.c:19
OSInfo os_info
Definition: pg_upgrade.c:58
char * db_name
Definition: pg_upgrade.h:185
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1846
#define qsort(a, b, c, d)
Definition: port.h:440
DbInfo * dbs
Definition: pg_upgrade.h:196
#define _(x)
Definition: elog.c:84