Commit 09dce662 authored by monty@tik.mysql.com's avatar monty@tik.mysql.com

Automatic repair of MyISAM tables + portability fixes

parent 16f11f94
monty@tramp.mysql.fi
monty@donna.mysql.com
monty@tik.mysql.com
This diff is collapsed.
......@@ -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 */
......
......@@ -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;
......
......@@ -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);
}
......
......@@ -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;
......
......@@ -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) ?
......
......@@ -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)))
......
......@@ -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))
......
......@@ -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, " ");
......
......@@ -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");
}
......@@ -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)
......
......@@ -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))
......
......@@ -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 &&
......
......@@ -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 ('')
......
......@@ -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
####
......
......@@ -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)
{
......
......@@ -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);
......
......@@ -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 @@ class handler :public Sql_alloc
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 @@ class handler :public Sql_alloc
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);
......
......@@ -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);
......
......@@ -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)
{
......
......@@ -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);
}
......
......@@ -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();
......
......@@ -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;
}
......
......@@ -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; }
......
......@@ -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));
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment