From da5366886f2c852cb05f8b9b31848d13a4816cad Mon Sep 17 00:00:00 2001
From: unknown <monty@tik.mysql.com>
Date: Wed, 11 Oct 2000 00:06:37 +0300
Subject: [PATCH] Automatic repair of MyISAM tables + portability fixes

Docs/manual.texi:
  Changes for 3.23 and change Ansi mode -> ANSI mode
include/my_base.h:
  Automatic repair of MyISAM tables
include/myisam.h:
  Automatic repair of MyISAM tables
myisam/ft_update.c:
  Portability fix
myisam/mi_check.c:
  Automatic repair of MyISAM tables
myisam/mi_open.c:
  Automatic repair of MyISAM tables
myisam/myisamchk.c:
  Allow one to combine check with --old-repair
myisam/sort.c:
  Fix for usage of IO_CACHE
mysys/charset.c:
  Portability fixes
mysys/default.c:
  Added --defaults-extra-dir
mysys/mf_tempfile.c:
  Portability fixes
mysys/my_init.c:
  Remove compiler warning
mysys/my_pread.c:
  Remove compiler warning
sql-bench/server-cfg.sh:
  New benchmark tests
sql-bench/test-insert.sh:
  New benchmark tests
sql/ha_myisam.cc:
  Automatic repair of MyISAM tables
sql/ha_myisam.h:
  Automatic repair of MyISAM tables
sql/handler.h:
  Automatic repair of MyISAM tables
sql/lock.cc:
  Add missing free
sql/log_event.cc:
  Portability fixes
sql/sql_base.cc:
  Automatic repair of MyISAM tables
sql/sql_select.h:
  Remove compiler warning
sql/sql_table.cc:
  Clean up intendent
sql/sql_yacc.yy:
  New syntax for CHECK
sql/table.cc:
  Automatic repair of MyISAM tables
sql/table.h:
  Automatic repair of MyISAM tables
BitKeeper/etc/logging_ok:
  Logging to logging@openlogging.org accepted
---
 BitKeeper/etc/logging_ok |  3 +-
 Docs/manual.texi         | 88 ++++++++++++++++++++++++---------------
 include/my_base.h        |  1 +
 include/myisam.h         | 19 +++++----
 myisam/ft_update.c       |  2 +-
 myisam/mi_check.c        | 19 ++++++---
 myisam/mi_open.c         |  5 ++-
 myisam/myisamchk.c       | 24 ++++++-----
 myisam/sort.c            |  6 +--
 mysys/charset.c          |  6 +--
 mysys/default.c          | 12 ++++--
 mysys/mf_tempfile.c      |  9 ++--
 mysys/my_init.c          |  2 +-
 mysys/my_pread.c         |  2 +-
 sql-bench/server-cfg.sh  | 13 ++++++
 sql-bench/test-insert.sh | 53 +++++++++++++++++++++--
 sql/ha_myisam.cc         | 40 +++++++++++++-----
 sql/ha_myisam.h          |  7 ++--
 sql/handler.h            |  8 ++--
 sql/lock.cc              |  3 ++
 sql/log_event.cc         |  4 +-
 sql/sql_base.cc          | 71 ++++++++++++++++++++++++++-----
 sql/sql_select.h         |  2 +-
 sql/sql_table.cc         | 90 ++++++++++++++++++++--------------------
 sql/sql_yacc.yy          |  5 +++
 sql/table.cc             | 28 ++++++++-----
 sql/table.h              |  1 +
 27 files changed, 356 insertions(+), 167 deletions(-)

diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index 2d75ea486e..a6b0f22026 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -1,2 +1 @@
-monty@tramp.mysql.fi
-monty@donna.mysql.com
+monty@tik.mysql.com
diff --git a/Docs/manual.texi b/Docs/manual.texi
index 4c056d1ff9..3c49afc3a0 100644
--- a/Docs/manual.texi
+++ b/Docs/manual.texi
@@ -315,7 +315,7 @@ Is There Anything Special to Do when Upgrading/Downgrading MySQL?
 How Standards-compatible Is MySQL?
 
 * Extensions to ANSI::          @strong{MySQL} extensions to ANSI SQL92
-* Ansi mode::                   Running @strong{MySQL} in ANSI mode
+* ANSI mode::                   Running @strong{MySQL} in ANSI mode
 * Differences from ANSI::       @strong{MySQL} differences compared to ANSI SQL92
 * Missing functions::           Functionality missing from @strong{MySQL}
 * Standards::                   What standards does @strong{MySQL} follow?
@@ -1550,7 +1550,8 @@ clauses. Support for group functions (@code{COUNT()},
 @code{MAX()} and @code{MIN()}).
 
 @item
