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 "access/transam.h"
13 #include "catalog/pg_language_d.h"
14 #include "pg_upgrade.h"
15 
16 /*
17  * qsort comparator for pointers to library names
18  *
19  * We sort first by name length, then alphabetically for names of the
20  * same length, then database array index. This is to ensure that, eg,
21  * "hstore_plpython" sorts after both "hstore" and "plpython"; otherwise
22  * transform modules will probably fail their LOAD tests. (The backend
23  * ought to cope with that consideration, but it doesn't yet, and even
24  * when it does it'll still be a good idea to have a predictable order of
25  * probing here.)
26  */
27 static int
28 library_name_compare(const void *p1, const void *p2)
29 {
30  const char *str1 = ((const LibraryInfo *) p1)->name;
31  const char *str2 = ((const LibraryInfo *) p2)->name;
32  int slen1 = strlen(str1);
33  int slen2 = strlen(str2);
34  int cmp = strcmp(str1, str2);
35 
36  if (slen1 != slen2)
37  return slen1 - slen2;
38  if (cmp != 0)
39  return cmp;
40  else
41  return ((const LibraryInfo *) p1)->dbnum -
42  ((const LibraryInfo *) p2)->dbnum;
43 }
44 
45 
46 /*
47  * get_loadable_libraries()
48  *
49  * Fetch the names of all old libraries containing C-language functions.
50  * We will later check that they all exist in the new installation.
51  */
52 void
54 {
55  PGresult **ress;
56  int totaltups;
57  int dbnum;
58  bool found_public_plpython_handler = false;
59 
60  ress = (PGresult **) pg_malloc(old_cluster.dbarr.ndbs * sizeof(PGresult *));
61  totaltups = 0;
62 
63  /* Fetch all library names, removing duplicates within each DB */
64  for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
65  {
66  DbInfo *active_db = &old_cluster.dbarr.dbs[dbnum];
68 
69  /*
70  * Fetch all libraries containing non-built-in C functions in this DB.
71  */
72  ress[dbnum] = executeQueryOrDie(conn,
73  "SELECT DISTINCT probin "
74  "FROM pg_catalog.pg_proc "
75  "WHERE prolang = %u AND "
76  "probin IS NOT NULL AND "
77  "oid >= %u;",
78  ClanguageId,
80  totaltups += PQntuples(ress[dbnum]);
81 
82  /*
83  * Systems that install plpython before 8.1 have
84  * plpython_call_handler() defined in the "public" schema, causing
85  * pg_dump to dump it. However that function still references
86  * "plpython" (no "2"), so it throws an error on restore. This code
87  * checks for the problem function, reports affected databases to the
88  * user and explains how to remove them. 8.1 git commit:
89  * e0dedd0559f005d60c69c9772163e69c204bac69
90  * http://archives.postgresql.org/pgsql-hackers/2012-03/msg01101.php
91  * http://archives.postgresql.org/pgsql-bugs/2012-05/msg00206.php
92  */
94  {
95  PGresult *res;
96 
97  res = executeQueryOrDie(conn,
98  "SELECT 1 "
99  "FROM pg_catalog.pg_proc p "
100  " JOIN pg_catalog.pg_namespace n "
101  " ON pronamespace = n.oid "
102  "WHERE proname = 'plpython_call_handler' AND "
103  "nspname = 'public' AND "
104  "prolang = %u AND "
105  "probin = '$libdir/plpython' AND "
106  "p.oid >= %u;",
107  ClanguageId,
109  if (PQntuples(res) > 0)
110  {
111  if (!found_public_plpython_handler)
112  {
114  "\nThe old cluster has a \"plpython_call_handler\" function defined\n"
115  "in the \"public\" schema which is a duplicate of the one defined\n"
116  "in the \"pg_catalog\" schema. You can confirm this by executing\n"
117  "in psql:\n"
118  "\n"
119  " \\df *.plpython_call_handler\n"
120  "\n"
121  "The \"public\" schema version of this function was created by a\n"
122  "pre-8.1 install of plpython, and must be removed for pg_upgrade\n"
123  "to complete because it references a now-obsolete \"plpython\"\n"
124  "shared object file. You can remove the \"public\" schema version\n"
125  "of this function by running the following command:\n"
126  "\n"
127  " DROP FUNCTION public.plpython_call_handler()\n"
128  "\n"
129  "in each affected database:\n"
130  "\n");
131  }
132  pg_log(PG_WARNING, " %s\n", active_db->db_name);
133  found_public_plpython_handler = true;
134  }
135  PQclear(res);
136  }
137 
138  PQfinish(conn);
139  }
140 
141  if (found_public_plpython_handler)
142  pg_fatal("Remove the problem functions from the old cluster to continue.\n");
143 
144  os_info.libraries = (LibraryInfo *) pg_malloc(totaltups * sizeof(LibraryInfo));
145  totaltups = 0;
146 
147  for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
148  {
149  PGresult *res = ress[dbnum];
150  int ntups;
151  int rowno;
152 
153  ntups = PQntuples(res);
154  for (rowno = 0; rowno < ntups; rowno++)
155  {
156  char *lib = PQgetvalue(res, rowno, 0);
157 
158  os_info.libraries[totaltups].name = pg_strdup(lib);
159  os_info.libraries[totaltups].dbnum = dbnum;
160 
161  totaltups++;
162  }
163  PQclear(res);
164  }
165 
166  pg_free(ress);
167 
168  os_info.num_libraries = totaltups;
169 }
170 
171 
172 /*
173  * check_loadable_libraries()
174  *
175  * Check that the new cluster contains all required libraries.
176  * We do this by actually trying to LOAD each one, thereby testing
177  * compatibility as well as presence.
178  */
179 void
181 {
182  PGconn *conn = connectToServer(&new_cluster, "template1");
183  int libnum;
184  int was_load_failure = false;
185  FILE *script = NULL;
186  bool found = false;
187  char output_path[MAXPGPATH];
188 
189  prep_status("Checking for presence of required libraries");
190 
191  snprintf(output_path, sizeof(output_path), "loadable_libraries.txt");
192 
193  /*
194  * Now we want to sort the library names into order. This avoids multiple
195  * probes of the same library, and ensures that libraries are probed in a
196  * consistent order, which is important for reproducible behavior if one
197  * library depends on another.
198  */
201 
202  for (libnum = 0; libnum < os_info.num_libraries; libnum++)
203  {
204  char *lib = os_info.libraries[libnum].name;
205  int llen = strlen(lib);
206  char cmd[7 + 2 * MAXPGPATH + 1];
207  PGresult *res;
208 
209  /* Did the library name change? Probe it. */
210  if (libnum == 0 || strcmp(lib, os_info.libraries[libnum - 1].name) != 0)
211  {
212  /*
213  * In Postgres 9.0, Python 3 support was added, and to do that, a
214  * plpython2u language was created with library name plpython2.so
215  * as a symbolic link to plpython.so. In Postgres 9.1, only the
216  * plpython2.so library was created, and both plpythonu and
217  * plpython2u pointing to it. For this reason, any reference to
218  * library name "plpython" in an old PG <= 9.1 cluster must look
219  * for "plpython2" in the new cluster.
220  *
221  * For this case, we could check pg_pltemplate, but that only
222  * works for languages, and does not help with function shared
223  * objects, so we just do a general fix.
224  */
226  strcmp(lib, "$libdir/plpython") == 0)
227  {
228  lib = "$libdir/plpython2";
229  llen = strlen(lib);
230  }
231 
232  strcpy(cmd, "LOAD '");
233  PQescapeStringConn(conn, cmd + strlen(cmd), lib, llen, NULL);
234  strcat(cmd, "'");
235 
236  res = PQexec(conn, cmd);
237 
238  if (PQresultStatus(res) != PGRES_COMMAND_OK)
239  {
240  found = true;
241  was_load_failure = true;
242 
243  if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
244  pg_fatal("could not open file \"%s\": %s\n",
245  output_path, strerror(errno));
246  fprintf(script, _("could not load library \"%s\": %s"),
247  lib,
248  PQerrorMessage(conn));
249  }
250  else
251  was_load_failure = false;
252 
253  PQclear(res);
254  }
255 
256  if (was_load_failure)
257  fprintf(script, _("In database: %s\n"),
259  }
260 
261  PQfinish(conn);
262 
263  if (found)
264  {
265  fclose(script);
266  pg_log(PG_REPORT, "fatal\n");
267  pg_fatal("Your installation references loadable libraries that are missing from the\n"
268  "new installation. You can add these libraries to the new installation,\n"
269  "or remove the functions using them from the old installation. A list of\n"
270  "problem libraries is in the file:\n"
271  " %s\n\n", output_path);
272  }
273  else
274  check_ok();
275 }
char * name
Definition: pg_upgrade.h:301
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6623
uint32 major_version
Definition: pg_upgrade.h:269
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3163
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
void check_loadable_libraries(void)
Definition: function.c:180
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:41
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4125
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2769
#define fprintf
Definition: port.h:196
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2692
#define FirstNormalObjectId
Definition: transam.h:141
ClusterInfo new_cluster
Definition: pg_upgrade.c:59
PGconn * conn
Definition: streamutil.c:54
#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:3410
static int library_name_compare(const void *p1, const void *p2)
Definition: function.c:28
LibraryInfo * libraries
Definition: pg_upgrade.h:315
static void check_ok(void)
Definition: initdb.c:2076
PGconn * connectToServer(ClusterInfo *cluster, const char *db_name)
Definition: server.c:27
void PQclear(PGresult *res)
Definition: fe-exec.c:694
void get_loadable_libraries(void)
Definition: function.c:53
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:1939
#define qsort(a, b, c, d)
Definition: port.h:488
DbInfo * dbs
Definition: pg_upgrade.h:192
#define snprintf
Definition: port.h:192
#define _(x)
Definition: elog.c:87
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:742