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