]> granicus.if.org Git - postgresql/blob - contrib/pg_upgrade/function.c
267f29143db34b3d404e34f9b05598e5953bc777
[postgresql] / contrib / pg_upgrade / function.c
1 /*
2  *      function.c
3  *
4  *      server-side function support
5  *
6  *      Copyright (c) 2010-2012, PostgreSQL Global Development Group
7  *      contrib/pg_upgrade/function.c
8  */
9
10 #include "postgres.h"
11
12 #include "pg_upgrade.h"
13
14 #include "access/transam.h"
15
16
17 /*
18  * install_support_functions_in_new_db()
19  *
20  * pg_upgrade requires some support functions that enable it to modify
21  * backend behavior.
22  */
23 void
24 install_support_functions_in_new_db(const char *db_name)
25 {
26         PGconn     *conn = connectToServer(&new_cluster, db_name);
27
28         /* suppress NOTICE of dropped objects */
29         PQclear(executeQueryOrDie(conn,
30                                                           "SET client_min_messages = warning;"));
31         PQclear(executeQueryOrDie(conn,
32                                                    "DROP SCHEMA IF EXISTS binary_upgrade CASCADE;"));
33         PQclear(executeQueryOrDie(conn,
34                                                           "RESET client_min_messages;"));
35
36         PQclear(executeQueryOrDie(conn,
37                                                           "CREATE SCHEMA binary_upgrade;"));
38
39         PQclear(executeQueryOrDie(conn,
40                                                           "CREATE OR REPLACE FUNCTION "
41                                                           "binary_upgrade.set_next_pg_type_oid(OID) "
42                                                           "RETURNS VOID "
43                                                           "AS '$libdir/pg_upgrade_support' "
44                                                           "LANGUAGE C STRICT;"));
45         PQclear(executeQueryOrDie(conn,
46                                                           "CREATE OR REPLACE FUNCTION "
47                                                         "binary_upgrade.set_next_array_pg_type_oid(OID) "
48                                                           "RETURNS VOID "
49                                                           "AS '$libdir/pg_upgrade_support' "
50                                                           "LANGUAGE C STRICT;"));
51         PQclear(executeQueryOrDie(conn,
52                                                           "CREATE OR REPLACE FUNCTION "
53                                                         "binary_upgrade.set_next_toast_pg_type_oid(OID) "
54                                                           "RETURNS VOID "
55                                                           "AS '$libdir/pg_upgrade_support' "
56                                                           "LANGUAGE C STRICT;"));
57         PQclear(executeQueryOrDie(conn,
58                                                           "CREATE OR REPLACE FUNCTION "
59                                                         "binary_upgrade.set_next_heap_pg_class_oid(OID) "
60                                                           "RETURNS VOID "
61                                                           "AS '$libdir/pg_upgrade_support' "
62                                                           "LANGUAGE C STRICT;"));
63         PQclear(executeQueryOrDie(conn,
64                                                           "CREATE OR REPLACE FUNCTION "
65                                                    "binary_upgrade.set_next_index_pg_class_oid(OID) "
66                                                           "RETURNS VOID "
67                                                           "AS '$libdir/pg_upgrade_support' "
68                                                           "LANGUAGE C STRICT;"));
69         PQclear(executeQueryOrDie(conn,
70                                                           "CREATE OR REPLACE FUNCTION "
71                                                    "binary_upgrade.set_next_toast_pg_class_oid(OID) "
72                                                           "RETURNS VOID "
73                                                           "AS '$libdir/pg_upgrade_support' "
74                                                           "LANGUAGE C STRICT;"));
75         PQclear(executeQueryOrDie(conn,
76                                                           "CREATE OR REPLACE FUNCTION "
77                                                           "binary_upgrade.set_next_pg_enum_oid(OID) "
78                                                           "RETURNS VOID "
79                                                           "AS '$libdir/pg_upgrade_support' "
80                                                           "LANGUAGE C STRICT;"));
81         PQclear(executeQueryOrDie(conn,
82                                                           "CREATE OR REPLACE FUNCTION "
83                                                           "binary_upgrade.set_next_pg_authid_oid(OID) "
84                                                           "RETURNS VOID "
85                                                           "AS '$libdir/pg_upgrade_support' "
86                                                           "LANGUAGE C STRICT;"));
87         PQclear(executeQueryOrDie(conn,
88                                                           "CREATE OR REPLACE FUNCTION "
89                                                           "binary_upgrade.create_empty_extension(text, text, bool, text, oid[], text[], text[]) "
90                                                           "RETURNS VOID "
91                                                           "AS '$libdir/pg_upgrade_support' "
92                                                           "LANGUAGE C;"));
93         PQfinish(conn);
94 }
95
96
97 void
98 uninstall_support_functions_from_new_cluster(void)
99 {
100         int                     dbnum;
101
102         prep_status("Removing support functions from new cluster");
103
104         for (dbnum = 0; dbnum < new_cluster.dbarr.ndbs; dbnum++)
105         {
106                 DbInfo     *new_db = &new_cluster.dbarr.dbs[dbnum];
107                 PGconn     *conn = connectToServer(&new_cluster, new_db->db_name);
108
109                 /* suppress NOTICE of dropped objects */
110                 PQclear(executeQueryOrDie(conn,
111                                                                   "SET client_min_messages = warning;"));
112                 PQclear(executeQueryOrDie(conn,
113                                                                   "DROP SCHEMA binary_upgrade CASCADE;"));
114                 PQclear(executeQueryOrDie(conn,
115                                                                   "RESET client_min_messages;"));
116                 PQfinish(conn);
117         }
118         check_ok();
119 }
120
121
122 /*
123  * get_loadable_libraries()
124  *
125  *      Fetch the names of all old libraries containing C-language functions.
126  *      We will later check that they all exist in the new installation.
127  */
128 void
129 get_loadable_libraries(void)
130 {
131         PGresult  **ress;
132         int                     totaltups;
133         int                     dbnum;
134
135         ress = (PGresult **) pg_malloc(old_cluster.dbarr.ndbs * sizeof(PGresult *));
136         totaltups = 0;
137
138         /* Fetch all library names, removing duplicates within each DB */
139         for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
140         {
141                 DbInfo     *active_db = &old_cluster.dbarr.dbs[dbnum];
142                 PGconn     *conn = connectToServer(&old_cluster, active_db->db_name);
143
144                 /* Fetch all libraries referenced in this DB */
145                 ress[dbnum] = executeQueryOrDie(conn,
146                                                                                 "SELECT DISTINCT probin "
147                                                                                 "FROM   pg_catalog.pg_proc "
148                                                                                 "WHERE  prolang = 13 /* C */ AND "
149                                                                                 "probin IS NOT NULL AND "
150                                                                                 "oid >= %u;",
151                                                                                 FirstNormalObjectId);
152                 totaltups += PQntuples(ress[dbnum]);
153
154                 PQfinish(conn);
155         }
156
157         /* Allocate what's certainly enough space */
158         if (totaltups > 0)
159                 os_info.libraries = (char **) pg_malloc(totaltups * sizeof(char *));
160         else
161                 os_info.libraries = NULL;
162
163         /*
164          * Now remove duplicates across DBs.  This is pretty inefficient code, but
165          * there probably aren't enough entries to matter.
166          */
167         totaltups = 0;
168
169         for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
170         {
171                 PGresult   *res = ress[dbnum];
172                 int                     ntups;
173                 int                     rowno;
174
175                 ntups = PQntuples(res);
176                 for (rowno = 0; rowno < ntups; rowno++)
177                 {
178                         char       *lib = PQgetvalue(res, rowno, 0);
179                         bool            dup = false;
180                         int                     n;
181
182                         for (n = 0; n < totaltups; n++)
183                         {
184                                 if (strcmp(lib, os_info.libraries[n]) == 0)
185                                 {
186                                         dup = true;
187                                         break;
188                                 }
189                         }
190                         if (!dup)
191                                 os_info.libraries[totaltups++] = pg_strdup(lib);
192                 }
193
194                 PQclear(res);
195         }
196
197         os_info.num_libraries = totaltups;
198
199         pg_free(ress);
200 }
201
202
203 /*
204  * check_loadable_libraries()
205  *
206  *      Check that the new cluster contains all required libraries.
207  *      We do this by actually trying to LOAD each one, thereby testing
208  *      compatibility as well as presence.
209  */
210 void
211 check_loadable_libraries(void)
212 {
213         PGconn     *conn = connectToServer(&new_cluster, "template1");
214         int                     libnum;
215         FILE       *script = NULL;
216         bool            found = false;
217         char            output_path[MAXPGPATH];
218
219         prep_status("Checking for presence of required libraries");
220
221         snprintf(output_path, sizeof(output_path), "%s/loadable_libraries.txt",
222                          os_info.cwd);
223
224         for (libnum = 0; libnum < os_info.num_libraries; libnum++)
225         {
226                 char       *lib = os_info.libraries[libnum];
227                 int                     llen = strlen(lib);
228                 char            cmd[7 + 2 * MAXPGPATH + 1];
229                 PGresult   *res;
230
231                 /*
232                  *      In Postgres 9.0, Python 3 support was added, and to do that, a
233                  *      plpython2u language was created with library name plpython2.so
234                  *      as a symbolic link to plpython.so.  In Postgres 9.1, only the
235                  *      plpython2.so library was created, and both plpythonu and
236                  *      plpython2u pointing to it.  For this reason, any reference to
237                  *      library name "plpython" in an old PG <= 9.1 cluster must look
238                  *      for "plpython2" in the new cluster.
239                  *
240                  *      For this case, we could check pg_pltemplate, but that only works
241                  *      for languages, and does not help with function shared objects,
242                  *      so we just do a general fix.
243                  */
244                 if (GET_MAJOR_VERSION(old_cluster.major_version) < 901 &&
245                         strcmp(lib, "$libdir/plpython") == 0)
246                 {
247                         lib = "$libdir/plpython2";
248                         llen = strlen(lib);
249                 }
250
251                 strcpy(cmd, "LOAD '");
252                 PQescapeStringConn(conn, cmd + strlen(cmd), lib, llen, NULL);
253                 strcat(cmd, "'");
254
255                 res = PQexec(conn, cmd);
256
257                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
258                 {
259                         found = true;
260                         if (script == NULL && (script = fopen(output_path, "w")) == NULL)
261                                 pg_log(PG_FATAL, "Could not open file \"%s\": %s\n",
262                                            output_path, getErrorText(errno));
263                         fprintf(script, "Could not load library \"%s\"\n%s\n",
264                                         lib,
265                                         PQerrorMessage(conn));
266                 }
267
268                 PQclear(res);
269         }
270
271         PQfinish(conn);
272
273         if (found)
274         {
275                 fclose(script);
276                 pg_log(PG_REPORT, "fatal\n");
277                 pg_log(PG_FATAL,
278                            "Your installation references loadable libraries that are missing from the\n"
279                            "new installation.  You can add these libraries to the new installation,\n"
280                            "or remove the functions using them from the old installation.  A list of\n"
281                            "problem libraries is in the file:\n"
282                            "    %s\n\n", output_path);
283         }
284         else
285                 check_ok();
286 }