PostgreSQL Source Code  git master
function.c
Go to the documentation of this file.
1 /*
2  * function.c
3  *
4  * server-side function support
5  *
6  * Copyright (c) 2010-2019, 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_d.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
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.)
28  */
29 static int
30 library_name_compare(const void *p1, const void *p2)
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 }
46 
47 
48 /*
49  * get_loadable_libraries()
50  *
51  * Fetch the names of all old libraries containing C-language functions.
52  * We will later check that they all exist in the new installation.
53  */
54 void
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 }
172 
173 
174 /*
175  * check_loadable_libraries()
176  *
177  * Check that the new cluster contains all required libraries.
178  * We do this by actually trying to LOAD each one, thereby testing
179  * compatibility as well as presence.
180  */
181 void
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
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
void check_loadable_libraries(void)
Definition: function.c:182
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 fprintf
Definition: port.h:196
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2693
#define FirstNormalObjectId
Definition: transam.h:141
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
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: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
void get_loadable_libraries(void)
Definition: function.c:55
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
void pg_free(void *ptr)
Definition: fe_memutils.c:105
#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
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:742