1 | /* |
2 | Copyright (c) 2006, 2013, Oracle and/or its affiliates. |
3 | Copyright (c) 2010, 2017, MariaDB |
4 | |
5 | This program is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published by |
7 | the Free Software Foundation; version 2 of the License. |
8 | |
9 | This program is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License |
15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ |
18 | |
19 | #include "client_priv.h" |
20 | #include <sslopt-vars.h> |
21 | #include "../scripts/mysql_fix_privilege_tables_sql.c" |
22 | |
23 | #include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */ |
24 | |
25 | #define VER "1.4" |
26 | |
27 | #ifdef HAVE_SYS_WAIT_H |
28 | #include <sys/wait.h> |
29 | #endif |
30 | |
31 | #ifndef WEXITSTATUS |
32 | # ifdef __WIN__ |
33 | # define WEXITSTATUS(stat_val) (stat_val) |
34 | # else |
35 | # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) |
36 | # endif |
37 | #endif |
38 | |
39 | static int phase = 0; |
40 | static const int phases_total = 7; |
41 | static char mysql_path[FN_REFLEN]; |
42 | static char mysqlcheck_path[FN_REFLEN]; |
43 | |
44 | static my_bool opt_force, opt_verbose, debug_info_flag, debug_check_flag, |
45 | opt_systables_only, opt_version_check; |
46 | static my_bool opt_not_used, opt_silent; |
47 | static uint my_end_arg= 0; |
48 | static char *opt_user= (char*)"root" ; |
49 | |
50 | static my_bool upgrade_from_mysql; |
51 | |
52 | static DYNAMIC_STRING ds_args; |
53 | static DYNAMIC_STRING conn_args; |
54 | |
55 | static char *opt_password= 0; |
56 | static char *opt_plugin_dir= 0, *opt_default_auth= 0; |
57 | |
58 | static char *cnf_file_path= 0, defaults_file[FN_REFLEN + 32]; |
59 | |
60 | static my_bool tty_password= 0; |
61 | |
62 | static char opt_tmpdir[FN_REFLEN] = "" ; |
63 | |
64 | #ifndef DBUG_OFF |
65 | static char *default_dbug_option= (char*) "d:t:O,/tmp/mysql_upgrade.trace" ; |
66 | #endif |
67 | |
68 | static char **defaults_argv; |
69 | |
70 | static my_bool not_used; /* Can't use GET_BOOL without a value pointer */ |
71 | |
72 | char upgrade_from_version[sizeof("10.20.456-MariaDB" )+1]; |
73 | |
74 | static my_bool opt_write_binlog; |
75 | |
76 | #define OPT_SILENT OPT_MAX_CLIENT_OPTION |
77 | |
78 | static struct my_option my_long_options[]= |
79 | { |
80 | {"help" , '?', "Display this help message and exit." , 0, 0, 0, GET_NO_ARG, |
81 | NO_ARG, 0, 0, 0, 0, 0, 0}, |
82 | {"basedir" , 'b', |
83 | "Not used by mysql_upgrade. Only for backward compatibility." , |
84 | 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
85 | {"character-sets-dir" , OPT_CHARSETS_DIR, |
86 | "Not used by mysql_upgrade. Only for backward compatibility." , |
87 | 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, |
88 | {"compress" , OPT_COMPRESS, |
89 | "Not used by mysql_upgrade. Only for backward compatibility." , |
90 | ¬_used, ¬_used, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
91 | {"datadir" , 'd', |
92 | "Not used by mysql_upgrade. Only for backward compatibility." , |
93 | 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
94 | #ifdef DBUG_OFF |
95 | {"debug" , '#', "This is a non-debug version. Catch this and exit." , |
96 | 0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, |
97 | #else |
98 | {"debug" , '#', "Output debug log." , &default_dbug_option, |
99 | &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, |
100 | #endif |
101 | {"debug-check" , OPT_DEBUG_CHECK, "Check memory and open file usage at exit." , |
102 | &debug_check_flag, &debug_check_flag, |
103 | 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
104 | {"debug-info" , 'T', "Print some debug info at exit." , &debug_info_flag, |
105 | &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
106 | {"default-character-set" , OPT_DEFAULT_CHARSET, |
107 | "Not used by mysql_upgrade. Only for backward compatibility." , |
108 | 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
109 | {"default_auth" , OPT_DEFAULT_AUTH, |
110 | "Default authentication client-side plugin to use." , |
111 | &opt_default_auth, &opt_default_auth, 0, |
112 | GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
113 | {"force" , 'f', "Force execution of mysqlcheck even if mysql_upgrade " |
114 | "has already been executed for the current version of MySQL." , |
115 | &opt_force, &opt_force, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
116 | {"host" , 'h', "Connect to host." , 0, |
117 | 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
118 | #define PASSWORD_OPT 12 |
119 | {"password" , 'p', |
120 | "Password to use when connecting to server. If password is not given," |
121 | " it's solicited on the tty." , &opt_password,&opt_password, |
122 | 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, |
123 | #ifdef __WIN__ |
124 | {"pipe" , 'W', "Use named pipes to connect to server." , 0, 0, 0, |
125 | GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
126 | #endif |
127 | {"plugin_dir" , OPT_PLUGIN_DIR, "Directory for client-side plugins." , |
128 | &opt_plugin_dir, &opt_plugin_dir, 0, |
129 | GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
130 | {"port" , 'P', "Port number to use for connection or 0 for default to, in " |
131 | "order of preference, my.cnf, $MYSQL_TCP_PORT, " |
132 | #if MYSQL_PORT_DEFAULT == 0 |
133 | "/etc/services, " |
134 | #endif |
135 | "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ")." , |
136 | 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
137 | {"protocol" , OPT_MYSQL_PROTOCOL, |
138 | "The protocol to use for connection (tcp, socket, pipe, memory)." , |
139 | 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
140 | #ifdef HAVE_SMEM |
141 | {"shared-memory-base-name" , OPT_SHARED_MEMORY_BASE_NAME, |
142 | "Base name of shared memory." , 0, |
143 | 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
144 | #endif |
145 | {"silent" , OPT_SILENT, "Print less information" , &opt_silent, |
146 | &opt_silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
147 | {"socket" , 'S', "The socket file to use for connection." , |
148 | 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
149 | #include <sslopt-longopts.h> |
150 | {"tmpdir" , 't', "Directory for temporary files." , |
151 | 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
152 | {"upgrade-system-tables" , 's', "Only upgrade the system tables in the mysql database. Tables in other databases are not checked or touched." , |
153 | &opt_systables_only, &opt_systables_only, 0, |
154 | GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
155 | #define USER_OPT (array_elements(my_long_options) - 6) |
156 | {"user" , 'u', "User for login if not current user." , &opt_user, |
157 | &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
158 | {"verbose" , 'v', "Display more output about the process; Using it twice will print connection argument; Using it 3 times will print out all CHECK, RENAME and ALTER TABLE during the check phase." , |
159 | &opt_not_used, &opt_not_used, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, |
160 | {"version" , 'V', "Output version information and exit." , 0, 0, 0, |
161 | GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
162 | {"version-check" , 'k', |
163 | "Run this program only if its \'server version\' " |
164 | "matches the version of the server to which it's connecting. " |
165 | "Note: the \'server version\' of the program is the version of the MariaDB " |
166 | "server with which it was built/distributed." , |
167 | &opt_version_check, &opt_version_check, 0, |
168 | GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, |
169 | {"write-binlog" , OPT_WRITE_BINLOG, "All commands including those " |
170 | "issued by mysqlcheck are written to the binary log." , |
171 | &opt_write_binlog, &opt_write_binlog, 0, GET_BOOL, NO_ARG, |
172 | 0, 0, 0, 0, 0, 0}, |
173 | {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} |
174 | }; |
175 | |
176 | |
177 | static const char *load_default_groups[]= |
178 | { |
179 | "client" , /* Read settings how to connect to server */ |
180 | "mysql_upgrade" , /* Read special settings for mysql_upgrade */ |
181 | "client-server" , /* Reads settings common between client & server */ |
182 | "client-mariadb" , /* Read mariadb unique client settings */ |
183 | 0 |
184 | }; |
185 | |
186 | static void free_used_memory(void) |
187 | { |
188 | /* Free memory allocated by 'load_defaults' */ |
189 | if (defaults_argv) |
190 | free_defaults(defaults_argv); |
191 | |
192 | dynstr_free(&ds_args); |
193 | dynstr_free(&conn_args); |
194 | if (cnf_file_path) |
195 | my_delete(cnf_file_path, MYF(MY_WME)); |
196 | } |
197 | |
198 | |
199 | static void die(const char *fmt, ...) |
200 | { |
201 | va_list args; |
202 | DBUG_ENTER("die" ); |
203 | |
204 | /* Print the error message */ |
205 | fflush(stdout); |
206 | va_start(args, fmt); |
207 | if (fmt) |
208 | { |
209 | fprintf(stderr, "FATAL ERROR: " ); |
210 | vfprintf(stderr, fmt, args); |
211 | fprintf(stderr, "\n" ); |
212 | fflush(stderr); |
213 | } |
214 | va_end(args); |
215 | |
216 | free_used_memory(); |
217 | my_end(my_end_arg); |
218 | exit(1); |
219 | } |
220 | |
221 | |
222 | static void verbose(const char *fmt, ...) |
223 | { |
224 | va_list args; |
225 | |
226 | if (opt_silent) |
227 | return; |
228 | |
229 | /* Print the verbose message */ |
230 | va_start(args, fmt); |
231 | if (fmt) |
232 | { |
233 | vfprintf(stdout, fmt, args); |
234 | fprintf(stdout, "\n" ); |
235 | fflush(stdout); |
236 | } |
237 | va_end(args); |
238 | } |
239 | |
240 | |
241 | /* |
242 | Add one option - passed to mysql_upgrade on command line |
243 | or by defaults file(my.cnf) - to a dynamic string, in |
244 | this way we pass the same arguments on to mysql and mysql_check |
245 | */ |
246 | |
247 | static void add_one_option_cmd_line(DYNAMIC_STRING *ds, |
248 | const struct my_option *opt, |
249 | const char* arg) |
250 | { |
251 | dynstr_append(ds, "--" ); |
252 | dynstr_append(ds, opt->name); |
253 | if (arg) |
254 | { |
255 | dynstr_append(ds, "=" ); |
256 | dynstr_append_os_quoted(ds, arg, NullS); |
257 | } |
258 | dynstr_append(ds, " " ); |
259 | } |
260 | |
261 | static void add_one_option_cnf_file(DYNAMIC_STRING *ds, |
262 | const struct my_option *opt, |
263 | const char* arg) |
264 | { |
265 | dynstr_append(ds, opt->name); |
266 | if (arg) |
267 | { |
268 | dynstr_append(ds, "=" ); |
269 | dynstr_append_os_quoted(ds, arg, NullS); |
270 | } |
271 | dynstr_append(ds, "\n" ); |
272 | } |
273 | |
274 | static my_bool |
275 | get_one_option(int optid, const struct my_option *opt, |
276 | char *argument) |
277 | { |
278 | my_bool add_option= TRUE; |
279 | |
280 | switch (optid) { |
281 | |
282 | case '?': |
283 | printf("%s Ver %s Distrib %s, for %s (%s)\n" , |
284 | my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); |
285 | puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000" )); |
286 | puts("MariaDB utility for upgrading databases to new MariaDB versions." ); |
287 | print_defaults("my" , load_default_groups); |
288 | puts("" ); |
289 | my_print_help(my_long_options); |
290 | my_print_variables(my_long_options); |
291 | die(0); |
292 | break; |
293 | |
294 | case '#': |
295 | DBUG_PUSH(argument ? argument : default_dbug_option); |
296 | add_option= FALSE; |
297 | debug_check_flag= 1; |
298 | break; |
299 | |
300 | case 'p': |
301 | if (argument == disabled_my_option) |
302 | argument= (char*) "" ; /* Don't require password */ |
303 | add_option= FALSE; |
304 | if (argument) |
305 | { |
306 | /* Add password to ds_args before overwriting the arg with x's */ |
307 | add_one_option_cnf_file(&ds_args, opt, argument); |
308 | while (*argument) |
309 | *argument++= 'x'; /* Destroy argument */ |
310 | tty_password= 0; |
311 | } |
312 | else |
313 | tty_password= 1; |
314 | break; |
315 | |
316 | case 't': |
317 | strnmov(opt_tmpdir, argument, sizeof(opt_tmpdir)); |
318 | add_option= FALSE; |
319 | break; |
320 | |
321 | case 'b': /* --basedir */ |
322 | case 'd': /* --datadir */ |
323 | fprintf(stderr, "%s: the '--%s' option is always ignored\n" , |
324 | my_progname, optid == 'b' ? "basedir" : "datadir" ); |
325 | /* FALLTHROUGH */ |
326 | |
327 | case 'k': /* --version-check */ |
328 | case 'v': /* --verbose */ |
329 | opt_verbose++; |
330 | if (argument == disabled_my_option) |
331 | { |
332 | opt_verbose= 0; |
333 | opt_silent= 1; |
334 | } |
335 | add_option= 0; |
336 | break; |
337 | case 'V': |
338 | printf("%s Ver %s Distrib %s, for %s (%s)\n" , |
339 | my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); |
340 | die(0); |
341 | break; |
342 | case OPT_SILENT: |
343 | opt_verbose= 0; |
344 | add_option= 0; |
345 | break; |
346 | case 'f': /* --force */ |
347 | case 's': /* --upgrade-system-tables */ |
348 | case OPT_WRITE_BINLOG: /* --write-binlog */ |
349 | add_option= FALSE; |
350 | break; |
351 | |
352 | case 'h': /* --host */ |
353 | case 'W': /* --pipe */ |
354 | case 'P': /* --port */ |
355 | case 'S': /* --socket */ |
356 | case OPT_MYSQL_PROTOCOL: /* --protocol */ |
357 | case OPT_SHARED_MEMORY_BASE_NAME: /* --shared-memory-base-name */ |
358 | case OPT_PLUGIN_DIR: /* --plugin-dir */ |
359 | case OPT_DEFAULT_AUTH: /* --default-auth */ |
360 | add_one_option_cmd_line(&conn_args, opt, argument); |
361 | break; |
362 | } |
363 | |
364 | if (add_option) |
365 | { |
366 | /* |
367 | This is an option that is accepted by mysql_upgrade just so |
368 | it can be passed on to "mysql" and "mysqlcheck" |
369 | Save it in the ds_args string |
370 | */ |
371 | add_one_option_cnf_file(&ds_args, opt, argument); |
372 | } |
373 | return 0; |
374 | } |
375 | |
376 | |
377 | /** |
378 | Run a command using the shell, storing its output in the supplied dynamic |
379 | string. |
380 | */ |
381 | static int run_command(char* cmd, |
382 | DYNAMIC_STRING *ds_res) |
383 | { |
384 | char buf[512]= {0}; |
385 | FILE *res_file; |
386 | int error; |
387 | |
388 | if (opt_verbose >= 4) |
389 | puts(cmd); |
390 | |
391 | if (!(res_file= popen(cmd, "r" ))) |
392 | die("popen(\"%s\", \"r\") failed" , cmd); |
393 | |
394 | while (fgets(buf, sizeof(buf), res_file)) |
395 | { |
396 | DBUG_PRINT("info" , ("buf: %s" , buf)); |
397 | if(ds_res) |
398 | { |
399 | /* Save the output of this command in the supplied string */ |
400 | dynstr_append(ds_res, buf); |
401 | } |
402 | else |
403 | { |
404 | /* Print it directly on screen */ |
405 | fprintf(stdout, "%s" , buf); |
406 | } |
407 | } |
408 | |
409 | error= pclose(res_file); |
410 | return WEXITSTATUS(error); |
411 | } |
412 | |
413 | |
414 | static int run_tool(char *tool_path, DYNAMIC_STRING *ds_res, ...) |
415 | { |
416 | int ret; |
417 | const char* arg; |
418 | va_list args; |
419 | DYNAMIC_STRING ds_cmdline; |
420 | |
421 | DBUG_ENTER("run_tool" ); |
422 | DBUG_PRINT("enter" , ("tool_path: %s" , tool_path)); |
423 | |
424 | if (init_dynamic_string(&ds_cmdline, IF_WIN("\"" , "" ), FN_REFLEN, FN_REFLEN)) |
425 | die("Out of memory" ); |
426 | |
427 | dynstr_append_os_quoted(&ds_cmdline, tool_path, NullS); |
428 | dynstr_append(&ds_cmdline, " " ); |
429 | |
430 | va_start(args, ds_res); |
431 | |
432 | while ((arg= va_arg(args, char *))) |
433 | { |
434 | /* Options should already be os quoted */ |
435 | dynstr_append(&ds_cmdline, arg); |
436 | dynstr_append(&ds_cmdline, " " ); |
437 | } |
438 | |
439 | va_end(args); |
440 | |
441 | #ifdef __WIN__ |
442 | dynstr_append(&ds_cmdline, "\"" ); |
443 | #endif |
444 | |
445 | DBUG_PRINT("info" , ("Running: %s" , ds_cmdline.str)); |
446 | ret= run_command(ds_cmdline.str, ds_res); |
447 | DBUG_PRINT("exit" , ("ret: %d" , ret)); |
448 | dynstr_free(&ds_cmdline); |
449 | DBUG_RETURN(ret); |
450 | } |
451 | |
452 | |
453 | /** |
454 | Look for the filename of given tool, with the presumption that it is in the |
455 | same directory as mysql_upgrade and that the same executable-searching |
456 | mechanism will be used when we run our sub-shells with popen() later. |
457 | */ |
458 | static void find_tool(char *tool_executable_name, const char *tool_name, |
459 | const char *self_name) |
460 | { |
461 | char *last_fn_libchar; |
462 | DYNAMIC_STRING ds_tmp; |
463 | DBUG_ENTER("find_tool" ); |
464 | DBUG_PRINT("enter" , ("progname: %s" , my_progname)); |
465 | |
466 | if (init_dynamic_string(&ds_tmp, "" , 32, 32)) |
467 | die("Out of memory" ); |
468 | |
469 | last_fn_libchar= strrchr(self_name, FN_LIBCHAR); |
470 | |
471 | if (last_fn_libchar == NULL) |
472 | { |
473 | /* |
474 | mysql_upgrade was found by the shell searching the path. A sibling |
475 | next to us should be found the same way. |
476 | */ |
477 | strncpy(tool_executable_name, tool_name, FN_REFLEN); |
478 | } |
479 | else |
480 | { |
481 | int len; |
482 | |
483 | /* |
484 | mysql_upgrade was run absolutely or relatively. We can find a sibling |
485 | by replacing our name after the LIBCHAR with the new tool name. |
486 | */ |
487 | |
488 | /* |
489 | When running in a not yet installed build and using libtool, |
490 | the program(mysql_upgrade) will be in .libs/ and executed |
491 | through a libtool wrapper in order to use the dynamic libraries |
492 | from this build. The same must be done for the tools(mysql and |
493 | mysqlcheck). Thus if path ends in .libs/, step up one directory |
494 | and execute the tools from there |
495 | */ |
496 | if (((last_fn_libchar - 6) >= self_name) && |
497 | (strncmp(last_fn_libchar - 5, ".libs" , 5) == 0) && |
498 | (*(last_fn_libchar - 6) == FN_LIBCHAR)) |
499 | { |
500 | DBUG_PRINT("info" , ("Chopping off \".libs\" from end of path" )); |
501 | last_fn_libchar -= 6; |
502 | } |
503 | |
504 | len= (int)(last_fn_libchar - self_name); |
505 | |
506 | my_snprintf(tool_executable_name, FN_REFLEN, "%.*s%c%s" , |
507 | len, self_name, FN_LIBCHAR, tool_name); |
508 | } |
509 | |
510 | if (opt_verbose) |
511 | verbose("Looking for '%s' as: %s" , tool_name, tool_executable_name); |
512 | |
513 | /* |
514 | Make sure it can be executed |
515 | */ |
516 | if (run_tool(tool_executable_name, |
517 | &ds_tmp, /* Get output from command, discard*/ |
518 | "--no-defaults" , |
519 | "--help" , |
520 | "2>&1" , |
521 | IF_WIN("> NUL" , "> /dev/null" ), |
522 | NULL)) |
523 | die("Can't execute '%s'" , tool_executable_name); |
524 | |
525 | dynstr_free(&ds_tmp); |
526 | |
527 | DBUG_VOID_RETURN; |
528 | } |
529 | |
530 | |
531 | /* |
532 | Run query using "mysql" |
533 | */ |
534 | |
535 | static int run_query(const char *query, DYNAMIC_STRING *ds_res, |
536 | my_bool force) |
537 | { |
538 | int ret; |
539 | File fd; |
540 | char query_file_path[FN_REFLEN]; |
541 | #ifdef WITH_WSREP |
542 | /* |
543 | Strictly speaking, WITH_WSREP on the client only means that the |
544 | client was compiled with WSREP, it doesn't mean the server was, |
545 | so the server might not have WSREP_ON variable. |
546 | |
547 | But mysql_upgrade is tightly bound to a specific server version |
548 | anyway - it was mysql_fix_privilege_tables_sql script embedded |
549 | into its binary - so even if it won't assume anything about server |
550 | wsrep-ness, it won't be any less server-dependent. |
551 | */ |
552 | const uchar sql_log_bin[]= "SET SQL_LOG_BIN=0, WSREP_ON=OFF;" ; |
553 | #else |
554 | const uchar sql_log_bin[]= "SET SQL_LOG_BIN=0;" ; |
555 | #endif /* WITH_WSREP */ |
556 | |
557 | DBUG_ENTER("run_query" ); |
558 | DBUG_PRINT("enter" , ("query: %s" , query)); |
559 | if ((fd= create_temp_file(query_file_path, |
560 | opt_tmpdir[0] ? opt_tmpdir : NULL, |
561 | "sql" , O_SHARE, MYF(MY_WME))) < 0) |
562 | die("Failed to create temporary file for defaults" ); |
563 | |
564 | /* |
565 | Master and slave should be upgraded separately. All statements executed |
566 | by mysql_upgrade will not be binlogged. |
567 | 'SET SQL_LOG_BIN=0' is executed before any other statements. |
568 | */ |
569 | if (!opt_write_binlog) |
570 | { |
571 | if (my_write(fd, sql_log_bin, sizeof(sql_log_bin)-1, |
572 | MYF(MY_FNABP | MY_WME))) |
573 | { |
574 | my_close(fd, MYF(0)); |
575 | my_delete(query_file_path, MYF(0)); |
576 | die("Failed to write to '%s'" , query_file_path); |
577 | } |
578 | } |
579 | |
580 | if (my_write(fd, (uchar*) query, strlen(query), |
581 | MYF(MY_FNABP | MY_WME))) |
582 | { |
583 | my_close(fd, MYF(0)); |
584 | my_delete(query_file_path, MYF(0)); |
585 | die("Failed to write to '%s'" , query_file_path); |
586 | } |
587 | |
588 | ret= run_tool(mysql_path, |
589 | ds_res, |
590 | defaults_file, |
591 | "--database=mysql" , |
592 | "--batch" , /* Turns off pager etc. */ |
593 | force ? "--force" : "--skip-force" , |
594 | ds_res || opt_silent ? "--silent" : "" , |
595 | "<" , |
596 | query_file_path, |
597 | "2>&1" , |
598 | NULL); |
599 | |
600 | my_close(fd, MYF(0)); |
601 | my_delete(query_file_path, MYF(0)); |
602 | |
603 | DBUG_RETURN(ret); |
604 | } |
605 | |
606 | |
607 | /* |
608 | Extract the value returned from result of "show variable like ..." |
609 | */ |
610 | |
611 | static int (DYNAMIC_STRING* ds, char* value) |
612 | { |
613 | char *value_start, *value_end; |
614 | size_t len; |
615 | |
616 | /* |
617 | The query returns "datadir\t<datadir>\n", skip past |
618 | the tab |
619 | */ |
620 | if ((value_start= strchr(ds->str, '\t')) == NULL) |
621 | return 1; /* Unexpected result */ |
622 | value_start++; |
623 | |
624 | /* Don't copy the ending newline */ |
625 | if ((value_end= strchr(value_start, '\n')) == NULL) |
626 | return 1; /* Unexpected result */ |
627 | |
628 | len= (size_t) MY_MIN(FN_REFLEN, value_end-value_start); |
629 | strncpy(value, value_start, len); |
630 | value[len]= '\0'; |
631 | return 0; |
632 | } |
633 | |
634 | |
635 | static int get_upgrade_info_file_name(char* name) |
636 | { |
637 | DYNAMIC_STRING ds_datadir; |
638 | DBUG_ENTER("get_upgrade_info_file_name" ); |
639 | |
640 | if (init_dynamic_string(&ds_datadir, NULL, 32, 32)) |
641 | die("Out of memory" ); |
642 | |
643 | if (run_query("show variables like 'datadir'" , |
644 | &ds_datadir, FALSE) || |
645 | extract_variable_from_show(&ds_datadir, name)) |
646 | { |
647 | dynstr_free(&ds_datadir); |
648 | DBUG_RETURN(1); /* Query failed */ |
649 | } |
650 | |
651 | dynstr_free(&ds_datadir); |
652 | |
653 | fn_format(name, "mysql_upgrade_info" , name, "" , MYF(0)); |
654 | DBUG_PRINT("exit" , ("name: %s" , name)); |
655 | DBUG_RETURN(0); |
656 | } |
657 | |
658 | |
659 | /* |
660 | Read the content of mysql_upgrade_info file and |
661 | compare the version number form file against |
662 | version number which mysql_upgrade was compiled for |
663 | |
664 | NOTE |
665 | This is an optimization to avoid running mysql_upgrade |
666 | when it's already been performed for the particular |
667 | version of MySQL. |
668 | |
669 | In case the MySQL server can't return the upgrade info |
670 | file it's always better to report that the upgrade hasn't |
671 | been performed. |
672 | |
673 | */ |
674 | |
675 | static int upgrade_already_done(myf flags) |
676 | { |
677 | FILE *in; |
678 | char upgrade_info_file[FN_REFLEN]= {0}; |
679 | |
680 | if (get_upgrade_info_file_name(upgrade_info_file)) |
681 | return 0; /* Could not get filename => not sure */ |
682 | |
683 | if (!(in= my_fopen(upgrade_info_file, O_RDONLY, flags))) |
684 | return 0; /* Could not open file => not sure */ |
685 | |
686 | bzero(upgrade_from_version, sizeof(upgrade_from_version)); |
687 | if (!fgets(upgrade_from_version, sizeof(upgrade_from_version), in)) |
688 | { |
689 | /* Preserve errno for caller */ |
690 | int save_errno= errno; |
691 | (void) my_fclose(in, flags); |
692 | errno= save_errno; |
693 | return 0; |
694 | } |
695 | |
696 | if (my_fclose(in, flags)) |
697 | return 0; |
698 | |
699 | errno= 0; |
700 | return (strncmp(upgrade_from_version, MYSQL_SERVER_VERSION, |
701 | sizeof(MYSQL_SERVER_VERSION)-1)==0); |
702 | } |
703 | |
704 | |
705 | /* |
706 | Write mysql_upgrade_info file in servers data dir indicating that |
707 | upgrade has been done for this version |
708 | |
709 | NOTE |
710 | This might very well fail but since it's just an optimization |
711 | to run mysql_upgrade only when necessary the error can be |
712 | ignored. |
713 | |
714 | */ |
715 | |
716 | static void create_mysql_upgrade_info_file(void) |
717 | { |
718 | FILE *out; |
719 | char upgrade_info_file[FN_REFLEN]= {0}; |
720 | |
721 | if (get_upgrade_info_file_name(upgrade_info_file)) |
722 | return; /* Could not get filename => skip */ |
723 | |
724 | if (!(out= my_fopen(upgrade_info_file, O_TRUNC | O_WRONLY, MYF(0)))) |
725 | { |
726 | fprintf(stderr, |
727 | "Could not create the upgrade info file '%s' in " |
728 | "the MariaDB Servers datadir, errno: %d\n" , |
729 | upgrade_info_file, errno); |
730 | return; |
731 | } |
732 | |
733 | /* Write new version to file */ |
734 | my_fwrite(out, (uchar*) MYSQL_SERVER_VERSION, |
735 | sizeof(MYSQL_SERVER_VERSION), MY_WME); |
736 | my_fclose(out, MYF(MY_WME)); |
737 | |
738 | /* |
739 | Check if the upgrad_info_file was properly created/updated |
740 | It's not a fatal error -> just print a message if it fails |
741 | */ |
742 | if (!upgrade_already_done(MY_WME)) |
743 | fprintf(stderr, |
744 | "Upgrade file '%s' was not properly created. " |
745 | "Got error errno while checking file content: %d\n" , |
746 | upgrade_info_file, errno); |
747 | return; |
748 | } |
749 | |
750 | |
751 | /* |
752 | Print connection-related arguments. |
753 | */ |
754 | |
755 | static void print_conn_args(const char *tool_name) |
756 | { |
757 | if (opt_verbose < 2) |
758 | return; |
759 | if (conn_args.str[0]) |
760 | verbose("Running '%s' with connection arguments: %s" , tool_name, |
761 | conn_args.str); |
762 | else |
763 | verbose("Running '%s with default connection arguments" , tool_name); |
764 | } |
765 | |
766 | /* |
767 | Check and upgrade(if necessary) all tables |
768 | in the server using "mysqlcheck --check-upgrade .." |
769 | */ |
770 | |
771 | static int run_mysqlcheck_upgrade(my_bool mysql_db_only) |
772 | { |
773 | const char *what= mysql_db_only ? "mysql database" : "tables" ; |
774 | const char *arg1= mysql_db_only ? "--databases" : "--all-databases" ; |
775 | const char *arg2= mysql_db_only ? "mysql" : "--skip-database=mysql" ; |
776 | int retch; |
777 | if (opt_systables_only && !mysql_db_only) |
778 | { |
779 | verbose("Phase %d/%d: Checking and upgrading %s... Skipped" , |
780 | ++phase, phases_total, what); |
781 | return 0; |
782 | } |
783 | verbose("Phase %d/%d: Checking and upgrading %s" , ++phase, phases_total, what); |
784 | print_conn_args("mysqlcheck" ); |
785 | retch= run_tool(mysqlcheck_path, |
786 | NULL, /* Send output from mysqlcheck directly to screen */ |
787 | defaults_file, |
788 | "--check-upgrade" , |
789 | "--auto-repair" , |
790 | !opt_silent || opt_verbose >= 1 ? "--verbose" : "" , |
791 | opt_verbose >= 2 ? "--verbose" : "" , |
792 | opt_verbose >= 3 ? "--verbose" : "" , |
793 | opt_silent ? "--silent" : "" , |
794 | opt_write_binlog ? "--write-binlog" : "--skip-write-binlog" , |
795 | arg1, arg2, |
796 | "2>&1" , |
797 | NULL); |
798 | return retch; |
799 | } |
800 | |
801 | #define EVENTS_STRUCT_LEN 7000 |
802 | |
803 | static my_bool is_mysql() |
804 | { |
805 | my_bool ret= TRUE; |
806 | DYNAMIC_STRING ds_events_struct; |
807 | |
808 | if (init_dynamic_string(&ds_events_struct, NULL, |
809 | EVENTS_STRUCT_LEN, EVENTS_STRUCT_LEN)) |
810 | die("Out of memory" ); |
811 | |
812 | if (run_query("show create table mysql.event" , |
813 | &ds_events_struct, FALSE) || |
814 | strstr(ds_events_struct.str, "IGNORE_BAD_TABLE_OPTIONS" ) != NULL) |
815 | ret= FALSE; |
816 | else |
817 | verbose("MySQL upgrade detected" ); |
818 | |
819 | dynstr_free(&ds_events_struct); |
820 | return(ret); |
821 | } |
822 | |
823 | static int run_mysqlcheck_views(void) |
824 | { |
825 | const char *upgrade_views="--process-views=YES" ; |
826 | if (upgrade_from_mysql) |
827 | { |
828 | /* |
829 | this has to ignore opt_systables_only, because upgrade_from_mysql |
830 | is determined by analyzing systables. if we honor opt_systables_only |
831 | here, views won't be fixed by subsequent mysql_upgrade runs |
832 | */ |
833 | upgrade_views="--process-views=UPGRADE_FROM_MYSQL" ; |
834 | verbose("Phase %d/%d: Fixing views from mysql" , ++phase, phases_total); |
835 | } |
836 | else if (opt_systables_only) |
837 | { |
838 | verbose("Phase %d/%d: Fixing views... Skipped" , ++phase, phases_total); |
839 | return 0; |
840 | } |
841 | else |
842 | verbose("Phase %d/%d: Fixing views" , ++phase, phases_total); |
843 | |
844 | print_conn_args("mysqlcheck" ); |
845 | return run_tool(mysqlcheck_path, |
846 | NULL, /* Send output from mysqlcheck directly to screen */ |
847 | defaults_file, |
848 | "--all-databases" , "--repair" , |
849 | upgrade_views, |
850 | "--skip-process-tables" , |
851 | opt_verbose ? "--verbose" : "" , |
852 | opt_silent ? "--silent" : "" , |
853 | opt_write_binlog ? "--write-binlog" : "--skip-write-binlog" , |
854 | "2>&1" , |
855 | NULL); |
856 | } |
857 | |
858 | static int run_mysqlcheck_fixnames(void) |
859 | { |
860 | if (opt_systables_only) |
861 | { |
862 | verbose("Phase %d/%d: Fixing table and database names ... Skipped" , |
863 | ++phase, phases_total); |
864 | return 0; |
865 | } |
866 | verbose("Phase %d/%d: Fixing table and database names" , |
867 | ++phase, phases_total); |
868 | print_conn_args("mysqlcheck" ); |
869 | return run_tool(mysqlcheck_path, |
870 | NULL, /* Send output from mysqlcheck directly to screen */ |
871 | defaults_file, |
872 | "--all-databases" , |
873 | "--fix-db-names" , |
874 | "--fix-table-names" , |
875 | opt_verbose >= 1 ? "--verbose" : "" , |
876 | opt_verbose >= 2 ? "--verbose" : "" , |
877 | opt_verbose >= 3 ? "--verbose" : "" , |
878 | opt_silent ? "--silent" : "" , |
879 | opt_write_binlog ? "--write-binlog" : "--skip-write-binlog" , |
880 | "2>&1" , |
881 | NULL); |
882 | } |
883 | |
884 | |
885 | static const char *expected_errors[]= |
886 | { |
887 | "ERROR 1060" , /* Duplicate column name */ |
888 | "ERROR 1061" , /* Duplicate key name */ |
889 | "ERROR 1054" , /* Unknown column */ |
890 | "ERROR 1290" , /* RR_OPTION_PREVENTS_STATEMENT */ |
891 | 0 |
892 | }; |
893 | |
894 | |
895 | static my_bool is_expected_error(const char* line) |
896 | { |
897 | const char** error= expected_errors; |
898 | while (*error) |
899 | { |
900 | /* |
901 | Check if lines starting with ERROR |
902 | are in the list of expected errors |
903 | */ |
904 | if (strncmp(line, "ERROR" , 5) != 0 || |
905 | strncmp(line, *error, strlen(*error)) == 0) |
906 | return 1; /* Found expected error */ |
907 | error++; |
908 | } |
909 | return 0; |
910 | } |
911 | |
912 | |
913 | static char* get_line(char* line) |
914 | { |
915 | while (*line && *line != '\n') |
916 | line++; |
917 | if (*line) |
918 | line++; |
919 | return line; |
920 | } |
921 | |
922 | |
923 | /* Print the current line to stderr */ |
924 | static void print_line(char* line) |
925 | { |
926 | while (*line && *line != '\n') |
927 | { |
928 | fputc(*line, stderr); |
929 | line++; |
930 | } |
931 | fputc('\n', stderr); |
932 | } |
933 | |
934 | static my_bool from_before_10_1() |
935 | { |
936 | my_bool ret= TRUE; |
937 | DYNAMIC_STRING ds_events_struct; |
938 | |
939 | if (upgrade_from_version[0]) |
940 | { |
941 | return upgrade_from_version[1] == '.' || |
942 | strncmp(upgrade_from_version, "10.1." , 5) < 0; |
943 | } |
944 | |
945 | if (init_dynamic_string(&ds_events_struct, NULL, 2048, 2048)) |
946 | die("Out of memory" ); |
947 | |
948 | if (run_query("show create table mysql.user" , &ds_events_struct, FALSE) || |
949 | strstr(ds_events_struct.str, "default_role" ) != NULL) |
950 | ret= FALSE; |
951 | else |
952 | verbose("Upgrading from a version before MariaDB-10.1" ); |
953 | |
954 | dynstr_free(&ds_events_struct); |
955 | return ret; |
956 | } |
957 | |
958 | |
959 | /* |
960 | Check for entries with "Unknown storage engine" in I_S.TABLES, |
961 | try to load plugins for these tables if available (MDEV-11942) |
962 | */ |
963 | static int install_used_engines(void) |
964 | { |
965 | char buf[512]; |
966 | DYNAMIC_STRING ds_result; |
967 | const char *query = "SELECT DISTINCT LOWER(engine) AS c1 FROM information_schema.tables" |
968 | " WHERE table_comment LIKE 'Unknown storage engine%'" |
969 | " ORDER BY c1" ; |
970 | |
971 | if (opt_systables_only || !from_before_10_1()) |
972 | { |
973 | verbose("Phase %d/%d: Installing used storage engines... Skipped" , ++phase, phases_total); |
974 | return 0; |
975 | } |
976 | verbose("Phase %d/%d: Installing used storage engines" , ++phase, phases_total); |
977 | |
978 | if (init_dynamic_string(&ds_result, "" , 512, 512)) |
979 | die("Out of memory" ); |
980 | |
981 | verbose("Checking for tables with unknown storage engine" ); |
982 | |
983 | run_query(query, &ds_result, TRUE); |
984 | |
985 | if (ds_result.length) |
986 | { |
987 | char *line= ds_result.str, *next=get_line(line); |
988 | do |
989 | { |
990 | if (next[-1] == '\n') |
991 | next[-1]=0; |
992 | |
993 | verbose("installing plugin for '%s' storage engine" , line); |
994 | |
995 | // we simply assume soname=ha_enginename |
996 | strxnmov(buf, sizeof(buf)-1, "install soname 'ha_" , line, "'" , NULL); |
997 | |
998 | |
999 | if (run_query(buf, NULL, TRUE)) |
1000 | fprintf(stderr, "... can't %s\n" , buf); |
1001 | line=next; |
1002 | next=get_line(line); |
1003 | } while (*line); |
1004 | } |
1005 | dynstr_free(&ds_result); |
1006 | return 0; |
1007 | } |
1008 | |
1009 | |
1010 | /* |
1011 | Update all system tables in MySQL Server to current |
1012 | version using "mysql" to execute all the SQL commands |
1013 | compiled into the mysql_fix_privilege_tables array |
1014 | */ |
1015 | |
1016 | static int run_sql_fix_privilege_tables(void) |
1017 | { |
1018 | int found_real_errors= 0; |
1019 | const char **query_ptr; |
1020 | DYNAMIC_STRING ds_script; |
1021 | DYNAMIC_STRING ds_result; |
1022 | DBUG_ENTER("run_sql_fix_privilege_tables" ); |
1023 | |
1024 | if (init_dynamic_string(&ds_script, "" , 65536, 1024)) |
1025 | die("Out of memory" ); |
1026 | |
1027 | if (init_dynamic_string(&ds_result, "" , 512, 512)) |
1028 | die("Out of memory" ); |
1029 | |
1030 | verbose("Phase %d/%d: Running 'mysql_fix_privilege_tables'" , |
1031 | ++phase, phases_total); |
1032 | |
1033 | /* |
1034 | Individual queries can not be executed independently by invoking |
1035 | a forked mysql client, because the script uses session variables |
1036 | and prepared statements. |
1037 | */ |
1038 | for ( query_ptr= &mysql_fix_privilege_tables[0]; |
1039 | *query_ptr != NULL; |
1040 | query_ptr++ |
1041 | ) |
1042 | { |
1043 | if (strcasecmp(*query_ptr, "flush privileges;\n" )) |
1044 | dynstr_append(&ds_script, *query_ptr); |
1045 | } |
1046 | |
1047 | run_query(ds_script.str, |
1048 | &ds_result, /* Collect result */ |
1049 | TRUE); |
1050 | |
1051 | { |
1052 | /* |
1053 | Scan each line of the result for real errors |
1054 | and ignore the expected one(s) like "Duplicate column name", |
1055 | "Unknown column" and "Duplicate key name" since they just |
1056 | indicate the system tables are already up to date |
1057 | */ |
1058 | char *line= ds_result.str; |
1059 | do |
1060 | { |
1061 | if (!is_expected_error(line)) |
1062 | { |
1063 | /* Something unexpected failed, dump error line to screen */ |
1064 | found_real_errors++; |
1065 | print_line(line); |
1066 | } |
1067 | else if (strncmp(line, "WARNING" , 7) == 0) |
1068 | { |
1069 | print_line(line); |
1070 | } |
1071 | } while ((line= get_line(line)) && *line); |
1072 | } |
1073 | |
1074 | dynstr_free(&ds_result); |
1075 | dynstr_free(&ds_script); |
1076 | DBUG_RETURN(found_real_errors); |
1077 | } |
1078 | |
1079 | |
1080 | static void print_error(const char *error_msg, DYNAMIC_STRING *output) |
1081 | { |
1082 | fprintf(stderr, "%s\n" , error_msg); |
1083 | fprintf(stderr, "%s" , output->str); |
1084 | } |
1085 | |
1086 | |
1087 | /* Convert the specified version string into the numeric format. */ |
1088 | static ulong STDCALL calc_server_version(char *some_version) |
1089 | { |
1090 | uint major, minor, version; |
1091 | char *point= some_version, *end_point; |
1092 | major= (uint) strtoul(point, &end_point, 10); point=end_point+1; |
1093 | minor= (uint) strtoul(point, &end_point, 10); point=end_point+1; |
1094 | version= (uint) strtoul(point, &end_point, 10); |
1095 | return (ulong) major * 10000L + (ulong)(minor * 100 + version); |
1096 | } |
1097 | |
1098 | /** |
1099 | Check if the server version matches with the server version mysql_upgrade |
1100 | was compiled with. |
1101 | |
1102 | @return 0 match successful |
1103 | 1 failed |
1104 | */ |
1105 | static int check_version_match(void) |
1106 | { |
1107 | DYNAMIC_STRING ds_version; |
1108 | char version_str[NAME_CHAR_LEN + 1]; |
1109 | |
1110 | if (init_dynamic_string(&ds_version, NULL, NAME_CHAR_LEN, NAME_CHAR_LEN)) |
1111 | die("Out of memory" ); |
1112 | |
1113 | if (run_query("show variables like 'version'" , |
1114 | &ds_version, FALSE) || |
1115 | extract_variable_from_show(&ds_version, version_str)) |
1116 | { |
1117 | print_error("Version check failed. Got the following error when calling " |
1118 | "the 'mysql' command line client" , &ds_version); |
1119 | dynstr_free(&ds_version); |
1120 | return 1; /* Query failed */ |
1121 | } |
1122 | |
1123 | dynstr_free(&ds_version); |
1124 | |
1125 | if (calc_server_version((char *) version_str) != MYSQL_VERSION_ID) |
1126 | { |
1127 | fprintf(stderr, "Error: Server version (%s) does not match with the " |
1128 | "version of\nthe server (%s) with which this program was built/" |
1129 | "distributed. You can\nuse --skip-version-check to skip this " |
1130 | "check.\n" , version_str, MYSQL_SERVER_VERSION); |
1131 | return 1; |
1132 | } |
1133 | else |
1134 | return 0; |
1135 | } |
1136 | |
1137 | |
1138 | int main(int argc, char **argv) |
1139 | { |
1140 | char self_name[FN_REFLEN + 1]; |
1141 | |
1142 | MY_INIT(argv[0]); |
1143 | load_defaults_or_exit("my" , load_default_groups, &argc, &argv); |
1144 | defaults_argv= argv; /* Must be freed by 'free_defaults' */ |
1145 | |
1146 | #if defined(__WIN__) |
1147 | if (GetModuleFileName(NULL, self_name, FN_REFLEN) == 0) |
1148 | #endif |
1149 | { |
1150 | strmake_buf(self_name, argv[0]); |
1151 | } |
1152 | |
1153 | if (init_dynamic_string(&ds_args, "" , 512, 256) || |
1154 | init_dynamic_string(&conn_args, "" , 512, 256)) |
1155 | die("Out of memory" ); |
1156 | |
1157 | if (handle_options(&argc, &argv, my_long_options, get_one_option)) |
1158 | die(NULL); |
1159 | if (debug_info_flag) |
1160 | my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; |
1161 | if (debug_check_flag) |
1162 | my_end_arg= MY_CHECK_ERROR; |
1163 | |
1164 | if (tty_password) |
1165 | { |
1166 | opt_password= get_tty_password(NullS); |
1167 | /* add password to defaults file */ |
1168 | add_one_option_cnf_file(&ds_args, &my_long_options[PASSWORD_OPT], opt_password); |
1169 | DBUG_ASSERT(strcmp(my_long_options[PASSWORD_OPT].name, "password" ) == 0); |
1170 | } |
1171 | /* add user to defaults file */ |
1172 | add_one_option_cnf_file(&ds_args, &my_long_options[USER_OPT], opt_user); |
1173 | DBUG_ASSERT(strcmp(my_long_options[USER_OPT].name, "user" ) == 0); |
1174 | |
1175 | cnf_file_path= strmov(defaults_file, "--defaults-file=" ); |
1176 | { |
1177 | int fd= create_temp_file(cnf_file_path, opt_tmpdir[0] ? opt_tmpdir : NULL, |
1178 | "mysql_upgrade-" , 0, MYF(MY_FAE)); |
1179 | if (fd < 0) |
1180 | die(NULL); |
1181 | my_write(fd, USTRING_WITH_LEN( "[client]\n" ), MYF(MY_FAE)); |
1182 | my_write(fd, (uchar*)ds_args.str, ds_args.length, MYF(MY_FAE)); |
1183 | my_close(fd, MYF(0)); |
1184 | } |
1185 | |
1186 | /* Find mysql */ |
1187 | find_tool(mysql_path, IF_WIN("mysql.exe" , "mysql" ), self_name); |
1188 | |
1189 | /* Find mysqlcheck */ |
1190 | find_tool(mysqlcheck_path, IF_WIN("mysqlcheck.exe" , "mysqlcheck" ), self_name); |
1191 | |
1192 | if (opt_systables_only && !opt_silent) |
1193 | printf("The --upgrade-system-tables option was used, user tables won't be touched.\n" ); |
1194 | |
1195 | /* |
1196 | Read the mysql_upgrade_info file to check if mysql_upgrade |
1197 | already has been run for this installation of MySQL |
1198 | */ |
1199 | if (!opt_force && upgrade_already_done(0)) |
1200 | { |
1201 | printf("This installation of MySQL is already upgraded to %s, " |
1202 | "use --force if you still need to run mysql_upgrade\n" , |
1203 | MYSQL_SERVER_VERSION); |
1204 | goto end; |
1205 | } |
1206 | |
1207 | if (opt_version_check && check_version_match()) |
1208 | die("Upgrade failed" ); |
1209 | |
1210 | upgrade_from_mysql= is_mysql(); |
1211 | |
1212 | /* |
1213 | Run "mysqlcheck" and "mysql_fix_privilege_tables.sql" |
1214 | */ |
1215 | if (run_mysqlcheck_upgrade(TRUE) || |
1216 | install_used_engines() || |
1217 | run_mysqlcheck_views() || |
1218 | run_sql_fix_privilege_tables() || |
1219 | run_mysqlcheck_fixnames() || |
1220 | run_mysqlcheck_upgrade(FALSE)) |
1221 | die("Upgrade failed" ); |
1222 | |
1223 | verbose("Phase %d/%d: Running 'FLUSH PRIVILEGES'" , ++phase, phases_total); |
1224 | if (run_query("FLUSH PRIVILEGES" , NULL, TRUE)) |
1225 | die("Upgrade failed" ); |
1226 | |
1227 | verbose("OK" ); |
1228 | |
1229 | /* Create a file indicating upgrade has been performed */ |
1230 | create_mysql_upgrade_info_file(); |
1231 | |
1232 | DBUG_ASSERT(phase == phases_total); |
1233 | |
1234 | end: |
1235 | free_used_memory(); |
1236 | my_end(my_end_arg); |
1237 | exit(0); |
1238 | } |
1239 | |