~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
#include "client_priv.h"
17
#include "../scripts/mysql_fix_privilege_tables_sql.c"
18
19
#define VER "1.1"
20
21
#ifdef HAVE_SYS_WAIT_H
22
#include <sys/wait.h>
23
#endif
24
25
#ifndef WEXITSTATUS
26
#  define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
27
#endif
28
29
static char mysql_path[FN_REFLEN];
30
static char mysqlcheck_path[FN_REFLEN];
31
32
static my_bool opt_force, opt_verbose, debug_info_flag, debug_check_flag;
33
static uint my_end_arg= 0;
34
static char *opt_user= (char*)"root";
35
36
static DYNAMIC_STRING ds_args;
37
38
static char *opt_password= 0;
39
static my_bool tty_password= 0;
40
41
#ifndef DBUG_OFF
42
static char *default_dbug_option= (char*) "d:t:O,/tmp/mysql_upgrade.trace";
43
#endif
44
45
static char **defaults_argv;
46
47
static my_bool not_used; /* Can't use GET_BOOL without a value pointer */
48
49
#include <help_start.h>
50
51
static struct my_option my_long_options[]=
52
{
53
  {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
54
   NO_ARG, 0, 0, 0, 0, 0, 0},
55
  {"basedir", 'b', "Not used by mysql_upgrade. Only for backward compatibilty",
56
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
57
  {"character-sets-dir", OPT_CHARSETS_DIR,
58
   "Directory where character sets are.", 0,
59
   0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
60
  {"compress", OPT_COMPRESS, "Use compression in server/client protocol.",
61
   (uchar**)&not_used, (uchar**)&not_used, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
62
  {"datadir", 'd',
63
   "Not used by mysql_upgrade. Only for backward compatibilty",
64
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
65
#ifdef DBUG_OFF
66
  {"debug", '#', "This is a non-debug version. Catch this and exit",
67
   0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
68
#else
69
  {"debug", '#', "Output debug log", (uchar* *) & default_dbug_option,
70
   (uchar* *) & default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
71
#endif
72
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
73
   (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0,
74
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
75
  {"debug-info", 'T', "Print some debug info at exit.", (uchar**) &debug_info_flag,
76
   (uchar**) &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
77
  {"default-character-set", OPT_DEFAULT_CHARSET,
78
   "Set the default character set.", 0,
79
   0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
80
  {"force", 'f', "Force execution of mysqlcheck even if mysql_upgrade "
81
   "has already been executed for the current version of MySQL.",
82
   (uchar**)&opt_force, (uchar**)&opt_force, 0,
83
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
84
  {"host",'h', "Connect to host.", 0,
85
   0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
86
  {"password", 'p',
87
   "Password to use when connecting to server. If password is not given"
88
   " it's solicited on the tty.", (uchar**) &opt_password,(uchar**) &opt_password,
89
   0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
90
  {"port", 'P', "Port number to use for connection or 0 for default to, in "
91
   "order of preference, my.cnf, $MYSQL_TCP_PORT, "
92
#if MYSQL_PORT_DEFAULT == 0
93
   "/etc/services, "
94
#endif
95
   "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
96
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
97
  {"protocol", OPT_MYSQL_PROTOCOL,
98
   "The protocol of connection (tcp,socket,pipe,memory).",
99
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
100
#ifdef HAVE_SMEM
101
  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
102
   "Base name of shared memory.", 0,
103
   0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
104
#endif
105
  {"socket", 'S', "Socket file to use for connection.",
106
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
107
  {"user", 'u', "User for login if not current user.", (uchar**) &opt_user,
108
   (uchar**) &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
109
  {"verbose", 'v', "Display more output about the process",
110
   (uchar**) &opt_verbose, (uchar**) &opt_verbose, 0,
111
   GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
112
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
113
};
114
115
#include <help_end.h>
116
117
118
static void free_used_memory(void)
119
{
120
  /* Free memory allocated by 'load_defaults' */
121
  free_defaults(defaults_argv);
122
123
  dynstr_free(&ds_args);
124
}
125
126
127
static void die(const char *fmt, ...)
128
{
129
  va_list args;
130
  DBUG_ENTER("die");
131
132
  /* Print the error message */
133
  va_start(args, fmt);
134
  if (fmt)
135
  {
136
    fprintf(stderr, "FATAL ERROR: ");
137
    vfprintf(stderr, fmt, args);
138
    fprintf(stderr, "\n");
139
    fflush(stderr);
140
  }
141
  va_end(args);
142
143
  free_used_memory();
144
  my_end(my_end_arg);
145
  exit(1);
146
}
147
148
149
static void verbose(const char *fmt, ...)
150
{
151
  va_list args;
152
153
  if (!opt_verbose)
154
    return;
155
156
  /* Print the verbose message */
157
  va_start(args, fmt);
158
  if (fmt)
159
  {
160
    vfprintf(stdout, fmt, args);
161
    fprintf(stdout, "\n");
162
    fflush(stdout);
163
  }
164
  va_end(args);
165
}
166
167
168
/*
169
  Add one option - passed to mysql_upgrade on command line
170
  or by defaults file(my.cnf) - to a dynamic string, in
171
  this way we pass the same arguments on to mysql and mysql_check
172
*/
173
174
static void add_one_option(DYNAMIC_STRING* ds,
175
                           const struct my_option *opt,
176
                           const char* argument)
177
178
{
179
  const char* eq= NullS;
180
  const char* arg= NullS;
181
  if (opt->arg_type != NO_ARG)
182
  {
183
    eq= "=";
184
    switch (opt->var_type & GET_TYPE_MASK) {
185
    case GET_STR:
186
      arg= argument;
187
      break;
188
    default:
189
      die("internal error at %s: %d",__FILE__, __LINE__);
190
    }
191
  }
192
  dynstr_append_os_quoted(ds, "--", opt->name, eq, arg, NullS);
193
  dynstr_append(&ds_args, " ");
194
}
195
196
197
static my_bool
198
get_one_option(int optid, const struct my_option *opt,
199
               char *argument)
200
{
201
  my_bool add_option= TRUE;
202
203
  switch (optid) {
204
205
  case '?':
206
    printf("%s  Ver %s Distrib %s, for %s (%s)\n",
207
           my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
208
    puts("MySQL utility for upgrading databases to new MySQL versions\n");
209
    my_print_help(my_long_options);
210
    exit(0);
211
    break;
212
213
  case '#':
214
    DBUG_PUSH(argument ? argument : default_dbug_option);
215
    add_option= FALSE;
216
    debug_check_flag= 1;
217
    break;
218
219
  case 'p':
220
    tty_password= 1;
221
    add_option= FALSE;
222
    if (argument)
223
    {
224
      /* Add password to ds_args before overwriting the arg with x's */
225
      add_one_option(&ds_args, opt, argument);
226
      while (*argument)
227
        *argument++= 'x';                       /* Destroy argument */
228
      tty_password= 0;
229
    }
230
    break;
231
232
  case 'b': /* --basedir   */
233
  case 'v': /* --verbose   */
234
  case 'd': /* --datadir   */
235
  case 'f': /* --force     */
236
    add_option= FALSE;
237
    break;
238
  }
239
240
  if (add_option)
241
  {
242
    /*
243
      This is an option that is accpted by mysql_upgrade just so
244
      it can be passed on to "mysql" and "mysqlcheck"
245
      Save it in the ds_args string
246
    */
247
    add_one_option(&ds_args, opt, argument);
248
  }
249
  return 0;
250
}
251
252
253
static int run_command(char* cmd,
254
                       DYNAMIC_STRING *ds_res)
255
{
256
  char buf[512]= {0};
257
  FILE *res_file;
258
  int error;
259
260
  if (!(res_file= popen(cmd, "r")))
261
    die("popen(\"%s\", \"r\") failed", cmd);
262
263
  while (fgets(buf, sizeof(buf), res_file))
264
  {
265
    DBUG_PRINT("info", ("buf: %s", buf));
266
    if(ds_res)
267
    {
268
      /* Save the output of this command in the supplied string */
269
      dynstr_append(ds_res, buf);
270
    }
271
    else
272
    {
273
      /* Print it directly on screen */
274
      fprintf(stdout, "%s", buf);
275
    }
276
  }
277
278
  error= pclose(res_file);
279
  return WEXITSTATUS(error);
280
}
281
282
283
static int run_tool(char *tool_path, DYNAMIC_STRING *ds_res, ...)
284
{
285
  int ret;
286
  const char* arg;
287
  va_list args;
288
  DYNAMIC_STRING ds_cmdline;
289
290
  DBUG_ENTER("run_tool");
291
  DBUG_PRINT("enter", ("tool_path: %s", tool_path));
292
15 by brian
Fix for stat, NETWARE removal
293
  if (init_dynamic_string(&ds_cmdline, "", FN_REFLEN, FN_REFLEN))
1 by brian
clean slate
294
    die("Out of memory");
295
296
  dynstr_append_os_quoted(&ds_cmdline, tool_path, NullS);
297
  dynstr_append(&ds_cmdline, " ");
298
299
  va_start(args, ds_res);
300
301
  while ((arg= va_arg(args, char *)))
302
  {
303
    /* Options should be os quoted */
304
    if (strncmp(arg, "--", 2) == 0)
305
      dynstr_append_os_quoted(&ds_cmdline, arg, NullS);
306
    else
307
      dynstr_append(&ds_cmdline, arg);
308
    dynstr_append(&ds_cmdline, " ");
309
  }
310
311
  va_end(args);
312
313
  DBUG_PRINT("info", ("Running: %s", ds_cmdline.str));
314
  ret= run_command(ds_cmdline.str, ds_res);
315
  DBUG_PRINT("exit", ("ret: %d", ret));
316
  dynstr_free(&ds_cmdline);
317
  DBUG_RETURN(ret);
318
}
319
320
321
/*
322
  Try to get the full path to this exceutable
323
324
  Return 0 if path found
325
326
*/
327
328
static my_bool get_full_path_to_executable(char* path)
329
{
330
  my_bool ret;
331
  DBUG_ENTER("get_full_path_to_executable");
15 by brian
Fix for stat, NETWARE removal
332
1 by brian
clean slate
333
  /* my_readlink returns 0 if a symlink was read */
334
  ret= (my_readlink(path, "/proc/self/exe", MYF(0)) != 0);
335
  /* Might also want to try with /proc/$$/exe if the above fails */
15 by brian
Fix for stat, NETWARE removal
336
1 by brian
clean slate
337
  DBUG_PRINT("exit", ("path: %s", path));
338
  DBUG_RETURN(ret);
339
}
340
341
342
/*
343
  Look for the tool in the same directory as mysql_upgrade.
344
*/
345
346
static void find_tool(char *tool_path, const char *tool_name)
347
{
348
  size_t path_len;
349
  char path[FN_REFLEN];
350
  DYNAMIC_STRING ds_tmp;
351
  DBUG_ENTER("find_tool");
352
  DBUG_PRINT("enter", ("progname: %s", my_progname));
353
354
  if (init_dynamic_string(&ds_tmp, "", 32, 32))
355
    die("Out of memory");
356
357
  /* Initialize path with the full path to this program */
358
  if (get_full_path_to_executable(path))
359
  {
360
    /*
361
      Easy way to get full executable path failed, try
362
      other methods
363
    */
364
    if (my_progname[0] == FN_LIBCHAR)
365
    {
366
      /* 1. my_progname contains full path */
367
      strmake(path, my_progname, FN_REFLEN);
368
    }
369
    else if (my_progname[0] == '.')
370
    {
371
      /* 2. my_progname contains relative path, prepend wd */
372
      char buf[FN_REFLEN];
373
      my_getwd(buf, FN_REFLEN, MYF(0));
374
      my_snprintf(path, FN_REFLEN, "%s%s", buf, my_progname);
375
    }
376
    else
377
    {
378
      /* 3. Just go for it and hope tool is in path */
379
      path[0]= 0;
380
    }
381
  }
382
383
  DBUG_PRINT("info", ("path: '%s'", path));
384
385
  /* Chop off binary name (i.e mysql-upgrade) from path */
386
  dirname_part(path, path, &path_len);
387
388
  /*
389
    When running in a not yet installed build and using libtool,
390
    the program(mysql_upgrade) will be in .libs/ and executed
391
    through a libtool wrapper in order to use the dynamic libraries
392
    from this build. The same must be done for the tools(mysql and
393
    mysqlcheck). Thus if path ends in .libs/, step up one directory
394
    and execute the tools from there
395
  */
396
  path[max(path_len-1, 0)]= 0;   /* Chop off last / */
397
  if (strncmp(path + dirname_length(path), ".libs", 5) == 0)
398
  {
399
    DBUG_PRINT("info", ("Chopping off .libs from '%s'", path));
400
401
    /* Chop off .libs */
402
    dirname_part(path, path, &path_len);
403
  }
404
405
406
  DBUG_PRINT("info", ("path: '%s'", path));
407
408
  /* Format name of the tool to search for */
409
  fn_format(tool_path, tool_name,
410
            path, "", MYF(MY_REPLACE_DIR));
411
412
  verbose("Looking for '%s' in: %s", tool_name, tool_path);
413
414
  /* Make sure the tool exists */
415
  if (my_access(tool_path, F_OK) != 0)
416
    die("Can't find '%s'", tool_path);
417
418
  /*
419
    Make sure it can be executed
420
  */
421
  if (run_tool(tool_path,
422
               &ds_tmp, /* Get output from command, discard*/
423
               "--help",
424
               "2>&1",
15 by brian
Fix for stat, NETWARE removal
425
               "> /dev/null",
1 by brian
clean slate
426
               NULL))
427
    die("Can't execute '%s'", tool_path);
428
429
  dynstr_free(&ds_tmp);
430
431
  DBUG_VOID_RETURN;
432
}
433
434
435
/*
436
  Run query using "mysql"
437
*/
438
439
static int run_query(const char *query, DYNAMIC_STRING *ds_res,
440
                     my_bool force)
441
{
442
  int ret;
443
  File fd;
444
  char query_file_path[FN_REFLEN];
445
  DBUG_ENTER("run_query");
446
  DBUG_PRINT("enter", ("query: %s", query));
447
  if ((fd= create_temp_file(query_file_path, NULL,
448
                            "sql", O_CREAT | O_SHARE | O_RDWR,
449
                            MYF(MY_WME))) < 0)
450
    die("Failed to create temporary file for defaults");
451
452
  if (my_write(fd, (uchar*) query, strlen(query),
453
               MYF(MY_FNABP | MY_WME)))
454
  {
455
    my_close(fd, MYF(0));
456
    my_delete(query_file_path, MYF(0));
457
    die("Failed to write to '%s'", query_file_path);
458
  }
459
460
  ret= run_tool(mysql_path,
461
                ds_res,
462
                "--no-defaults",
463
                ds_args.str,
464
                "--database=mysql",
465
                "--batch", /* Turns off pager etc. */
466
                force ? "--force": "--skip-force",
467
                ds_res ? "--silent": "",
468
                "<",
469
                query_file_path,
470
                "2>&1",
471
                NULL);
472
473
  my_close(fd, MYF(0));
474
  my_delete(query_file_path, MYF(0));
475
476
  DBUG_RETURN(ret);
477
}
478
479
480
/*
481
  Extract the value returned from result of "show variable like ..."
482
*/
483
484
static int extract_variable_from_show(DYNAMIC_STRING* ds, char* value)
485
{
486
  char *value_start, *value_end;
487
  /*
488
    The query returns "datadir\t<datadir>\n", skip past
489
    the tab
490
  */
491
  if ((value_start= strchr(ds->str, '\t')) == NULL)
492
    return 1; /* Unexpected result */
493
  value_start++;
494
495
  /* Don't copy the ending newline */
496
  if ((value_end= strchr(value_start, '\n')) == NULL)
497
    return 1; /* Unexpected result */
498
499
  strncpy(value, value_start, min(FN_REFLEN, value_end-value_start));
500
  return 0;
501
}
502
503
504
static int get_upgrade_info_file_name(char* name)
505
{
506
  DYNAMIC_STRING ds_datadir;
507
  DBUG_ENTER("get_upgrade_info_file_name");
508
509
  if (init_dynamic_string(&ds_datadir, NULL, 32, 32))
510
    die("Out of memory");
511
512
  if (run_query("show variables like 'datadir'",
513
                &ds_datadir, FALSE) ||
514
      extract_variable_from_show(&ds_datadir, name))
515
  {
516
    dynstr_free(&ds_datadir);
517
    DBUG_RETURN(1); /* Query failed */
518
  }
519
520
  dynstr_free(&ds_datadir);
521
522
  fn_format(name, "mysql_upgrade_info", name, "", MYF(0));
523
  DBUG_PRINT("exit", ("name: %s", name));
524
  DBUG_RETURN(0);
525
}
526
527
528
/*
529
  Read the content of mysql_upgrade_info file and
530
  compare the version number form file against
531
  version number wich mysql_upgrade was compiled for
532
533
  NOTE
534
  This is an optimization to avoid running mysql_upgrade
535
  when it's already been performed for the particular
536
  version of MySQL.
537
538
  In case the MySQL server can't return the upgrade info
539
  file it's always better to report that the upgrade hasn't
540
  been performed.
541
542
*/
543
544
static int upgrade_already_done(void)
545
{
546
  FILE *in;
547
  char upgrade_info_file[FN_REFLEN]= {0};
548
  char buf[sizeof(MYSQL_SERVER_VERSION)+1];
549
550
  if (get_upgrade_info_file_name(upgrade_info_file))
551
    return 0; /* Could not get filename => not sure */
552
553
  if (!(in= my_fopen(upgrade_info_file, O_RDONLY, MYF(0))))
554
    return 0; /* Could not open file => not sure */
555
556
  /*
557
    Read from file, don't care if it fails since it
558
    will be detected by the strncmp
559
  */
560
  bzero(buf, sizeof(buf));
561
  fgets(buf, sizeof(buf), in);
562
563
  my_fclose(in, MYF(0));
564
565
  return (strncmp(buf, MYSQL_SERVER_VERSION,
566
                  sizeof(MYSQL_SERVER_VERSION)-1)==0);
567
}
568
569
570
/*
571
  Write mysql_upgrade_info file in servers data dir indicating that
572
  upgrade has been done for this version
573
574
  NOTE
575
  This might very well fail but since it's just an optimization
576
  to run mysql_upgrade only when necessary the error can be
577
  ignored.
578
579
*/
580
581
static void create_mysql_upgrade_info_file(void)
582
{
583
  FILE *out;
584
  char upgrade_info_file[FN_REFLEN]= {0};
585
586
  if (get_upgrade_info_file_name(upgrade_info_file))
587
    return; /* Could not get filename => skip */
588
589
  if (!(out= my_fopen(upgrade_info_file, O_TRUNC | O_WRONLY, MYF(0))))
590
  {
591
    fprintf(stderr,
592
            "Could not create the upgrade info file '%s' in "
593
            "the MySQL Servers datadir, errno: %d\n",
594
            upgrade_info_file, errno);
595
    return;
596
  }
597
598
  /* Write new version to file */
599
  fputs(MYSQL_SERVER_VERSION, out);
600
  my_fclose(out, MYF(0));
601
602
  /*
603
    Check if the upgrad_info_file was properly created/updated
604
    It's not a fatal error -> just print a message if it fails
605
  */
606
  if (!upgrade_already_done())
607
    fprintf(stderr,
608
            "Could not write to the upgrade info file '%s' in "
609
            "the MySQL Servers datadir, errno: %d\n",
610
            upgrade_info_file, errno);
611
  return;
612
}
613
614
615
/*
616
  Check and upgrade(if neccessary) all tables
617
  in the server using "mysqlcheck --check-upgrade .."
618
*/
619
620
static int run_mysqlcheck_upgrade(void)
621
{
622
  verbose("Running 'mysqlcheck'...");
623
  return run_tool(mysqlcheck_path,
624
                  NULL, /* Send output from mysqlcheck directly to screen */
625
                  "--no-defaults",
626
                  ds_args.str,
627
                  "--check-upgrade",
628
                  "--all-databases",
629
                  "--auto-repair",
630
                  NULL);
631
}
632
633
634
static const char *expected_errors[]=
635
{
636
  "ERROR 1060", /* Duplicate column name */
637
  "ERROR 1061", /* Duplicate key name */
638
  "ERROR 1054", /* Unknown column */
639
  0
640
};
641
642
643
static my_bool is_expected_error(const char* line)
644
{
645
  const char** error= expected_errors;
646
  while (*error)
647
  {
648
    /*
649
      Check if lines starting with ERROR
650
      are in the list of expected errors
651
    */
652
    if (strncmp(line, "ERROR", 5) != 0 ||
653
        strncmp(line, *error, strlen(*error)) == 0)
654
      return 1; /* Found expected error */
655
    error++;
656
  }
657
  return 0;
658
}
659
660
661
static char* get_line(char* line)
662
{
663
  while (*line && *line != '\n')
664
    line++;
665
  if (*line)
666
    line++;
667
  return line;
668
}
669
670
671
/* Print the current line to stderr */
672
static void print_line(char* line)
673
{
674
  while (*line && *line != '\n')
675
  {
676
    fputc(*line, stderr);
677
    line++;
678
  }
679
  fputc('\n', stderr);
680
}
681
682
683
/*
684
  Update all system tables in MySQL Server to current
685
  version using "mysql" to execute all the SQL commands
686
  compiled into the mysql_fix_privilege_tables array
687
*/
688
689
static int run_sql_fix_privilege_tables(void)
690
{
691
  int found_real_errors= 0;
692
  DYNAMIC_STRING ds_result;
693
  DBUG_ENTER("run_sql_fix_privilege_tables");
694
695
  if (init_dynamic_string(&ds_result, "", 512, 512))
696
    die("Out of memory");
697
698
  verbose("Running 'mysql_fix_privilege_tables'...");
699
  run_query(mysql_fix_privilege_tables,
700
            &ds_result, /* Collect result */
701
            TRUE);
702
703
  {
704
    /*
705
      Scan each line of the result for real errors
706
      and ignore the expected one(s) like "Duplicate column name",
707
      "Unknown column" and "Duplicate key name" since they just
708
      indicate the system tables are already up to date
709
    */
710
    char *line= ds_result.str;
711
    do
712
    {
713
      if (!is_expected_error(line))
714
      {
715
        /* Something unexpected failed, dump error line to screen */
716
        found_real_errors++;
717
        print_line(line);
718
      }
719
    } while ((line= get_line(line)) && *line);
720
  }
721
722
  dynstr_free(&ds_result);
723
  return found_real_errors;
724
}
725
726
727
static const char *load_default_groups[]=
728
{
729
  "client", /* Read settings how to connect to server */
730
  "mysql_upgrade", /* Read special settings for mysql_upgrade*/
731
  0
732
};
733
734
735
int main(int argc, char **argv)
736
{
737
  MY_INIT(argv[0]);
738
739
  if (init_dynamic_string(&ds_args, "", 512, 256))
740
    die("Out of memory");
741
742
  load_defaults("my", load_default_groups, &argc, &argv);
743
  defaults_argv= argv; /* Must be freed by 'free_defaults' */
744
745
  if (handle_options(&argc, &argv, my_long_options, get_one_option))
746
    die(NULL);
747
  if (debug_info_flag)
748
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
749
  if (debug_check_flag)
750
    my_end_arg= MY_CHECK_ERROR;
751
752
  if (tty_password)
753
  {
754
    opt_password= get_tty_password(NullS);
755
    /* add password to defaults file */
756
    dynstr_append_os_quoted(&ds_args, "--password=", opt_password, NullS);
757
    dynstr_append(&ds_args, " ");
758
  }
759
  /* add user to defaults file */
760
  dynstr_append_os_quoted(&ds_args, "--user=", opt_user, NullS);
761
  dynstr_append(&ds_args, " ");
762
763
  /* Find mysql */
15 by brian
Fix for stat, NETWARE removal
764
  find_tool(mysql_path, "mysql");
1 by brian
clean slate
765
766
  /* Find mysqlcheck */
15 by brian
Fix for stat, NETWARE removal
767
  find_tool(mysqlcheck_path, "mysqlcheck");
1 by brian
clean slate
768
769
  /*
770
    Read the mysql_upgrade_info file to check if mysql_upgrade
771
    already has been run for this installation of MySQL
772
  */
773
  if (!opt_force && upgrade_already_done())
774
  {
775
    printf("This installation of MySQL is already upgraded to %s, "
776
           "use --force if you still need to run mysql_upgrade\n",
777
           MYSQL_SERVER_VERSION);
778
    die(NULL);
779
  }
780
781
  /*
782
    Run "mysqlcheck" and "mysql_fix_privilege_tables.sql"
783
  */
784
  if (run_mysqlcheck_upgrade() ||
785
      run_sql_fix_privilege_tables())
786
  {
787
    /*
788
      The upgrade failed to complete in some way or another,
789
      significant error message should have been printed to the screen
790
    */
791
    die("Upgrade failed" );
792
  }
793
  verbose("OK");
794
795
  /* Create a file indicating upgrade has been performed */
796
  create_mysql_upgrade_info_file();
797
798
  free_used_memory();
799
  my_end(my_end_arg);
800
  exit(0);
801
}
802