-Support for @code{LEFT OUTER JOIN} with ANSI SQL and ODBC syntax.
+Support for @code{LEFT OUTER JOIN} and @code{RIGHT OUTER JOIN} with ANSI
+SQL and ODBC syntax.
 
 @item
 You can mix tables from different databases in the same query (as of
@@ -6024,6 +6025,16 @@ you are probably using @code{gcc} (or using an old binary compiled with
 /usr/bin/perl: can't resolve symbol '__divdi3'
 @end example
 
+Add @code{-L/usr/lib/gcc-lib/... -lgcc} to the link command when the
+@file{mysql.so} library gets built (check the output from @code{make} for
+@file{mysql.so} when you compile the Perl client).  The @code{-L} option
+should specify the pathname of the directory where @file{libgcc.a} is located
+on your system.
+
+Another cause of this problem may be that Perl and @strong{MySQL} aren't both
+compiled with @code{gcc}.  In this case, you can solve the mismatch by
+compiling both with @code{gcc}.
+
 If you get the following error from @code{Msql-Mysql-modules}
 when you run the tests:
 
@@ -6032,7 +6043,8 @@ t/00base............install_driver(mysql) failed: Can't load '../blib/arch/auto/
 @end example
 
 it means that you need to include the compression library, -lz, to the
-link line. This can be done by changing the line:
+link line. This can be doing the following change in the file
+@file{lib/DBD/mysql/Install.pm}:
 
 @example
 $sysliblist .= " -lm";
@@ -6042,20 +6054,9 @@ to
 $sysliblist .= " -lm -lz";
 @end example
 
-in file lib/DBD/mysql/Install.pm in the Msql-Mysql-modules directory.
 After this, you MUST run 'make realclean' and then proceed with the
 installation from the beginning.
 
-Add @code{-L/usr/lib/gcc-lib/... -lgcc} to the link command when the
-@file{mysql.so} library gets built (check the output from @code{make} for
-@file{mysql.so} when you compile the Perl client).  The @code{-L} option
-should specify the pathname of the directory where @file{libgcc.a} is located
-on your system.
-
-Another cause of this problem may be that Perl and @strong{MySQL} aren't both
-compiled with @code{gcc}.  In this case, you can solve the mismatch by
-compiling both with @code{gcc}.
-
 If you want to use the Perl module on a system that doesn't support dynamic
 linking (like SCO) you can generate a static version of Perl that includes
 @code{DBI} and @code{DBD-mysql}.  The way this works is that you generate a
@@ -8931,7 +8932,7 @@ The @code{mysql.server} script uses the following variables:
 @table @code
 
 @item --ansi
-Use ANSI SQL syntax instead of MySQL syntax. @xref{Ansi mode}.
+Use ANSI SQL syntax instead of MySQL syntax. @xref{ANSI mode}.
 
 @item -b, --basedir=path
 Path to installation directory. All paths are
@@ -9631,14 +9632,14 @@ information.
 
 @menu
 * Extensions to ANSI::          @strong{MySQL} extensions to ANSI SQL92
-* Ansi mode::                   Running @strong{MySQL} in ANSI mode
+* ANSI mode::                   Running @strong{MySQL} in ANSI mode
 * Differences from ANSI::       @strong{MySQL} differences compared to ANSI SQL92
 * Missing functions::           Functionality missing from @strong{MySQL}
 * Standards::                   What standards does @strong{MySQL} follow?
 * Commit-rollback::             How to cope without @code{COMMIT}-@code{ROLLBACK}
 @end menu
 
-@node Extensions to ANSI, Ansi mode, Compatibility, Compatibility
+@node Extensions to ANSI, ANSI mode, Compatibility, Compatibility
 @section MySQL Extensions to ANSI SQL92
 
 @strong{MySQL} includes some extensions that you probably will not find in
@@ -9882,7 +9883,7 @@ SELECT @@t1:=(@@t2:=1)+@@t3:=4,@@t1,@@t2,@@t3;
 
 @end itemize
 
-@node Ansi mode, Differences from ANSI, Extensions to ANSI, Compatibility
+@node ANSI mode, Differences from ANSI, Extensions to ANSI, Compatibility
 @section Running MySQL in ANSI Mode
 @cindex running, ANSI mode
 @cindex ANSI mode, running
@@ -9895,7 +9896,7 @@ of @strong{MySQL} changes:
 @code{||} is string concatenation instead of @code{OR}.
 @item
 You can have any number of spaces between a function name and the @samp{(}. 
-This makes also all function names reserved words.
+This forces all function names to be treated as reserved words.
 @item
 @samp{"} will be an identifier quote character (like the @strong{MySQL}
 @samp{`} quote character) and not a string quote character.
@@ -9904,7 +9905,7 @@ This makes also all function names reserved words.
 @code{DOUBLE}.
 @end itemize
 
-@node Differences from ANSI, Missing functions, Ansi mode, Compatibility
+@node Differences from ANSI, Missing functions, ANSI mode, Compatibility
 @section MySQL Differences Compared to ANSI SQL92
 
 We try to make @strong{MySQL} follow the ANSI SQL standard and the
@@ -9913,7 +9914,8 @@ differently:
 
 @itemize @bullet
 @item
-@code{--} is only a comment if followed by a white space. @xref{Missing comments}.
+@code{--} is only a comment if followed by a white space. @xref{Missing
+comments}.
 @item
 For @code{VARCHAR} columns, trailing spaces are removed when the value is
 stored. @xref{Bugs}.
@@ -9936,11 +9938,11 @@ extra conditions in this case.
 @cindex functionality, missing
 
 The following functionality is missing in the current version of
-@strong{MySQL}.  For a prioritized list indicating when new extensions may be
-added to @strong{MySQL}, you should consult
-@uref{http://www.mysql.com/documentation/manual.php?section=TODO, the online
-@strong{MySQL} TODO list}. That is the latest version of the TODO list in
-this manual. @xref{TODO}.
+@strong{MySQL}.  For a prioritized list indicating when new extensions
+may be added to @strong{MySQL}, you should consult
+@uref{http://www.mysql.com/documentation/manual.php?section=TODO, the
+online @strong{MySQL} TODO list}. That is the latest version of the TODO
+list in this manual. @xref{TODO}.
 
 @menu
 * Missing Sub-selects::         Sub-selects
@@ -12726,8 +12728,8 @@ Database, table, index, column, and alias names all follow the same rules in
 @tindex "
 Note that the rules changed starting with @strong{MySQL} Version 3.23.6 when we
 introduced quoting of identifiers (database, table, and column names)
-with @samp{`} (@samp{"} will also work to quote identifiers if you run
-in ANSI mode).
+with @samp{`}. @samp{"} will also work to quote identifiers if you run
+in ANSI mode. @xref{ANSI mode}.
 
 @multitable @columnfractions .15 .15 .70
 @item @strong{Identifier} @tab @strong{Max length} @tab @strong{Allowed characters}
@@ -13405,7 +13407,7 @@ standard, @strong{MySQL} recognizes @code{DOUBLE} as a synonym for the
 @code{DOUBLE PRECISION} type.  In contrast with the standard's
 requirement that the precision for @code{REAL} be smaller than that used
 for @code{DOUBLE PRECISION}, @strong{MySQL} implements both as 8-byte
-double-precision floating-point values (when not running in ``Ansi mode'').
+double-precision floating-point values (when not running in ``ANSI mode'').
 For maximum portability, code requiring storage of approximate numeric
 data values should use @code{FLOAT} or @code{DOUBLE PRECISION} with no
 specification of precision or number of decimal points.
@@ -17838,7 +17840,9 @@ running!
 @section @code{CHECK TABLE} Syntax
 
 @example
-CHECK TABLE tbl_name[,tbl_name...] [TYPE = [QUICK | FAST | EXTEND | CHANGED]]
+CHECK TABLE tbl_name[,tbl_name...] [option [option...]]
+
+option = QUICK | FAST | EXTEND | CHANGED
 @end example
 
 @code{CHECK TABLE} only works on @code{MyISAM} tables and is the same thing
@@ -17872,6 +17876,14 @@ The different check types stand for the following:
 @item @code{EXTENDED} @tab Do a full key lookup for all keys for each row.  This ensures that the table is 100 % consistent, but will take a long time!
 @end multitable
 
+You can combine check options as in:
+
+@example
+CHECK TABLE test_table FAST QUICK;
+@end example
+
+Which only would do a quick check on the table if it wasn't closed properly.
+
 If a table is corrupted, then it's most likely that the problem is in
 the indexes and not in the data part.  All of the above check types
 checks the indexes throughly and should thus find most errors.
@@ -17881,7 +17893,8 @@ no check options or the @code{QUICK} option. The later should be used
 when you are in a hurry and can take the very small risk that
 @code{QUICK} didn't find an error in the data file (In most cases
 @strong{MySQL} should find, under normal usage, any error in the data
-file. If this happens then the table will be marked as 'corrupted'.
+file. If this happens then the table will be marked as 'corrupted',
+in which case the table can't be used until it's repaired).
 
 @code{FAST} and @code{CHANGED} are mostly intended to be used from a
 script (for example to be executed from cron) if you want to check your
@@ -17988,7 +18001,7 @@ the table will not be analyzed again.
 @section @code{REPAIR TABLE} syntax
 
 @example
-REPAIR TABLE tbl_name[,tbl_name...] [TYPE = QUICK]
+REPAIR TABLE tbl_name[,tbl_name...] [QUICK]
 @end example
 
 @code{REPAIR TABLE} only works on @code{MyISAM} tables and is the same things
@@ -18012,7 +18025,7 @@ repairing the table with @code{myisamchk -o}, as @code{REPAIR TABLE}
 does not yet implement all the options of @code{myisamchk}. In the near
 future, we will make it more flexible.
 
-If @code{TYPE=QUICK} is given then @strong{MySQL} will try to do a
+If @code{QUICK} is given then @strong{MySQL} will try to do a
 @code{REPAIR} of only the index tree.
 
 @findex DELETE
@@ -19692,7 +19705,7 @@ indicates 16 megabytes.  The case of suffix letters does not matter;
 @table @code
 @item @code{ansi_mode}.
 Is @code{ON} if @code{mysqld} was started with @code{--ansi}.
-@xref{Ansi mode}.
+@xref{ANSI mode}.
 
 @item @code{back_log}
 The number of outstanding connection requests @strong{MySQL} can have. This
@@ -37858,6 +37871,13 @@ though, so 3.23 is not released as a stable version yet.
 @appendixsubsec Changes in release 3.23.26
 @itemize @bullet
 @item
+Automatic repair of @code{MyISAM} tables if you start @code{mysqld} with
+@code{--myisam-recover}.
+@item
+Removed the @code{TYPE=} keyword from @code{CHECK} and
+@code{REPAIR}. Allow one to combine @code{CHECK} options. (One can still
+use @code{TYPE=} but this usage is deprecated).
+@item
 Added optimization of queries where @code{DISTINCT} is only used on columns
 from some of the tables.
 @item
diff --git a/include/my_base.h b/include/my_base.h
index dd9dafc5fb..033b38672d 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -46,6 +46,7 @@
 #define HA_OPEN_TMP_TABLE		4	/* Table is a temp table */
 #define HA_OPEN_DELAY_KEY_WRITE		8	/* Don't update index  */
 #define HA_OPEN_ABORT_IF_CRASHED	16
+#define HA_OPEN_FOR_REPAIR		32	/* open even if crashed */
 
 	/* The following is parameter to ha_rkey() how to use key */
 
diff --git a/include/myisam.h b/include/myisam.h
index 5d7ef6325d..0183098a38 100644
--- a/include/myisam.h
+++ b/include/myisam.h
@@ -308,22 +308,23 @@ typedef struct st_sort_info {
 
 typedef struct st_mi_check_param
 {
+  ulonglong auto_increment_value;
+  ulonglong max_data_file_length;
+  ulonglong keys_in_use;
+  my_off_t search_after_block;
+  my_off_t new_file_pos,key_file_blocks;
+  my_off_t keydata,totaldata,key_blocks,start_check_pos;
+  ha_rows total_records,total_deleted;
+  ha_checksum record_checksum,glob_crc;
   ulong	use_buffers,read_buffer_length,write_buffer_length,
 	sort_buffer_length,sort_key_blocks;
   uint out_flag,warning_printed,error_printed,
        opt_rep_quick,verbose;
   uint opt_sort_key,total_files,max_level;
+  uint testflag;
   uint8 language;
   my_bool using_global_keycache, opt_lock_memory, opt_follow_links;
-  uint testflag;
-  ha_rows total_records,total_deleted;
-  ulonglong auto_increment_value;
-  my_off_t search_after_block;
-  ulonglong max_data_file_length;
-  ulonglong keys_in_use;
-  my_off_t new_file_pos,key_file_blocks;
-  my_off_t keydata,totaldata,key_blocks,start_check_pos;
-  ha_checksum record_checksum,glob_crc;
+  my_bool retry_repair,retry_without_quick;
   char temp_filename[FN_REFLEN],*isam_file_name,*tmpdir;
   int tmpfile_createflag;
   myf myf_rw;
diff --git a/myisam/ft_update.c b/myisam/ft_update.c
index 7cfce1158f..658ea9282f 100644
--- a/myisam/ft_update.c
+++ b/myisam/ft_update.c
@@ -64,7 +64,7 @@ static FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, byte *keybuf,
       return NULL;
   }
   /* Handle the case where all columns are NULL */
-  if (!parsed && !(parsed=ft_parse(0, "", 0)))
+  if (!parsed && !(parsed=ft_parse(0, (byte*) "", 0)))
     return NULL;
   return ft_linearize(info, keynr, keybuf, parsed);
 }
diff --git a/myisam/mi_check.c b/myisam/mi_check.c
index c6a07ff9c3..a35ccc7edf 100644
--- a/myisam/mi_check.c
+++ b/myisam/mi_check.c
@@ -192,6 +192,7 @@ int chk_del(MI_CHECK *param, register MI_INFO *info, uint test_flag)
   }
   DBUG_RETURN(0);
 wrong:
+  param->retry_without_quick=1;		// Don't use quick repair
   if (test_flag & T_VERBOSE) puts("");
   mi_check_print_error(param,"record delete-link-chain corrupted");
   DBUG_RETURN(1);
@@ -291,6 +292,7 @@ int chk_size(MI_CHECK *param, register MI_INFO *info)
       error=1;
       mi_check_print_error(param,"Size of datafile is: %-8s         Should be: %s",
 		    llstr(size,buff), llstr(skr,buff2));
+      param->retry_without_quick=1;		// Don't use quick repair
     }
     else
     {
@@ -750,8 +752,9 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
 	  {
 	    if (block_info.block_len < info->s->base.min_block_length)
 	    {
-	      mi_check_print_error(param,"Deleted block with impossible length %lu at %s",
-			  block_info.block_len,llstr(pos,llbuff));
+	      mi_check_print_error(param,
+				   "Deleted block with impossible length %lu at %s",
+				   block_info.block_len,llstr(pos,llbuff));
 	      goto err2;
 	    }
 	    if ((block_info.next_filepos != HA_OFFSET_ERROR &&
@@ -1071,7 +1074,7 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
   new_file= -1;
   if (!(param->testflag & T_SILENT))
   {
-    printf("- recovering MyISAM-table '%s'\n",name);
+    printf("- recovering (with keycache) MyISAM-table '%s'\n",name);
     printf("Data records: %s\n", llstr(info->state->records,llbuff));
   }
 
@@ -1211,6 +1214,7 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
     mi_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
     mi_check_print_error(param,"Run recovery again without -q");
     got_error=1;
+    param->retry_repair=param->retry_without_quick=1;
     goto err;
   }
 
@@ -1651,7 +1655,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
     share->pack.header_length;
   if (!(param->testflag & T_SILENT))
   {
-    printf("- recovering MyISAM-table '%s'\n",name);
+    printf("- recovering (with sort) MyISAM-table '%s'\n",name);
     printf("Data records: %s\n", llstr(start_records,llbuff));
   }
   bzero((char*) sort_info,sizeof(*sort_info));
@@ -1805,7 +1809,10 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
     if (_create_index_by_sort(&sort_param,
 			      (my_bool) (!(param->testflag & T_VERBOSE)),
 			      (uint) param->sort_buffer_length))
+    {
+      param->retry_repair=1;
       goto err;
+    }
 
     /* Set for next loop */
     sort_param.max_records=sort_info->max_records=
@@ -1862,6 +1869,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
     mi_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
     mi_check_print_error(param,"Run recovery again without -q");
     got_error=1;
+    param->retry_repair=param->retry_without_quick=1;
     goto err;
   }
 
@@ -3037,7 +3045,8 @@ void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows)
   even if the temporary file would be quite big!
 */
 
-my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows, my_bool force)
+my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows, 
+			    my_bool force __attribute__((unused)))
 {
   MYISAM_SHARE *share=info->s;
   uint i;
diff --git a/myisam/mi_open.c b/myisam/mi_open.c
index cb19011fea..942b4cee49 100644
--- a/myisam/mi_open.c
+++ b/myisam/mi_open.c
@@ -174,9 +174,10 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
     disk_pos=my_n_base_info_read(disk_cache+base_pos, &share->base);
     share->state.state_length=base_pos;
 
-    if ((open_flags & HA_OPEN_ABORT_IF_CRASHED) &&
+    if (!(open_flags & HA_OPEN_FOR_REPAIR) &&
 	((share->state.changed & STATE_CRASHED) ||
-	 (my_disable_locking && share->state.open_count)))
+	 ((open_flags & HA_OPEN_ABORT_IF_CRASHED) &&
+	  (my_disable_locking && share->state.open_count))))
     {
       DBUG_PRINT("error",("Table is marked as crashed"));
       my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c
index c1d3e8873f..7fad3349d3 100644
--- a/myisam/myisamchk.c
+++ b/myisam/myisamchk.c
@@ -92,7 +92,7 @@ int main(int argc, char **argv)
   error=0;
   while (--argc >= 0)
   {
-    error|= myisamchk(&check_param, *(argv++));
+    int new_error=myisamchk(&check_param, *(argv++));
     VOID(fflush(stdout));
     VOID(fflush(stderr));
     if ((check_param.error_printed | check_param.warning_printed) &&
@@ -101,13 +101,16 @@ int main(int argc, char **argv)
 				   T_SORT_INDEX))))
     {
       uint old_testflag=check_param.testflag;
-      check_param.testflag|=T_REP;
+      if (!(check_param.testflag & T_REP))
+	check_param.testflag|= T_REP_BY_SORT;
       check_param.testflag&= ~T_EXTEND;			/* Don't needed  */
       error|=myisamchk(&check_param, argv[-1]);
       check_param.testflag= old_testflag;
       VOID(fflush(stdout));
       VOID(fflush(stderr));
     }
+    else
+      error|=new_error;
     if (argc && (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO))
     {
       puts("\n---------\n");
@@ -193,7 +196,7 @@ static struct option long_options[] =
 
 static void print_version(void)
 {
-  printf("%s  Ver 1.32 for %s at %s\n",my_progname,SYSTEM_TYPE,
+  printf("%s  Ver 1.34 for %s at %s\n",my_progname,SYSTEM_TYPE,
 	 MACHINE_TYPE);
 }
 
@@ -229,7 +232,7 @@ static void usage(void)
   -f, --force         Restart with -r if there are any errors in the table\n\
   -i, --information   Print statistics information about table that is checked\n\
   -m, --medium-check  Faster than extended-check, but only finds 99.99% of\n\
-		      all errors.  Should however be good enough for most cases\n\
+		      all errors.  Should be good enough for most cases\n\
   -U  --update-state  Mark tables as crashed if you find any errors\n\
   -T, --read-only     Don't mark table as checked\n");
 
@@ -488,10 +491,11 @@ static int myisamchk(MI_CHECK *param, my_string filename)
   if (!(info=mi_open(filename,
 		     (param->testflag & (T_DESCRIPT | T_READONLY)) ?
 		     O_RDONLY : O_RDWR,
-		     (param->testflag & T_WAIT_FOREVER) ?
-		     HA_OPEN_WAIT_IF_LOCKED :
-		     (param->testflag & T_DESCRIPT) ?
-		     HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED)))
+		     HA_OPEN_FOR_REPAIR |
+		     ((param->testflag & T_WAIT_FOREVER) ?
+		      HA_OPEN_WAIT_IF_LOCKED :
+		      (param->testflag & T_DESCRIPT) ?
+		      HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
   {
     /* Avoid twice printing of isam file name */
     param->error_printed=1;
@@ -748,8 +752,8 @@ static int myisamchk(MI_CHECK *param, my_string filename)
       error =chk_size(param,info);
       if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
 	error|=chk_del(param, info,param->testflag);
-      if ((!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
-	   !param->start_check_pos))
+      if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
+		      !param->start_check_pos)))
       {
 	error|=chk_key(param, info);
 	if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
diff --git a/myisam/sort.c b/myisam/sort.c
index 80f9b0b036..436fa5a3c6 100644
--- a/myisam/sort.c
+++ b/myisam/sort.c
@@ -155,10 +155,10 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
 	printf("  - Merging %lu keys\n",records);
       if (merge_many_buff(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile))
 	goto err;
-      if (flush_io_cache(&tempfile) ||
-	  reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
-      goto err;
     }
+    if (flush_io_cache(&tempfile) ||
+	reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
+      goto err;
     if (!no_messages)
       puts("  - Last merge and dumping keys");
     if (merge_index(info,keys,sort_keys,buffpek,maxbuffer,&tempfile))
diff --git a/mysys/charset.c b/mysys/charset.c
index 54b4dd1a13..16536b581b 100644
--- a/mysys/charset.c
+++ b/mysys/charset.c
@@ -67,7 +67,7 @@ static char *name_from_csnum(CS_ID **cs, uint number)
     for (c = cs; *c; ++c)
       if ((*c)->number == number)
 	return (*c)->name;
-  return "?";   /* this mimics find_type() */
+  return (char*) "?";   /* this mimics find_type() */
 }
 
 static my_bool get_word(struct simpleconfig_buf_st *fb, char *buf)
@@ -487,7 +487,7 @@ char * list_charsets(myf want_flags)
   {
     CS_ID **c;
     char buf[FN_REFLEN];
-    MY_STAT stat;
+    MY_STAT status;
 
     if((c=available_charsets))
       for (; *c; ++c)
@@ -495,7 +495,7 @@ char * list_charsets(myf want_flags)
 	  if (charset_in_string((*c)->name, &s))
 	    continue;
 	  get_charset_conf_name((*c)->number, buf);
-	  if (!my_stat(buf, &stat, MYF(0)))
+	  if (!my_stat(buf, &status, MYF(0)))
 	    continue;       /* conf file doesn't exist */
 	  dynstr_append(&s, (*c)->name);
 	  dynstr_append(&s, " ");
diff --git a/mysys/default.c b/mysys/default.c
index dda96d5092..e7e2e7cc8f 100644
--- a/mysys/default.c
+++ b/mysys/default.c
@@ -148,7 +148,7 @@ void load_defaults(const char *conf_file, const char **groups,
 #endif
     for (dirs=default_directories ; *dirs; dirs++)
     {
-      int error;
+      int error=0;
       if (**dirs)
 	error=search_default_file(&args, &alloc, *dirs, conf_file,
 				  default_ext, &group);
@@ -359,7 +359,12 @@ void print_defaults(const char *conf_file, const char **groups)
 #endif
     for (dirs=default_directories ; *dirs; dirs++)
     {
-      strmov(name,*dirs);
+      if (**dirs)
+	strmov(name,*dirs);
+      else if (defaults_extra_file)
+	strmov(name,defaults_extra_file);
+      else
+	continue;
       convert_dirname(name);
       if (name[0] == FN_HOMELIB)	/* Add . to filenames in home */
 	strcat(name,".");
@@ -377,6 +382,7 @@ void print_defaults(const char *conf_file, const char **groups)
   puts("\nThe following options may be given as the first argument:\n\
 --print-defaults	Print the program argument list and exit\n\
 --no-defaults		Don't read default options from any options file\n\
---defaults-file=#	Only read default options from the given file #");
+--defaults-file=#	Only read default options from the given file #\n\
+--defaults-extra-file=# Read this file after the global files are read");
 }
 
diff --git a/mysys/mf_tempfile.c b/mysys/mf_tempfile.c
index 8370c6e7ec..44826ad57c 100644
--- a/mysys/mf_tempfile.c
+++ b/mysys/mf_tempfile.c
@@ -36,7 +36,8 @@ extern char **environ;
 */
 
 File create_temp_file(char *to, const char *dir, const char *prefix,
-		      int mode, myf MyFlags)
+		      int mode __attribute__((unused)),
+		      myf MyFlags __attribute__((unused)))
 {
   File file= -1;
   DBUG_ENTER("open_temp_file");
@@ -85,12 +86,12 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
   }
 #elif defined(HAVE_MKSTEMP)
   {
-    char prefix[30];
+    char prefix_buff[30];
     uint pfx_len;
 
-    pfx_len=(strmov(strnmov(prefix,
+    pfx_len=(strmov(strnmov(prefix_buff,
 			    prefix ? prefix : "tmp.",
-			    sizeof(prefix)-7),"XXXXXX") - prefix);
+			    sizeof(prefix_buff)-7),"XXXXXX") - prefix_buff);
     if (!dir && ! (dir =getenv("TMPDIR")))
       dir=P_tmpdir;
     if (strlen(dir)+ pfx_len > FN_REFLEN-2)
diff --git a/mysys/my_init.c b/mysys/my_init.c
index 4e7d1b6b2d..3b5eb83f9f 100644
--- a/mysys/my_init.c
+++ b/mysys/my_init.c
@@ -48,7 +48,7 @@ static my_bool win32_init_tcp_ip();
 static my_bool my_init_done=0;
 
 
-ulong atoi_octal(const char *str)
+static ulong atoi_octal(const char *str)
 {
   long int tmp;
   while (*str && isspace(*str))
diff --git a/mysys/my_pread.c b/mysys/my_pread.c
index 74bb7783af..4e0de71bcf 100644
--- a/mysys/my_pread.c
+++ b/mysys/my_pread.c
@@ -80,7 +80,6 @@ uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
 uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset,
 	       myf MyFlags)
 {
-  int error;
   uint writenbytes,errors;
   ulong written;
   DBUG_ENTER("my_pwrite");
@@ -91,6 +90,7 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset,
   for (;;)
   {
 #ifndef HAVE_PREAD
+    int error;
     writenbytes= (uint) -1;
     pthread_mutex_lock(&my_file_info[Filedes].mutex);
     error=(lseek(Filedes, offset, MY_SEEK_SET) != -1L &&
diff --git a/sql-bench/server-cfg.sh b/sql-bench/server-cfg.sh
index a49893c53e..fa273ab8bd 100755
--- a/sql-bench/server-cfg.sh
+++ b/sql-bench/server-cfg.sh
@@ -161,6 +161,7 @@ sub new
   $limits{'func_extra_in_num'}	= 1; # Has function in
   $limits{'limit'}		= 1;		# supports the limit attribute
   $limits{'unique_index'}	= 1; # Unique index works or not
+  $limits{'insert_select'}	= 1;
 
   $smds{'time'}			= 1;
   $smds{'q1'} 	= 'b';		# with time not supp by mysql ('')
@@ -378,6 +379,7 @@ sub new
   $limits{'group_func_extra_std'} = 0;
   $limits{'limit'}		= 1;		# supports the limit attribute
   $limits{'unique_index'}	= 1; # Unique index works or not
+  $limits{'insert_select'}	= 0;
 
   $limits{'func_odbc_mod'}	= 0;
   $limits{'func_extra_%'}	= 0;
@@ -576,6 +578,7 @@ sub new
   $limits{'max_text_size'}	= 7000;		# 8000 crashes pg 6.3
   $limits{'query_size'}		= 16777216;
   $limits{'unique_index'}	= 1; # Unique index works or not
+  $limits{'insert_select'}	= 1;
 
   # the different cases per query ...
   $smds{'q1'} 	= 'b'; # with time
@@ -849,6 +852,7 @@ sub new
   $limits{'NEG'}		= 1;
   $limits{'func_extra_in_num'}	= 1;
   $limits{'unique_index'}	= 1; # Unique index works or not
+  $limits{'insert_select'}	= 1;
 
   # for the smds small benchmark test ....
   # the different cases per query ...
@@ -1087,6 +1091,7 @@ sub new
   $limits{'NEG'}		= 1;
   $limits{'func_extra_in_num'}	= 0;
   $limits{'unique_index'}	= 1; # Unique index works or not
+  $limits{'insert_select'}	= 1;
 
   # for the smds small benchmark test ....
   # the different cases per query ... EMPRESS
@@ -1364,6 +1369,7 @@ sub new
   $limits{'NEG'}		= 1; # Supports -id
   $limits{'func_extra_in_num'}	= 1; # Has function in
   $limits{'unique_index'}	= 1; # Unique index works or not
+  $limits{'insert_select'}	= 1;
 
   $smds{'time'}			= 1;
   $smds{'q1'} 	= 'b';		# with time not supp by mysql ('')
@@ -1612,6 +1618,7 @@ sub new
   $limits{'subqueries'}		= 1; # Doesn't support sub-queries.
   $limits{'table_wildcard'}	= 1; # Has SELECT table_name.*
   $limits{'unique_index'}	= 1; # Unique index works or not
+  $limits{'insert_select'}	= 1;
 
   return $self;
 }
@@ -1809,6 +1816,7 @@ sub new
   $limits{'NEG'}		= 1; # Supports -id
   $limits{'func_extra_in_num'}	= 1; # Has function in
   $limits{'unique_index'}	= 1; # Unique index works or not
+  $limits{'insert_select'}	= 1;
   return $self;
 }
 
@@ -1980,6 +1988,7 @@ sub new
   $limits{'NEG'}		= 1; # Supports -id
   $limits{'func_extra_in_num'}	= 0; # Has function in
   $limits{'unique_index'}	= 1; # Unique index works or not
+  $limits{'insert_select'}	= 1;
   return $self;
 }
 
@@ -2163,6 +2172,7 @@ sub new
   $limits{'NEG'}		= 1; # Supports -id
   $limits{'func_extra_in_num'}	= 0; # Has function in
   $limits{'unique_index'}	= 1; # Unique index works or not
+  $limits{'insert_select'}	= 1;
   return $self;
 }
 
@@ -2349,6 +2359,7 @@ sub new
   $limits{'NEG'}		= 1; # Supports -id
   $limits{'func_extra_in_num'}	= 1; # Has function in
   $limits{'unique_index'}	= 1; # Unique index works or not
+  $limits{'insert_select'}	= 1;
 
   $smds{'time'}			= 1;
   $smds{'q1'} 	= 'b';		# with time not supp by mysql ('')
@@ -2558,6 +2569,7 @@ sub new
   $limits{'NEG'}		= 1; # Supports -id
   $limits{'func_extra_in_num'}	= 0; # Has function in
   $limits{'unique_index'}	= 1; # Unique index works or not
+  $limits{'insert_select'}	= 1;
   return $self;
 }
 
@@ -2726,6 +2738,7 @@ sub new
   $limits{'func_extra_in_num'}	= 1; # Has function in
   $limits{'limit'}		= 0; # Does not support the limit attribute
   $limits{'unique_index'}	= 1; # Unique index works or not
+  $limits{'insert_select'}	= 1;
 
   $smds{'time'}			= 1;
   $smds{'q1'} 	= 'b';		# with time not supp by mysql ('')
diff --git a/sql-bench/test-insert.sh b/sql-bench/test-insert.sh
index 93f6745742..129c37fac0 100755
--- a/sql-bench/test-insert.sh
+++ b/sql-bench/test-insert.sh
@@ -97,6 +97,8 @@ goto select_test if ($opt_skip_create);
 
 print "Creating tables\n";
 $dbh->do("drop table bench1");
+$dbh->do("drop table bench2");
+$dbh->do("drop table bench3");
 do_many($dbh,$server->create("bench1",
 			     ["id int NOT NULL",
 			      "id2 int NOT NULL",
@@ -240,7 +242,7 @@ if ($limits->{'unique_index'})
 }
 
 $end_time=new Benchmark;
-print "Time for insert_duplicates (" . ($total_rows) . "): " .
+print "Time for insert_duplicates (" . ($opt_loop_count) . "): " .
   timestr(timediff($end_time, $loop_time),"all") . "\n\n";
 
 #if ($opt_fast && defined($server->{vacuum}))
@@ -611,7 +613,7 @@ if ($limits->{'functions'})
   }
 
   $end_time=new Benchmark;
-  print "Time for update_of_key ($range_loop_count):  " .
+  print "Time for update_of_key ($update_loop_count):  " .
     timestr(timediff($end_time, $loop_time),"all") . "\n";
 
   if ($opt_lock_tables)
@@ -775,7 +777,7 @@ for ($i=0 ; $i < $opt_loop_count*3 ; $i++)
 }
 
 $end_time=new Benchmark;
-print "Time for update_with_key ($opt_loop_count):  " .
+print "Time for update_with_key (" . ($opt_loop_count*3) . "):  " .
   timestr(timediff($end_time, $loop_time),"all") . "\n";
 
 print "\nTesting update of all rows\n";
@@ -785,7 +787,7 @@ for ($i=0 ; $i < $small_loop_count ; $i++)
   $sth = $dbh->do("update bench1 set dummy1='updated $i'") or die $DBI::errstr;
 }
 $end_time=new Benchmark;
-print "Time for update_big ($range_loop_count):  " .
+print "Time for update_big ($small_loop_count):  " .
   timestr(timediff($end_time, $loop_time),"all") . "\n";
 
 
@@ -859,6 +861,49 @@ if ($server->small_rollback_segment())
   $dbh = $server->connect();
 }
 
+####
+#### Test INSERT INTO ... SELECT
+####
+
+if ($limits->{'insert_select'})
+{
+  print "\nTesting INSERT INTO ... SELECT\n";
+  do_many($dbh,$server->create("bench2",
+			       ["id int NOT NULL",
+				"id2 int NOT NULL",
+				"id3 int NOT NULL",
+				"dummy1 char(30)"],
+			       ["primary key (id,id2)"]));
+  do_many($dbh,$server->create("bench3",
+			       ["id int NOT NULL",
+				"id2 int NOT NULL",
+				"id3 int NOT NULL",
+				"dummy1 char(30)"],
+			       ["primary key (id,id2)",
+				"index index_id3 (id3)"]));
+  $loop_time=new Benchmark;
+  $sth = $dbh->do("INSERT INTO bench2 SELECT * from bench1") ||
+    die $DBI::errstr;
+  $end_time=new Benchmark;
+  print "Time for insert_select_1_key (1):  " .
+    timestr(timediff($end_time, $loop_time),"all") . "\n";
+  $loop_time=new Benchmark;
+  $sth = $dbh->do("INSERT INTO bench3 SELECT * from bench1") ||
+    die $DBI::errstr;
+  $end_time=new Benchmark;
+  print "Time for insert_select_2_keys (1):  " .
+    timestr(timediff($end_time, $loop_time),"all") . "\n";
+  $loop_time=new Benchmark;
+  $sth = $dbh->do("DROP TABLE bench2") ||
+    die $DBI::errstr;
+  $sth = $dbh->do("DROP TABLE bench3") ||
+    die $DBI::errstr;
+  $end_time=new Benchmark;
+  print "Time for drop table(2): " .
+    timestr(timediff($end_time, $loop_time),"all") . "\n";
+}
+
+
 ####
 #### Do some deletes on the table
 ####
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 698a4f64d1..5cb4432dea 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -254,7 +254,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
 				  STATE_CRASHED_ON_REPAIR)) &&
 	share->state.open_count == 0) ||
        ((param.testflag & T_FAST) && (share->state.open_count ==
-				      (share->global_changed ? 1 : 0)))))
+				      (uint) (share->global_changed ? 1 : 0)))))
     return HA_ADMIN_ALREADY_DONE;
 
   error = chk_size(&param, file);
@@ -298,6 +298,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
     mi_mark_crashed(file);
     file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
   }
+  check_opt->retry_without_quick=param.retry_without_quick;
 
   return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
 }
@@ -317,7 +318,7 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt)
 
   myisamchk_init(&param);
   param.thd = thd;
-  param.op_name = (char*)" analyze";
+  param.op_name = (char*) "analyze";
   param.table_name = table->table_name;
   param.testflag=(T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
 		  T_DONT_CHECK_CHECKSUM);
@@ -338,6 +339,7 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt)
   return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
 }
 
+
 int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
 {
   HA_CHECK_OPT tmp_check_opt;
@@ -404,6 +406,7 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
 
 int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
 {
+  int error;
   if (!file) return HA_ADMIN_INTERNAL_ERROR;
   MI_CHECK param;
 
@@ -415,7 +418,21 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
   if (check_opt->quick)
     param.opt_rep_quick++;
   param.sort_buffer_length=  check_opt->sort_buffer_size;
-  return repair(thd,param,0);
+  while ((error=repair(thd,param,0)))
+  {
+    if (param.retry_without_quick && param.opt_rep_quick)
+    {
+      param.opt_rep_quick=0;
+      continue;
+    }
+    if ((param.testflag & T_REP_BY_SORT))
+    {
+      param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;      
+      continue;
+    }
+    break;
+  }
+  return error;
 }
 
 int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt)
@@ -576,19 +593,19 @@ bool ha_myisam::activate_all_index(THD *thd)
 }
 
 
-bool ha_myisam::check_and_repair(THD *thd, const char *name)
+bool ha_myisam::check_and_repair(THD *thd)
 {
   int error=0;
   HA_CHECK_OPT check_opt;
   DBUG_ENTER("ha_myisam::auto_check_and_repair");
 
-  if (open(name, O_RDWR, HA_OPEN_WAIT_IF_LOCKED))
-    DBUG_RETURN(1);
-
   check_opt.init();
-  check_opt.flags=T_MEDIUM;
+  check_opt.flags= T_MEDIUM;
+  check_opt.quick= !file->state->del;	// Don't use quick if deleted rows
   if (mi_is_crashed(file) || check(thd, &check_opt))
   {
+    if (check_opt.retry_without_quick)
+      check_opt.quick=0;
     check_opt.flags=(((myisam_recover_options & HA_RECOVER_BACKUP) ? 
 		      T_BACKUP_DATA : 0) |
 		     (!(myisam_recover_options & HA_RECOVER_FORCE) ? 
@@ -596,11 +613,14 @@ bool ha_myisam::check_and_repair(THD *thd, const char *name)
     if (repair(thd, &check_opt))
       error=1;
   }
-  if (close())
-    error=1;
   DBUG_RETURN(error);
 }
 
+bool ha_myisam::is_crashed() const
+{
+  return (file->s->state.changed & STATE_CRASHED ||
+	  (my_disable_locking && file->s->state.open_count));
+}
 
 int ha_myisam::update_row(const byte * old_data, byte * new_data)
 {
diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h
index d33fc52c93..ff959ead88 100644
--- a/sql/ha_myisam.h
+++ b/sql/ha_myisam.h
@@ -45,8 +45,7 @@ class ha_myisam: public handler
 		    HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER |  HA_LASTKEY_ORDER |
 		    HA_HAVE_KEY_READ_ONLY | HA_READ_NOT_EXACT_KEY |
 		    HA_LONGLONG_KEYS |  HA_NULL_KEY |
-		    HA_DUPP_POS | HA_BLOB_KEY | HA_AUTO_PART_KEY |
-		    HA_CHECK_AND_REPAIR)
+		    HA_DUPP_POS | HA_BLOB_KEY | HA_AUTO_PART_KEY)
   {}
   ~ha_myisam() {}
   const char *table_type() const { return "MyISAM"; }
@@ -103,7 +102,9 @@ class ha_myisam: public handler
   int check(THD* thd, HA_CHECK_OPT* check_opt);
   int analyze(THD* thd,HA_CHECK_OPT* check_opt);
   int repair(THD* thd, HA_CHECK_OPT* check_opt);
-  bool check_and_repair(THD *thd, const char *name);
+  bool check_and_repair(THD *thd);
+  bool is_crashed() const;
+  bool auto_repair() const { return myisam_recover_options != 0; }
   int optimize(THD* thd, HA_CHECK_OPT* check_opt);
   int restore(THD* thd, HA_CHECK_OPT* check_opt);
   int backup(THD* thd, HA_CHECK_OPT* check_opt);
diff --git a/sql/handler.h b/sql/handler.h
index d256ee944e..1457c033ed 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -66,7 +66,6 @@
 #define HA_NO_WRITE_DELAYED	(HA_NOT_EXACT_COUNT*2)
 #define HA_PRIMARY_KEY_IN_READ_INDEX (HA_NO_WRITE_DELAYED*2)
 #define HA_DROP_BEFORE_CREATE	(HA_PRIMARY_KEY_IN_READ_INDEX*2)
-#define HA_CHECK_AND_REPAIR	(HA_DROP_BEFORE_CREATE*2)
 
 	/* Parameters for open() (in register form->filestat) */
 	/* HA_GET_INFO does a implicit HA_ABORT_IF_LOCKED */
@@ -146,9 +145,10 @@ typedef struct st_ha_check_opt
   bool quick;
   bool changed_files;
   bool optimize;
+  bool retry_without_quick;
   inline void init()
   {
-    flags= 0; quick= optimize=0;
+    flags= 0; quick= optimize= retry_without_quick=0;
     sort_buffer_size = myisam_sort_buffer_size;
   }
 } HA_CHECK_OPT;
@@ -249,7 +249,7 @@ public:
   virtual void update_create_info(HA_CREATE_INFO *create_info) {}
   virtual int check(THD* thd,   HA_CHECK_OPT* check_opt );
   virtual int repair(THD* thd,  HA_CHECK_OPT* check_opt);
-  virtual bool check_and_repair(THD *thd, const char *name) {return 1;}
+  virtual bool check_and_repair(THD *thd) {return 1;}
   virtual int optimize(THD* thd,HA_CHECK_OPT* check_opt);
   virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt);
   virtual int backup(THD* thd, HA_CHECK_OPT* check_opt);
@@ -274,6 +274,8 @@ public:
   virtual uint max_key_length()const =0;
   virtual uint min_record_length(uint options) const { return 1; }
   virtual bool low_byte_first() const { return 1; }
+  virtual bool is_crashed() const  { return 0; }
+  virtual bool auto_repair() const { return 0; }
 
   virtual int rename_table(const char *from, const char *to);
   virtual int delete_table(const char *name);
diff --git a/sql/lock.cc b/sql/lock.cc
index 7eb42f6b08..4c7ae8e950 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -434,7 +434,10 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
   table_list->table=table;
 
   if (hash_insert(&open_cache, (byte*) table))
+  {
+    my_free((gptr) table,MYF(0));
     DBUG_RETURN(-1);
+  }
   if (remove_table_from_cache(thd, table_list->db, table_list->name))
     DBUG_RETURN(1);					// Table is in use
   DBUG_RETURN(0);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index c73dda5750..5d1aad6695 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -261,7 +261,7 @@ void Log_event::print_header(FILE* file)
 {
   fputc('#', file);
   print_timestamp(file);
-  fprintf(file, " server id  %d ", server_id); 
+  fprintf(file, " server id  %ld ", server_id); 
 }
 
 void Log_event::print_timestamp(FILE* file, time_t* ts = 0)
@@ -709,7 +709,7 @@ void Load_log_event::print(FILE* file, bool short_form)
   }
      
   if((int)skip_lines > 0)
-    fprintf(file, " IGNORE %d LINES ", skip_lines);
+    fprintf(file, " IGNORE %ld LINES ", skip_lines);
 
   if(num_fields)
     {
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index ed018eb333..03b799aee7 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -34,7 +34,7 @@ HASH open_cache;				/* Used by mysql_test */
 
 
 static int open_unireg_entry(TABLE *entry,const char *db,const char *name,
-			     const char *alias);
+			     const char *alias, bool locked);
 static bool insert_fields(THD *thd,TABLE_LIST *tables, const char *table_name,
 			  List_iterator<Item> *it);
 static void free_cache_entry(TABLE *entry);
@@ -572,7 +572,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
   key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
 
   pthread_mutex_lock(&LOCK_open);
-  if (open_unireg_entry(table, db, table_name, table_name) ||
+  if (open_unireg_entry(table, db, table_name, table_name,0) ||
       !(table->table_cache_key =memdup_root(&table->mem_root,(char*) key,
 					    key_length)))
     {
@@ -706,7 +706,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
     /* make a new table */
     if (!(table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME))))
       DBUG_RETURN(NULL);
-    if (open_unireg_entry(table,db,table_name,alias) ||
+    if (open_unireg_entry(table,db,table_name,alias,0) ||
 	!(table->table_cache_key=memdup_root(&table->mem_root,(char*) key,
 					     key_length)))
     {
@@ -816,7 +816,7 @@ bool reopen_table(TABLE *table,bool locked)
   if (!locked)
     VOID(pthread_mutex_lock(&LOCK_open));
 
-  if (open_unireg_entry(&tmp,db,table_name,table->table_name))
+  if (open_unireg_entry(&tmp,db,table_name,table->table_name,locked))
     goto end;
   free_io_cache(table);
 
@@ -1113,23 +1113,72 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name)
 */
 
 static int open_unireg_entry(TABLE *entry,const char *db,const char *name,
-			     const char *alias)
+			     const char *alias, bool locked)
 {
   char path[FN_REFLEN];
+  int error;
   DBUG_ENTER("open_unireg_entry");
 
   (void) sprintf(path,"%s/%s/%s",mysql_data_home,db,name);
   if (openfrm(path,alias,
-	      (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX |
-		      HA_TRY_READ_ONLY),
-	      READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
-	      ha_open_options,
-	      entry))
+	       (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX |
+		       HA_TRY_READ_ONLY),
+	       READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
+		 ha_open_options,
+		 entry))
   {
-    DBUG_RETURN(1);
+    THD *thd=current_thd;
+    if (!entry->crashed)
+      goto err;					// Can't repair the table
+
+    TABLE_LIST table_list;
+    table_list.db=(char*) db;
+    table_list.name=(char*) name;
+    table_list.next=0;
+    if (!locked)
+      pthread_mutex_lock(&LOCK_open);
+    if ((error=lock_table_name(thd,&table_list)))
+    {
+      if (error < 0)
+      {
+	if (!locked)
+	  pthread_mutex_lock(&LOCK_open);
+	goto err;
+      }
+      if (wait_for_locked_table_names(thd,&table_list))
+      {
+	unlock_table_name(thd,&table_list);
+	if (!locked)
+	  pthread_mutex_lock(&LOCK_open);
+	goto err;
+      }
+    }
+    pthread_mutex_unlock(&LOCK_open);
+    thd->net.last_error[0]=0;				// Clear error message
+    thd->net.last_errno=0;
+    error=0;
+    sql_print_error("Warning: Repairing table: %s.%s",db,name);
+    if (openfrm(path,alias,
+		(uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX |
+			 HA_TRY_READ_ONLY),
+		READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
+		ha_open_options | HA_OPEN_FOR_REPAIR,
+		entry) ||
+	(entry->file->is_crashed() && entry->file->check_and_repair(thd)))
+    {
+      sql_print_error("Error: Couldn't repair table: %s.%s",db,name);
+      error=1;
+    }
+    unlock_table_name(thd,&table_list);
+    if (locked)
+      pthread_mutex_lock(&LOCK_open);      // Get back old lock
+    if (error)
+      goto err;
   }
   (void) entry->file->extra(HA_EXTRA_NO_READCHECK);	// Not needed in SQL
   DBUG_RETURN(0);
+err:
+  DBUG_RETURN(1);
 }
 
 
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 796802c0a5..4bee0bf2c3 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -127,7 +127,7 @@ class TMP_TABLE_PARAM {
   uint	group_parts,group_length;
   uint	quick_group;
 
-  TMP_TABLE_PARAM() :group_parts(0),group_length(0),copy_field(0) {}
+  TMP_TABLE_PARAM() :copy_field(0), group_parts(0), group_length(0) {}
   ~TMP_TABLE_PARAM()
   {
     cleanup();
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 3cb40d7d9e..390bfb28fd 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -745,61 +745,61 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table)
 {
   String *packet = &thd->packet;
   
-  if(table->table) // do not overwrite existing tables on restore
-    {
-      return send_check_errmsg(thd, table, "restore",
-			       "table exists, will not overwrite on restore"
-			       );
-    }
+  if (table->table) // do not overwrite existing tables on restore
+  {
+    return send_check_errmsg(thd, table, "restore",
+			     "table exists, will not overwrite on restore"
+			     );
+  }
   else
-    {
-      char* backup_dir = thd->lex.backup_dir;
-      char src_path[FN_REFLEN], dst_path[FN_REFLEN];
-      char* table_name = table->name;
-      char* db = thd->db ? thd->db : table->db;
+  {
+    char* backup_dir = thd->lex.backup_dir;
+    char src_path[FN_REFLEN], dst_path[FN_REFLEN];
+    char* table_name = table->name;
+    char* db = thd->db ? thd->db : table->db;
 	
-      if(!fn_format(src_path, table_name, backup_dir, reg_ext, 4 + 64))
-	return -1; // protect buffer overflow
+    if (!fn_format(src_path, table_name, backup_dir, reg_ext, 4 + 64))
+      return -1; // protect buffer overflow
 	    
-      sprintf(dst_path, "%s/%s/%s", mysql_real_data_home, db, table_name);
+    sprintf(dst_path, "%s/%s/%s", mysql_real_data_home, db, table_name);
 
-      int lock_retcode;
-      pthread_mutex_lock(&LOCK_open);
-      if((lock_retcode = lock_table_name(thd, table)) < 0)
-	{
-	  pthread_mutex_unlock(&LOCK_open);
-	  return -1;
-	}
-      
-      if(lock_retcode && wait_for_locked_table_names(thd, table))
-	{
-          pthread_mutex_unlock(&LOCK_open);
-	  return -1;
-	}
+    int lock_retcode;
+    pthread_mutex_lock(&LOCK_open);
+    if ((lock_retcode = lock_table_name(thd, table)) < 0)
+    {
       pthread_mutex_unlock(&LOCK_open);
+      return -1;
+    }
       
-      if(my_copy(src_path,
-		 fn_format(dst_path, dst_path,"",
-			   reg_ext, 4),
-		 MYF(MY_WME)))
-	{
-           return send_check_errmsg(thd, table, "restore",
-				    "Failed copying .frm file");
-	}
-      bool save_no_send_ok = thd->net.no_send_ok;
-      thd->net.no_send_ok = 1;
-      // generate table will try to send OK which messes up the output
-      // for the client
+    if (lock_retcode && wait_for_locked_table_names(thd, table))
+    {
+      pthread_mutex_unlock(&LOCK_open);
+      return -1;
+    }
+    pthread_mutex_unlock(&LOCK_open);
       
-      if(generate_table(thd, table, 0))
-	{
-	  thd->net.no_send_ok = save_no_send_ok;
-           return send_check_errmsg(thd, table, "restore",
-				    "Failed generating table from .frm file");
-	}
+    if (my_copy(src_path,
+		fn_format(dst_path, dst_path,"",
+			  reg_ext, 4),
+		MYF(MY_WME)))
+    {
+      return send_check_errmsg(thd, table, "restore",
+			       "Failed copying .frm file");
+    }
+    bool save_no_send_ok = thd->net.no_send_ok;
+    thd->net.no_send_ok = 1;
+    // generate table will try to send OK which messes up the output
+    // for the client
       
+    if (generate_table(thd, table, 0))
+    {
       thd->net.no_send_ok = save_no_send_ok;
+      return send_check_errmsg(thd, table, "restore",
+			       "Failed generating table from .frm file");
     }
+      
+    thd->net.no_send_ok = save_no_send_ok;
+  }
 	
   return 0;	
 }
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 1fde60acce..ae1296153e 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1134,8 +1134,13 @@ repair:
 opt_mi_check_type:
 	/* empty */ { Lex->check_opt.flags = T_MEDIUM; }
 	| TYPE_SYM EQ mi_check_types {}
+	| mi_check_types {}
 
 mi_check_types:
+	mi_check_type {}
+	| mi_check_type mi_check_types {}
+
+mi_check_type:
 	QUICK      { Lex->check_opt.quick = 1; }
 	| FAST_SYM { Lex->check_opt.flags|= T_FAST; }
 	| EXTENDED_SYM { Lex->check_opt.flags|= T_EXTEND; }
diff --git a/sql/table.cc b/sql/table.cc
index c7fe81c182..c0c4fd1eba 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -212,17 +212,24 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
   error=2;
   if (db_stat)
   {
-    if ((outparam->file->
-	 ha_open(index_file,
-		 (db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
-		 (db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
-		  (db_stat & HA_WAIT_IF_LOCKED ||
-		   specialflag & SPECIAL_WAIT_IF_LOCKED) ?
-		  HA_OPEN_WAIT_IF_LOCKED :
-		  (db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ?
-		  HA_OPEN_ABORT_IF_LOCKED :
-		  HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags)))
+    int err;
+    if ((err=(outparam->file->
+	      ha_open(index_file,
+		      (db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
+		      (db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
+		       ((db_stat & HA_WAIT_IF_LOCKED) ||
+			(specialflag & SPECIAL_WAIT_IF_LOCKED)) ?
+		       HA_OPEN_WAIT_IF_LOCKED :
+		       (db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ?
+		       HA_OPEN_ABORT_IF_LOCKED :
+		       HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags))))
+    {
+      /* Set a flag if the table is crashed and it can be auto. repaired */
+      outparam->crashed=(err == HA_ERR_CRASHED &&
+			 outparam->file->auto_repair() &&
+			 !(ha_open_flags & HA_OPEN_FOR_REPAIR));
       goto err_not_open; /* purecov: inspected */
+    }
   }
   outparam->db_low_byte_first=outparam->file->low_byte_first();
 
@@ -549,6 +556,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
   delete crypted;
   my_pthread_setspecific_ptr(THR_MALLOC,old_root);
   frm_error(error,outparam,name,ME_ERROR+ME_WAITTANG);
+  delete outparam->file;
   outparam->file=0;				// For easyer errorchecking
   free_root(&outparam->mem_root,MYF(0));
   my_free(outparam->table_name,MYF(MY_ALLOW_ZERO_PTR));
diff --git a/sql/table.h b/sql/table.h
index f7d81e690e..4f17bbf9c4 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -92,6 +92,7 @@ struct st_table {
   my_bool db_low_byte_first;		/* Portable row format */
   my_bool locked_by_flush;
   my_bool locked_by_name;
+  my_bool crashed;
   Field *next_number_field,		/* Set if next_number is activated */
 	*found_next_number_field,	/* Set on open */
         *rowid_field;
-- 
2.30.9