]> granicus.if.org Git - postgresql/blob - contrib/pg_upgrade/function.c
pgindent run for 9.4
[postgresql] / contrib / pg_upgrade / function.c
1 /*
2  *      function.c
3  *
4  *      server-side function support
5  *
6  *      Copyright (c) 2010-2014, PostgreSQL Global Development Group
7  *      contrib/pg_upgrade/function.c
8  */
9
10 #include "postgres_fe.h"
11
12 #include "pg_upgrade.h"
13
14 #include "access/transam.h"
15
16 #define PG_UPGRADE_SUPPORT      "$libdir/pg_upgrade_support"
17
18 /*
19  * install_support_functions_in_new_db()
20  *
21  * pg_upgrade requires some support functions that enable it to modify
22  * backend behavior.
23  */
24 void
25 install_support_functions_in_new_db(const char *db_name)
26 {
27         PGconn     *conn = connectToServer(&new_cluster, db_name);
28
29         /* suppress NOTICE of dropped objects */
30         PQclear(executeQueryOrDie(conn,
31                                                           "SET client_min_messages = warning;"));
32         PQclear(executeQueryOrDie(conn,
33                                                    "DROP SCHEMA IF EXISTS binary_upgrade CASCADE;"));
34         PQclear(executeQueryOrDie(conn,
35                                                           "RESET client_min_messages;"));
36
37         PQclear(executeQueryOrDie(conn,
38                                                           "CREATE SCHEMA binary_upgrade;"));
39
40         PQclear(executeQueryOrDie(conn,
41                                                           "CREATE OR REPLACE FUNCTION "
42                                                           "binary_upgrade.set_next_pg_type_oid(OID) "
43                                                           "RETURNS VOID "
44                                                           "AS '$libdir/pg_upgrade_support' "
45                                                           "LANGUAGE C STRICT;"));
46         PQclear(executeQueryOrDie(conn,
47                                                           "CREATE OR REPLACE FUNCTION "
48                                                         "binary_upgrade.set_next_array_pg_type_oid(OID) "
49                                                           "RETURNS VOID "
50                                                           "AS '$libdir/pg_upgrade_support' "
51                                                           "LANGUAGE C STRICT;"));
52         PQclear(executeQueryOrDie(conn,
53                                                           "CREATE OR REPLACE FUNCTION "
54                                                         "binary_upgrade.set_next_toast_pg_type_oid(OID) "
55                                                           "RETURNS VOID "
56                                                           "AS '$libdir/pg_upgrade_support' "
57                                                           "LANGUAGE C STRICT;"));
58         PQclear(executeQueryOrDie(conn,
59                                                           "CREATE OR REPLACE FUNCTION "
60                                                         "binary_upgrade.set_next_heap_pg_class_oid(OID) "
61                                                           "RETURNS VOID "
62                                                           "AS '$libdir/pg_upgrade_support' "
63                                                           "LANGUAGE C STRICT;"));
64         PQclear(executeQueryOrDie(conn,
65                                                           "CREATE OR REPLACE FUNCTION "
66                                                    "binary_upgrade.set_next_index_pg_class_oid(OID) "
67                                                           "RETURNS VOID "
68                                                           "AS '$libdir/pg_upgrade_support' "
69                                                           "LANGUAGE C STRICT;"));
70         PQclear(executeQueryOrDie(conn,
71                                                           "CREATE OR REPLACE FUNCTION "
72                                                    "binary_upgrade.set_next_toast_pg_class_oid(OID) "
73                                                           "RETURNS VOID "
74                                                           "AS '$libdir/pg_upgrade_support' "
75                                                           "LANGUAGE C STRICT;"));
76         PQclear(executeQueryOrDie(conn,
77                                                           "CREATE OR REPLACE FUNCTION "
78                                                           "binary_upgrade.set_next_pg_enum_oid(OID) "
79                                                           "RETURNS VOID "
80                                                           "AS '$libdir/pg_upgrade_support' "
81                                                           "LANGUAGE C STRICT;"));
82         PQclear(executeQueryOrDie(conn,
83                                                           "CREATE OR REPLACE FUNCTION "
84                                                           "binary_upgrade.set_next_pg_authid_oid(OID) "
85                                                           "RETURNS VOID "
86                                                           "AS '$libdir/pg_upgrade_support' "
87                                                           "LANGUAGE C STRICT;"));
88         PQclear(executeQueryOrDie(conn,
89                                                           "CREATE OR REPLACE FUNCTION "
90                                                           "binary_upgrade.create_empty_extension(text, text, bool, text, oid[], text[], text[]) "
91                                                           "RETURNS VOID "
92                                                           "AS '$libdir/pg_upgrade_support' "
93                                                           "LANGUAGE C;"));
94         PQfinish(conn);
95 }
96
97
98 void
99 uninstall_support_functions_from_new_cluster(void)
100 {
101         int                     dbnum;
102
103         prep_status("Removing support functions from new cluster");
104
105         for (dbnum = 0; dbnum < new_cluster.dbarr.ndbs; dbnum++)
106         {
107                 DbInfo     *new_db = &new_cluster.dbarr.dbs[dbnum];
108                 PGconn     *conn = connectToServer(&new_cluster, new_db->db_name);
109
110                 /* suppress NOTICE of dropped objects */
111                 PQclear(executeQueryOrDie(conn,
112                                                                   "SET client_min_messages = warning;"));
113                 PQclear(executeQueryOrDie(conn,
114                                                                   "DROP SCHEMA binary_upgrade CASCADE;"));
115                 PQclear(executeQueryOrDie(conn,
116                                                                   "RESET client_min_messages;"));
117                 PQfinish(conn);
118         }
119         check_ok();
120 }
121
122
123 /*
124  * get_loadable_libraries()
125  *
126  *      Fetch the names of all old libraries containing C-language functions.
127  *      We will later check that they all exist in the new installation.
128  */
129 void
130 get_loadable_libraries(void)
131 {
132         PGresult  **ress;
133         int                     totaltups;
134         int                     dbnum;
135         bool            found_public_plpython_handler = false;
136
137         ress = (PGresult **) pg_malloc(old_cluster.dbarr.ndbs * sizeof(PGresult *));
138         totaltups = 0;
139
140         /* Fetch all library names, removing duplicates within each DB */
141         for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
142         {
143                 DbInfo     *active_db = &old_cluster.dbarr.dbs[dbnum];
144                 PGconn     *conn = connectToServer(&old_cluster, active_db->db_name);
145
146                 /*
147                  * Fetch all libraries referenced in this DB.  We can't exclude the
148                  * "pg_catalog" schema because, while such functions are not
149                  * explicitly dumped by pg_dump, they do reference implicit objects
150                  * that pg_dump does dump, e.g. CREATE LANGUAGE plperl.
151                  */
152                 ress[dbnum] = executeQueryOrDie(conn,
153                                                                                 "SELECT DISTINCT probin "
154                                                                                 "FROM   pg_catalog.pg_proc "
155                                                                                 "WHERE  prolang = 13 /* C */ AND "
156                                                                                 "probin IS NOT NULL AND "
157                                                                                 "oid >= %u;",
158                                                                                 FirstNormalObjectId);
159                 totaltups += PQntuples(ress[dbnum]);
160
161                 /*
162                  * Systems that install plpython before 8.1 have
163                  * plpython_call_handler() defined in the "public" schema, causing
164                  * pg_dumpall to dump it.  However that function still references
165                  * "plpython" (no "2"), so it throws an error on restore.  This code
166                  * checks for the problem function, reports affected databases to the
167                  * user and explains how to remove them. 8.1 git commit:
168                  * e0dedd0559f005d60c69c9772163e69c204bac69
169                  * http://archives.postgresql.org/pgsql-hackers/2012-03/msg01101.php
170                  * http://archives.postgresql.org/pgsql-bugs/2012-05/msg00206.php
171                  */
172                 if (GET_MAJOR_VERSION(old_cluster.major_version) < 901)
173                 {
174                         PGresult   *res;
175
176                         res = executeQueryOrDie(conn,
177                                                                         "SELECT 1 "
178                                                    "FROM        pg_catalog.pg_proc JOIN pg_namespace "
179                                                          "              ON pronamespace = pg_namespace.oid "
180                                                            "WHERE proname = 'plpython_call_handler' AND "
181                                                                         "nspname = 'public' AND "
182                                                                         "prolang = 13 /* C */ AND "
183                                                                         "probin = '$libdir/plpython' AND "
184                                                                         "pg_proc.oid >= %u;",
185                                                                         FirstNormalObjectId);
186                         if (PQntuples(res) > 0)
187                         {
188                                 if (!found_public_plpython_handler)
189                                 {
190                                         pg_log(PG_WARNING,
191                                                    "\nThe old cluster has a \"plpython_call_handler\" function defined\n"
192                                                    "in the \"public\" schema which is a duplicate of the one defined\n"
193                                                    "in the \"pg_catalog\" schema.  You can confirm this by executing\n"
194                                                    "in psql:\n"
195                                                    "\n"
196                                                    "    \\df *.plpython_call_handler\n"
197                                                    "\n"
198                                                    "The \"public\" schema version of this function was created by a\n"
199                                                    "pre-8.1 install of plpython, and must be removed for pg_upgrade\n"
200                                                    "to complete because it references a now-obsolete \"plpython\"\n"
201                                                    "shared object file.  You can remove the \"public\" schema version\n"
202                                            "of this function by running the following command:\n"
203                                                    "\n"
204                                                  "    DROP FUNCTION public.plpython_call_handler()\n"
205                                                    "\n"
206                                                    "in each affected database:\n"
207                                                    "\n");
208                                 }
209                                 pg_log(PG_WARNING, "    %s\n", active_db->db_name);
210                                 found_public_plpython_handler = true;
211                         }
212                         PQclear(res);
213                 }
214
215                 PQfinish(conn);
216         }
217
218         if (found_public_plpython_handler)
219                 pg_fatal("Remove the problem functions from the old cluster to continue.\n");
220
221         totaltups++;                            /* reserve for pg_upgrade_support */
222
223         /* Allocate what's certainly enough space */
224         os_info.libraries = (char **) pg_malloc(totaltups * sizeof(char *));
225
226         /*
227          * Now remove duplicates across DBs.  This is pretty inefficient code, but
228          * there probably aren't enough entries to matter.
229          */
230         totaltups = 0;
231         os_info.libraries[totaltups++] = pg_strdup(PG_UPGRADE_SUPPORT);
232
233         for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
234         {
235                 PGresult   *res = ress[dbnum];
236                 int                     ntups;
237                 int                     rowno;
238
239                 ntups = PQntuples(res);
240                 for (rowno = 0; rowno < ntups; rowno++)
241                 {
242                         char       *lib = PQgetvalue(res, rowno, 0);
243                         bool            dup = false;
244                         int                     n;
245
246                         for (n = 0; n < totaltups; n++)
247                         {
248                                 if (strcmp(lib, os_info.libraries[n]) == 0)
249                                 {
250                                         dup = true;
251                                         break;
252                                 }
253                         }
254                         if (!dup)
255                                 os_info.libraries[totaltups++] = pg_strdup(lib);
256                 }
257
258                 PQclear(res);
259         }
260
261         os_info.num_libraries = totaltups;
262
263         pg_free(ress);
264 }
265
266
267 /*
268  * check_loadable_libraries()
269  *
270  *      Check that the new cluster contains all required libraries.
271  *      We do this by actually trying to LOAD each one, thereby testing
272  *      compatibility as well as presence.
273  */
274 void
275 check_loadable_libraries(void)
276 {
277         PGconn     *conn = connectToServer(&new_cluster, "template1");
278         int                     libnum;
279         FILE       *script = NULL;
280         bool            found = false;
281         char            output_path[MAXPGPATH];
282
283         prep_status("Checking for presence of required libraries");
284
285         snprintf(output_path, sizeof(output_path), "loadable_libraries.txt");
286
287         for (libnum = 0; libnum < os_info.num_libraries; libnum++)
288         {
289                 char       *lib = os_info.libraries[libnum];
290                 int                     llen = strlen(lib);
291                 char            cmd[7 + 2 * MAXPGPATH + 1];
292                 PGresult   *res;
293
294                 /*
295                  * In Postgres 9.0, Python 3 support was added, and to do that, a
296                  * plpython2u language was created with library name plpython2.so as a
297                  * symbolic link to plpython.so.  In Postgres 9.1, only the
298                  * plpython2.so library was created, and both plpythonu and plpython2u
299                  * pointing to it.  For this reason, any reference to library name
300                  * "plpython" in an old PG <= 9.1 cluster must look for "plpython2" in
301                  * the new cluster.
302                  *
303                  * For this case, we could check pg_pltemplate, but that only works
304                  * for languages, and does not help with function shared objects, so
305                  * we just do a general fix.
306                  */
307                 if (GET_MAJOR_VERSION(old_cluster.major_version) < 901 &&
308                         strcmp(lib, "$libdir/plpython") == 0)
309                 {
310                         lib = "$libdir/plpython2";
311                         llen = strlen(lib);
312                 }
313
314                 strcpy(cmd, "LOAD '");
315                 PQescapeStringConn(conn, cmd + strlen(cmd), lib, llen, NULL);
316                 strcat(cmd, "'");
317
318                 res = PQexec(conn, cmd);
319
320                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
321                 {
322                         found = true;
323
324                         /* exit and report missing support library with special message */
325                         if (strcmp(lib, PG_UPGRADE_SUPPORT) == 0)
326                                 pg_fatal("The pg_upgrade_support module must be created and installed in the new cluster.\n");
327
328                         if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
329                                 pg_fatal("Could not open file \"%s\": %s\n",
330                                                  output_path, getErrorText(errno));
331                         fprintf(script, "Could not load library \"%s\"\n%s\n",
332                                         lib,
333                                         PQerrorMessage(conn));
334                 }
335
336                 PQclear(res);
337         }
338
339         PQfinish(conn);
340
341         if (found)
342         {
343                 fclose(script);
344                 pg_log(PG_REPORT, "fatal\n");
345                 pg_fatal("Your installation references loadable libraries that are missing from the\n"
346                                  "new installation.  You can add these libraries to the new installation,\n"
347                                  "or remove the functions using them from the old installation.  A list of\n"
348                                  "problem libraries is in the file:\n"
349                                  "    %s\n\n", output_path);
350         }
351         else
352                 check_ok();
353 }