From c39be2d0e7e4df339617efc96e1a38aab36be82b Mon Sep 17 00:00:00 2001 From: "ingo@mysql.com" <> Date: Thu, 23 Dec 2004 20:11:38 +0100 Subject: [PATCH] WL#1895 - Print message to error log in case of detected MyISAM corruption Changed my_error() to print error messages, which come from arbitrary registered ranges of error messages. Messages can be unregistered (and should be at end of the program). Added registration of handler error messages. Added a new mi_print_error() macro and a new mi_report_error() function, which supply error messages with a table name. Added calls to mi_print_error() or mi_report_error() at all places in MyISAM, where table corruption is detected. --- extra/comp_err.c | 9 +- include/errmsg.h | 7 ++ include/my_base.h | 6 ++ include/my_sys.h | 5 +- include/mysys_err.h | 10 ++- libmysql/errmsg.c | 28 ++++++- libmysql/libmysql.c | 1 + myisam/mi_delete.c | 32 +++++++- myisam/mi_extra.c | 5 ++ myisam/mi_info.c | 33 ++++++++ myisam/mi_key.c | 1 + myisam/mi_keycache.c | 1 + myisam/mi_locking.c | 6 ++ myisam/mi_open.c | 13 +++ myisam/mi_page.c | 2 + myisam/mi_range.c | 4 + myisam/mi_rkey.c | 1 + myisam/mi_search.c | 17 +++- myisam/mi_update.c | 9 ++ myisam/mi_write.c | 20 +++++ myisam/myisamdef.h | 3 + mysql-test/r/merge.result | 4 +- mysql-test/r/repair.result | 2 +- mysql-test/t/merge.test | 4 +- mysys/errors.c | 6 +- mysys/my_error.c | 163 ++++++++++++++++++++++++++++++++++--- sql/derror.cc | 64 +++++++++++---- sql/handler.cc | 101 +++++++++++++++++++++++ sql/mysqld.cc | 4 +- sql/table.cc | 9 +- sql/unireg.h | 4 +- 31 files changed, 518 insertions(+), 56 deletions(-) diff --git a/extra/comp_err.c b/extra/comp_err.c index 9ddd1d7d971..8bc8a989a6a 100644 --- a/extra/comp_err.c +++ b/extra/comp_err.c @@ -191,10 +191,11 @@ int main(int argc, char *argv[]) static int create_header_files(struct errors *error_head) { - uint er_count= 0; + uint er_last; FILE *er_definef, *sql_statef; struct errors *tmp_error; DBUG_ENTER("create_header_files"); + LINT_INIT(er_last); if (!(er_definef= my_fopen(HEADERFILE, O_WRONLY, MYF(MY_WME)))) { @@ -209,6 +210,8 @@ static int create_header_files(struct errors *error_head) fprintf(er_definef, "/* Autogenerated file, please don't edit */\n\n"); fprintf(sql_statef, "/* Autogenerated file, please don't edit */\n\n"); + fprintf(er_definef, "#define ER_ERROR_FIRST %d\n", error_head->d_code); + for (tmp_error= error_head; tmp_error; tmp_error= tmp_error->next_error) { /* @@ -217,16 +220,16 @@ static int create_header_files(struct errors *error_head) */ fprintf(er_definef, "#define %s %d\n", tmp_error->er_name, tmp_error->d_code); + er_last= tmp_error->d_code; /* generating sql_state.h file */ if (tmp_error->sql_code1[0] || tmp_error->sql_code2[0]) fprintf(sql_statef, "%-40s,\"%s\", \"%s\",\n", tmp_error->er_name, tmp_error->sql_code1, tmp_error->sql_code2); - er_count++; } /* finishing off with mysqld_error.h */ - fprintf(er_definef, "#define ER_ERROR_MESSAGES %d\n", er_count); + fprintf(er_definef, "#define ER_ERROR_LAST %d\n", er_last); my_fclose(er_definef, MYF(0)); my_fclose(sql_statef, MYF(0)); DBUG_RETURN(0); diff --git a/include/errmsg.h b/include/errmsg.h index 6115b24a3d8..55bbdf6d767 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -21,6 +21,7 @@ extern "C" { #endif void init_client_errs(void); +void finish_client_errs(void); extern const char *client_errors[]; /* Error messages */ #ifdef __cplusplus } @@ -35,6 +36,9 @@ extern const char *client_errors[]; /* Error messages */ #endif #define CLIENT_ERRMAP 2 /* Errormap used by my_error() */ +/* Do not add error numbers before CR_ERROR_FIRST. */ +/* If necessary to add lower numbers, change CR_ERROR_FIRST accordingly. */ +#define CR_ERROR_FIRST 2000 /*Copy first error nr.*/ #define CR_UNKNOWN_ERROR 2000 #define CR_SOCKET_CREATE_ERROR 2001 #define CR_CONNECTION_ERROR 2002 @@ -90,3 +94,6 @@ extern const char *client_errors[]; /* Error messages */ #define CR_SECURE_AUTH 2049 #define CR_FETCH_CANCELED 2050 #define CR_NO_DATA 2051 +#define CR_ERROR_LAST /*Copy last error nr:*/ 2051 +/* Add error numbers before CR_ERROR_LAST and change it accordingly. */ + diff --git a/include/my_base.h b/include/my_base.h index 4d043cf6b5b..7c4c6d521ab 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -273,6 +273,9 @@ enum ha_base_keytype { /* Errorcodes given by functions */ /* opt_sum_query() assumes these codes are > 1 */ +/* Do not add error numbers before HA_ERR_FIRST. */ +/* If necessary to add lower numbers, change HA_ERR_FIRST accordingly. */ +#define HA_ERR_FIRST 120 /*Copy first error nr.*/ #define HA_ERR_KEY_NOT_FOUND 120 /* Didn't find key on read or update */ #define HA_ERR_FOUND_DUPP_KEY 121 /* Dupplicate key on write */ #define HA_ERR_RECORD_CHANGED 123 /* Uppdate with is recoverable */ @@ -308,6 +311,9 @@ enum ha_base_keytype { #define HA_ERR_NO_SUCH_TABLE 155 /* The table does not exist in engine */ #define HA_ERR_TABLE_EXIST 156 /* The table existed in storage engine */ #define HA_ERR_NO_CONNECTION 157 /* Could not connect to storage engine */ +#define HA_ERR_LAST 157 /*Copy last error nr.*/ +/* Add error numbers before HA_ERR_LAST and change it accordingly. */ +#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1) /* Other constants */ diff --git a/include/my_sys.h b/include/my_sys.h index e630c9bdbba..cbcd6f0f833 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -43,8 +43,6 @@ extern int NEAR my_errno; /* Last error in mysys */ #define MYSYS_PROGRAM_DONT_USE_CURSES() { error_handler_hook = my_message_no_curses; mysys_uses_curses=0;} #define MY_INIT(name); { my_progname= name; my_init(); } -#define MAXMAPS (4) /* Number of error message maps */ -#define ERRMOD (1000) /* Max number of errors in a map */ #define ERRMSGSIZE (SC_MAXWIDTH) /* Max length of a error message */ #define NRERRBUFFS (2) /* Buffers for parameters */ #define MY_FILE_ERROR ((uint) ~0) @@ -213,7 +211,6 @@ void __CDECL hfree(void *ptr); #else extern int errno; /* declare errno */ #endif -extern const char ** NEAR my_errmsg[]; extern char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE]; extern char *home_dir; /* Home directory for user */ extern char *my_progname; /* program-name (printed in errors) */ @@ -610,6 +607,8 @@ extern int my_error _VARARGS((int nr,myf MyFlags, ...)); extern int my_printf_error _VARARGS((uint my_err, const char *format, myf MyFlags, ...) __attribute__ ((format (printf, 2, 4)))); +extern int my_error_register(const char **errmsgs, int first, int last); +extern const char **my_error_unregister(int first, int last); extern int my_message(uint my_err, const char *str,myf MyFlags); extern int my_message_no_curses(uint my_err, const char *str,myf MyFlags); extern int my_message_curses(uint my_err, const char *str,myf MyFlags); diff --git a/include/mysys_err.h b/include/mysys_err.h index 230be5f4720..1fd7c2eddc6 100644 --- a/include/mysys_err.h +++ b/include/mysys_err.h @@ -20,13 +20,15 @@ extern "C" { #endif -#define GLOB 0 /* Error maps */ -#define GLOBERRS 28 /* Max number of error messages in map's */ -#define EE(X) globerrs[ X ] /* Defines to add error to right map */ +#define GLOBERRS (EE_ERROR_LAST - EE_ERROR_FIRST + 1) /* Nr of global errors */ +#define EE(X) (globerrs[(X) - EE_ERROR_FIRST]) extern const char * NEAR globerrs[]; /* my_error_messages is here */ /* Error message numbers in global map */ +/* Do not add error numbers before EE_ERROR_FIRST. */ +/* If necessary to add lower numbers, change EE_ERROR_FIRST accordingly. */ +#define EE_ERROR_FIRST 0 /*Copy first error nr.*/ #define EE_FILENOTFOUND 0 #define EE_CANTCREATEFILE 1 #define EE_READ 2 @@ -54,6 +56,8 @@ extern const char * NEAR globerrs[]; /* my_error_messages is here */ #define EE_CANT_SYMLINK 25 #define EE_REALPATH 26 #define EE_SYNC 27 +#define EE_ERROR_LAST 27 /*Copy last error nr.*/ +/* Add error numbers before EE_ERROR_LAST and change it accordingly. */ /* exit codes for all MySQL programs */ diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c index 710bf4ccd8d..73726e772e5 100644 --- a/libmysql/errmsg.c +++ b/libmysql/errmsg.c @@ -199,7 +199,33 @@ const char *client_errors[]= #endif +/* + Register client error messages for use with my_error(). + + SYNOPSIS + init_client_errs() + + RETURN + void +*/ + void init_client_errs(void) { - my_errmsg[CLIENT_ERRMAP] = &client_errors[0]; + (void) my_error_register(client_errors, CR_ERROR_FIRST, CR_ERROR_LAST); +} + + +/* + Unregister client error messages. + + SYNOPSIS + finish_client_errs() + + RETURN + void +*/ + +void finish_client_errs(void) +{ + (void) my_error_unregister(CR_ERROR_FIRST, CR_ERROR_LAST); } diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 4476a42f8ac..8c20b566957 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -185,6 +185,7 @@ void STDCALL mysql_server_end() } else mysql_thread_end(); + finish_client_errs(); mysql_client_init= org_my_init_done= 0; } diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c index b964cb35dd8..d79d9040ee7 100644 --- a/myisam/mi_delete.c +++ b/myisam/mi_delete.c @@ -45,6 +45,12 @@ int mi_delete(MI_INFO *info,const byte *record) /* Test if record is in datafile */ + DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_usage", + mi_print_error(info, HA_ERR_CRASHED); + DBUG_RETURN(my_errno= HA_ERR_CRASHED);); + DBUG_EXECUTE_IF("my_error_test_undefined_error", + mi_print_error(info, INT_MAX); + DBUG_RETURN(my_errno= INT_MAX);); if (!(info->update & HA_STATE_AKTIV)) { DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND); /* No database read */ @@ -109,13 +115,19 @@ err: mi_sizestore(lastpos,info->lastpos); myisam_log_command(MI_LOG_DELETE,info,(byte*) lastpos, sizeof(lastpos),0); if (save_errno != HA_ERR_RECORD_CHANGED) + { + mi_print_error(info, HA_ERR_CRASHED); mi_mark_crashed(info); /* mark table crashed */ + } VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE)); info->update|=HA_STATE_WRITTEN; /* Buffer changed */ allow_break(); /* Allow SIGHUP & SIGINT */ my_errno=save_errno; if (save_errno == HA_ERR_KEY_NOT_FOUND) + { + mi_print_error(info, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; + } DBUG_RETURN(my_errno); } /* mi_delete */ @@ -142,6 +154,7 @@ static int _mi_ck_real_delete(register MI_INFO *info, MI_KEYDEF *keyinfo, if ((old_root=*root) == HA_OFFSET_ERROR) { + mi_print_error(info, HA_ERR_CRASHED); DBUG_RETURN(my_errno=HA_ERR_CRASHED); } if (!(root_buff= (uchar*) my_alloca((uint) keyinfo->block_length+ @@ -253,7 +266,9 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, my_off_t root; uchar *kpos=keypos; - tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&kpos,lastkey); + if (!(tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&kpos,lastkey)) + && (my_errno == HA_ERR_CRASHED)) + mi_print_error(info, HA_ERR_CRASHED); root=_mi_dpos(info,nod_flag,kpos); if (subkeys == -1) { @@ -302,6 +317,7 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, if (!nod_flag) { DBUG_PRINT("error",("Didn't find key")); + mi_print_error(info, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; /* This should newer happend */ goto err; } @@ -317,6 +333,8 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, &next_block); if (tmp == 0) { + if (my_errno == HA_ERR_CRASHED) + mi_print_error(info, HA_ERR_CRASHED); DBUG_PRINT("exit",("Return: %d",0)); DBUG_RETURN(0); } @@ -473,6 +491,8 @@ static int del(register MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *key, (info->quick_mode ? MI_MIN_KEYBLOCK_LENGTH : (uint) keyinfo->underflow_block_length)); err: + if (my_errno == HA_ERR_CRASHED) + mi_print_error(info, HA_ERR_CRASHED); DBUG_RETURN(-1); } /* del */ @@ -562,7 +582,11 @@ static int underflow(register MI_INFO *info, register MI_KEYDEF *keyinfo, s_length=remove_key(keyinfo,key_reflength,keypos,anc_key, anc_buff+anc_length,(my_off_t *) 0); if (!s_length) + { + if (my_errno == HA_ERR_CRASHED) + mi_print_error(info, HA_ERR_CRASHED); goto err; + } anc_length-=s_length; mi_putint(anc_buff,anc_length,key_reflength); @@ -671,7 +695,11 @@ static int underflow(register MI_INFO *info, register MI_KEYDEF *keyinfo, s_length=remove_key(keyinfo,key_reflength,keypos,anc_key, anc_buff+anc_length,(my_off_t *) 0); if (!s_length) + { + if (my_errno == HA_ERR_CRASHED) + mi_print_error(info, HA_ERR_CRASHED); goto err; + } anc_length-=s_length; mi_putint(anc_buff,anc_length,key_reflength); @@ -732,6 +760,8 @@ static int underflow(register MI_INFO *info, register MI_KEYDEF *keyinfo, goto err; DBUG_RETURN(anc_length <= (uint) keyinfo->block_length/2); err: + if (my_errno == HA_ERR_CRASHED) + mi_print_error(info, HA_ERR_CRASHED); DBUG_RETURN(-1); } /* underflow */ diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c index 4b011ca424f..999c4ba8f3d 100644 --- a/myisam/mi_extra.c +++ b/myisam/mi_extra.c @@ -186,7 +186,10 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) if (info->opt_flag & WRITE_CACHE_USED) { if ((error=flush_io_cache(&info->rec_cache))) + { + mi_print_error(info, HA_ERR_CRASHED); mi_mark_crashed(info); /* Fatal error found */ + } } break; case HA_EXTRA_NO_READCHECK: @@ -285,6 +288,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) { error=my_errno; share->changed=1; + mi_print_error(info, HA_ERR_CRASHED); mi_mark_crashed(info); /* Fatal error found */ } if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) @@ -339,6 +343,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) if (error) { share->changed=1; + mi_print_error(info, HA_ERR_CRASHED); mi_mark_crashed(info); /* Fatal error found */ } } diff --git a/myisam/mi_info.c b/myisam/mi_info.c index cf63ef63618..bdece9c2ee3 100644 --- a/myisam/mi_info.c +++ b/myisam/mi_info.c @@ -105,3 +105,36 @@ int mi_status(MI_INFO *info, register MI_ISAMINFO *x, uint flag) } DBUG_RETURN(0); } + + +/* + Write a message to the error log. + + SYNOPSIS + mi_report_error() + file_name Name of table file (e.g. index_file_name). + errcode Error number. + + DESCRIPTION + This function supplies my_error() with a table name. Most error + messages need one. Since string arguments in error messages are limited + to 64 characters by convention, we ensure that in case of truncation, + that the end of the index file path is in the message. This contains + the most valuable information (the table name and the database name). + + RETURN + void +*/ + +void mi_report_error(int errcode, const char *file_name) +{ + size_t lgt; + DBUG_ENTER("mi_report_error"); + DBUG_PRINT("enter",("errcode %d, table '%s'", errcode, file_name)); + + if ((lgt= strlen(file_name)) > 64) + file_name+= lgt - 64; + my_error(errcode, MYF(ME_NOREFRESH), file_name); + DBUG_VOID_RETURN; +} + diff --git a/myisam/mi_key.c b/myisam/mi_key.c index caca63452b0..eaaee617f32 100644 --- a/myisam/mi_key.c +++ b/myisam/mi_key.c @@ -477,6 +477,7 @@ int _mi_read_key_record(MI_INFO *info, my_off_t filepos, byte *buf) { /* Read only key */ if (_mi_put_key_in_record(info,(uint) info->lastinx,buf)) { + mi_print_error(info, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; return -1; } diff --git a/myisam/mi_keycache.c b/myisam/mi_keycache.c index 99a2fd6db15..33d0ac4f6bc 100644 --- a/myisam/mi_keycache.c +++ b/myisam/mi_keycache.c @@ -79,6 +79,7 @@ int mi_assign_to_key_cache(MI_INFO *info, if (flush_key_blocks(share->key_cache, share->kfile, FLUSH_RELEASE)) { error= my_errno; + mi_print_error(info, HA_ERR_CRASHED); mi_mark_crashed(info); /* Mark that table must be checked */ } diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c index 66950f62321..91e9f09b9fb 100644 --- a/myisam/mi_locking.c +++ b/myisam/mi_locking.c @@ -66,6 +66,7 @@ int mi_lock_database(MI_INFO *info, int lock_type) share->kfile,FLUSH_KEEP)) { error=my_errno; + mi_print_error(info, HA_ERR_CRASHED); mi_mark_crashed(info); /* Mark that table must be checked */ } if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) @@ -73,6 +74,7 @@ int mi_lock_database(MI_INFO *info, int lock_type) if (end_io_cache(&info->rec_cache)) { error=my_errno; + mi_print_error(info, HA_ERR_CRASHED); mi_mark_crashed(info); } } @@ -98,7 +100,10 @@ int mi_lock_database(MI_INFO *info, int lock_type) else share->not_flushed=1; if (error) + { + mi_print_error(info, HA_ERR_CRASHED); mi_mark_crashed(info); + } } if (info->lock_type != F_EXTRA_LCK) { @@ -285,6 +290,7 @@ void mi_update_status(void* param) { if (end_io_cache(&info->rec_cache)) { + mi_print_error(info, HA_ERR_CRASHED); mi_mark_crashed(info); } info->opt_flag&= ~WRITE_CACHE_USED; diff --git a/myisam/mi_open.c b/myisam/mi_open.c index 58db2e47c1f..040bc1503aa 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -106,6 +106,12 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) share_buff.state.key_del=key_del; share_buff.key_cache= multi_key_cache_search(name_buff, strlen(name_buff)); + DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_open", + if (strstr(name, "/t1")) + { + my_errno= HA_ERR_CRASHED; + goto err; + }); if ((kfile=my_open(name_buff,(open_mode=O_RDWR) | O_SHARE,MYF(0))) < 0) { if ((errno != EROFS && errno != EACCES) || @@ -601,6 +607,10 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) err: save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE; + if ((save_errno == HA_ERR_CRASHED) || + (save_errno == HA_ERR_CRASHED_ON_USAGE) || + (save_errno == HA_ERR_CRASHED_ON_REPAIR)) + mi_report_error(save_errno, name); switch (errpos) { case 6: my_free((gptr) m_info,MYF(0)); @@ -1223,7 +1233,10 @@ int mi_enable_indexes(MI_INFO *info) if (share->state.state.data_file_length || (share->state.state.key_file_length != share->base.keystart)) + { + mi_print_error(info, HA_ERR_CRASHED); error= HA_ERR_CRASHED; + } else share->state.key_map= ((ulonglong) 1L << share->base.keys) - 1; return error; diff --git a/myisam/mi_page.c b/myisam/mi_page.c index 16713c87e10..dc2bc75f1a0 100644 --- a/myisam/mi_page.c +++ b/myisam/mi_page.c @@ -40,6 +40,7 @@ uchar *_mi_fetch_keypage(register MI_INFO *info, MI_KEYDEF *keyinfo, { DBUG_PRINT("error",("Got errno: %d from key_cache_read",my_errno)); info->last_keypage=HA_OFFSET_ERROR; + mi_print_error(info, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_RETURN(0); } @@ -51,6 +52,7 @@ uchar *_mi_fetch_keypage(register MI_INFO *info, MI_KEYDEF *keyinfo, (ulong) page, page_size)); DBUG_DUMP("page", (char*) tmp, keyinfo->block_length); info->last_keypage = HA_OFFSET_ERROR; + mi_print_error(info, HA_ERR_CRASHED); my_errno = HA_ERR_CRASHED; tmp = 0; } diff --git a/myisam/mi_range.c b/myisam/mi_range.c index 789607c9889..0d8f8763b92 100644 --- a/myisam/mi_range.c +++ b/myisam/mi_range.c @@ -233,7 +233,11 @@ static uint _mi_keynr(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, u while (page < end) { if (!(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff)) + { + if (my_errno == HA_ERR_CRASHED) + mi_print_error(info, HA_ERR_CRASHED); return 0; /* Error */ + } max_key++; if (page == keypos) keynr=max_key; diff --git a/myisam/mi_rkey.c b/myisam/mi_rkey.c index 12db00337ee..d564c672f19 100644 --- a/myisam/mi_rkey.c +++ b/myisam/mi_rkey.c @@ -78,6 +78,7 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, case HA_KEY_ALG_RTREE: if (rtree_find_first(info,inx,key_buff,use_key_length,nextflag) < 0) { + mi_print_error(info, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; goto err; } diff --git a/myisam/mi_search.c b/myisam/mi_search.c index 2259dd17fcd..f252719d29c 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -161,6 +161,8 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, DBUG_RETURN(0); err: DBUG_PRINT("exit",("Error: %d",my_errno)); + if (my_errno == HA_ERR_CRASHED) + mi_print_error(info, HA_ERR_CRASHED); info->lastpos= HA_OFFSET_ERROR; info->page_changed=1; DBUG_RETURN (-1); @@ -234,6 +236,7 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff); if (length == 0 || page > end) { + mi_print_error(info, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_PRINT("error",("Found wrong key: length: %u page: %p end: %p", length, page, end)); @@ -380,6 +383,7 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, if (page > end) { + mi_print_error(info, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_PRINT("error",("Found wrong key: length: %u page: %p end: %p", length, page, end)); @@ -969,6 +973,7 @@ uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, *return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key); if (*return_key_length == 0) { + mi_print_error(info, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_RETURN(0); } @@ -1006,6 +1011,7 @@ static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, *return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key); if (*return_key_length == 0) { + mi_print_error(info, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_RETURN(1); } @@ -1046,6 +1052,7 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, if (*return_key_length == 0) { DBUG_PRINT("error",("Couldn't find last key: page: %p", page)); + mi_print_error(info, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_RETURN(0); } @@ -1178,7 +1185,11 @@ int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo, memcpy(lastkey,key,key_length); if (!(info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag, &info->int_keypos,lastkey))) + { + if (my_errno == HA_ERR_CRASHED) + mi_print_error(info, HA_ERR_CRASHED); DBUG_RETURN(-1); + } } else /* Previous key */ { @@ -1236,8 +1247,10 @@ int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo, page=info->buff+2+nod_flag; } while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR); - info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page, - info->lastkey); + if (!(info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page, + info->lastkey)) && + (my_errno == HA_ERR_CRASHED)) + mi_print_error(info, HA_ERR_CRASHED); info->int_keypos=page; info->int_maxpos=info->buff+mi_getint(info->buff)-1; info->int_nod_flag=nod_flag; info->int_keytree_version=keyinfo->version; diff --git a/myisam/mi_update.c b/myisam/mi_update.c index f62be133ed9..2936e29a01c 100644 --- a/myisam/mi_update.c +++ b/myisam/mi_update.c @@ -34,6 +34,9 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec) LINT_INIT(changed); LINT_INIT(old_checksum); + DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_usage", + mi_print_error(info, HA_ERR_CRASHED); + DBUG_RETURN(my_errno= HA_ERR_CRASHED);); if (!(info->update & HA_STATE_AKTIV)) { DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND); @@ -205,7 +208,10 @@ err: } while (i-- != 0); } else + { + mi_print_error(info, HA_ERR_CRASHED); mi_mark_crashed(info); + } info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_ROW_CHANGED | key_changed); @@ -214,6 +220,9 @@ err: VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE)); allow_break(); /* Allow SIGHUP & SIGINT */ if (save_errno == HA_ERR_KEY_NOT_FOUND) + { + mi_print_error(info, HA_ERR_CRASHED); save_errno=HA_ERR_CRASHED; + } DBUG_RETURN(my_errno=save_errno); } /* mi_update */ diff --git a/myisam/mi_write.c b/myisam/mi_write.c index c2f24ae1ae3..8ff653bdd2d 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -52,6 +52,9 @@ int mi_write(MI_INFO *info, byte *record) DBUG_ENTER("mi_write"); DBUG_PRINT("enter",("isam: %d data: %d",info->s->kfile,info->dfile)); + DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_usage", + mi_print_error(info, HA_ERR_CRASHED); + DBUG_RETURN(my_errno= HA_ERR_CRASHED);); if (share->options & HA_OPTION_READ_ONLY_DATA) { DBUG_RETURN(my_errno=EACCES); @@ -202,7 +205,10 @@ err: } } else + { + mi_print_error(info, HA_ERR_CRASHED); mi_mark_crashed(info); + } info->update= (HA_STATE_CHANGED | HA_STATE_WRITTEN | HA_STATE_ROW_CHANGED); my_errno=save_errno; err2: @@ -346,7 +352,11 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, if (tmp_key_length) dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length); else + { + if (my_errno == HA_ERR_CRASHED) + mi_print_error(info, HA_ERR_CRASHED); dupp_key_pos= HA_OFFSET_ERROR; + } if (keyinfo->flag & HA_FULLTEXT) { uint off; @@ -455,6 +465,7 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo, { if (t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH) { + mi_print_error(info, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_RETURN(-1); } @@ -464,6 +475,7 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo, { if (-t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH) { + mi_print_error(info, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_RETURN(-1); } @@ -558,7 +570,11 @@ int _mi_split_page(register MI_INFO *info, register MI_KEYDEF *keyinfo, key_pos=_mi_find_half_pos(nod_flag,keyinfo,buff,key_buff, &key_length, &after_key); if (!key_pos) + { + if (my_errno == HA_ERR_CRASHED) + mi_print_error(info, HA_ERR_CRASHED); DBUG_RETURN(-1); + } length=(uint) (key_pos-buff); a_length=mi_getint(buff); mi_putint(buff,length,nod_flag); @@ -578,7 +594,11 @@ int _mi_split_page(register MI_INFO *info, register MI_KEYDEF *keyinfo, /* Store new page */ if (!(*keyinfo->get_key)(keyinfo,nod_flag,&key_pos,key_buff)) + { + if (my_errno == HA_ERR_CRASHED) + mi_print_error(info, HA_ERR_CRASHED); DBUG_RETURN(-1); + } t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(uchar *) 0, (uchar*) 0, (uchar*) 0, key_buff, &s_temp); diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index 12ce112dbe0..c0f56a7b720 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -356,6 +356,8 @@ typedef struct st_mi_sort_param #define mi_mark_crashed_on_repair(x) { (x)->s->state.changed|=STATE_CRASHED|STATE_CRASHED_ON_REPAIR ; (x)->update|= HA_STATE_CHANGED; } #define mi_is_crashed(x) ((x)->s->state.changed & STATE_CRASHED) #define mi_is_crashed_on_repair(x) ((x)->s->state.changed & STATE_CRASHED_ON_REPAIR) +#define mi_print_error(INFO, ERRNO) \ + mi_report_error((ERRNO), (INFO)->s->index_file_name) /* Functions to store length of space packed keys, VARCHAR or BLOB keys */ @@ -667,6 +669,7 @@ extern void _myisam_log_command(enum myisam_log_commands command, extern void _myisam_log_record(enum myisam_log_commands command,MI_INFO *info, const byte *record,my_off_t filepos, int result); +extern void mi_report_error(int errcode, const char *file_name); extern my_bool _mi_memmap_file(MI_INFO *info); extern void _mi_unmap_file(MI_INFO *info); extern uint save_pack_length(byte *block_buff,ulong length); diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index a9d90813660..618816cd623 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -178,9 +178,9 @@ t3 CREATE TABLE `t3` ( ) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t1`,`t2`) create table t4 (a int not null, b char(10), key(a)) engine=MERGE UNION=(t1,t2); select * from t4; -ERROR HY000: Can't open file: 't4.MRG' (errno: 143) +ERROR HY000: All tables in the MERGE table are not identically defined alter table t4 add column c int; -ERROR HY000: Can't open file: 't4.MRG' (errno: 143) +ERROR HY000: All tables in the MERGE table are not identically defined create database mysqltest; create table mysqltest.t6 (a int not null primary key auto_increment, message char(20)); create table t5 (a int not null, b char(20), key(a)) engine=MERGE UNION=(test.t1,mysqltest.t6); diff --git a/mysql-test/r/repair.result b/mysql-test/r/repair.result index dbca5c39a6c..0347d3a52f5 100644 --- a/mysql-test/r/repair.result +++ b/mysql-test/r/repair.result @@ -31,7 +31,7 @@ create table t1 engine=myisam SELECT 1,"table 1"; flush tables; repair table t1; Table Op Msg_type Msg_text -test.t1 repair error Can't open file: 't1.MYI' (errno: 130) +test.t1 repair error Incorrect file format 't1' repair table t1 use_frm; Table Op Msg_type Msg_text test.t1 repair warning Number of rows changed from 0 to 1 diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index 9d367260049..41d44376525 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -47,9 +47,9 @@ show create table t3; # The following should give errors create table t4 (a int not null, b char(10), key(a)) engine=MERGE UNION=(t1,t2); ---error 1016 +--error 1168 select * from t4; ---error 1016 +--error 1168 alter table t4 add column c int; # diff --git a/mysys/errors.c b/mysys/errors.c index 5401c2b3cc6..5f548cad480 100644 --- a/mysys/errors.c +++ b/mysys/errors.c @@ -53,15 +53,13 @@ const char * NEAR globerrs[GLOBERRS]= void init_glob_errs(void) { - my_errmsg[GLOB] = & globerrs[0]; -} /* init_glob_errs */ + /* This is now done statically. */ +} #else void init_glob_errs() { - my_errmsg[GLOB] = & globerrs[0]; - EE(EE_FILENOTFOUND) = "File '%s' not found (Errcode: %d)"; EE(EE_CANTCREATEFILE) = "Can't create/write to file '%s' (Errcode: %d)"; EE(EE_READ) = "Error reading file '%s' (Errcode: %d)"; diff --git a/mysys/my_error.c b/mysys/my_error.c index 175f8cf516b..0c18bbf6e8b 100644 --- a/mysys/my_error.c +++ b/mysys/my_error.c @@ -31,9 +31,30 @@ my_printf_error(ER_CODE, format, MYF(N), ...) */ -const char ** NEAR my_errmsg[MAXMAPS]={0,0,0,0}; char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE]; +/* + Message texts are registered into a linked list of 'my_err_head' structs. + Each struct contains (1.) an array of pointers to C character strings with + '\0' termination, (2.) the error number for the first message in the array + (array index 0) and (3.) the error number for the last message in the array + (array index (last - first)). + The array may contain gaps with NULL pointers and pointers to empty strings. + Both kinds of gaps will be translated to "Unknown error %d.", if my_error() + is called with a respective error number. + The list of header structs is sorted in increasing order of error numbers. + Negative error numbers are allowed. Overlap of error numbers is not allowed. + Not registered error numbers will be translated to "Unknown error %d.". +*/ +static struct my_err_head +{ + struct my_err_head *meh_next; /* chain link */ + const char **meh_errmsgs; /* error messages array */ + int meh_first; /* error number matching array slot 0 */ + int meh_last; /* error number matching last slot */ +} my_errmsgs_globerrs = {NULL, globerrs, EE_ERROR_FIRST, EE_ERROR_LAST}; +static struct my_err_head *my_errmsgs_list= &my_errmsgs_globerrs; + /* Error message to user @@ -42,30 +63,42 @@ char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE]; nr Errno MyFlags Flags ... variable list - NOTE - The following subset of printf format is supported: - "%[0-9.-]*l?[sdu]", where all length flags are parsed but ignored. - Additionally "%.*s" is supported and "%.*[ud]" is correctly parsed but - the length value is ignored. + RETURN + What (*error_handler_hook)() returns: + 0 OK */ int my_error(int nr, myf MyFlags, ...) { const char *format; + struct my_err_head *meh_p; va_list args; char ebuff[ERRMSGSIZE + 20]; DBUG_ENTER("my_error"); DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d", nr, MyFlags, errno)); - if (nr / ERRMOD == GLOB && my_errmsg[GLOB] == 0) - init_glob_errs(); - format= my_errmsg[nr / ERRMOD][nr % ERRMOD]; + /* Search for the error messages array, which could contain the message. */ + for (meh_p= my_errmsgs_list; meh_p; meh_p= meh_p->meh_next) + if (nr <= meh_p->meh_last) + break; - va_start(args,MyFlags); - (void) my_vsnprintf (ebuff, sizeof(ebuff), format, args); - va_end(args); +#ifdef SHARED_LIBRARY + if ((meh_p == &my_errmsgs_globerrs) && ! globerrs[0]) + init_glob_errs(); +#endif + + /* get the error message string. Default, if NULL or empty string (""). */ + if (! (format= (meh_p && (nr >= meh_p->meh_first)) ? + meh_p->meh_errmsgs[nr - meh_p->meh_first] : NULL) || ! *format) + (void) my_snprintf (ebuff, sizeof(ebuff), "Unknown error %d", nr); + else + { + va_start(args,MyFlags); + (void) my_vsnprintf (ebuff, sizeof(ebuff), format, args); + va_end(args); + } DBUG_RETURN((*error_handler_hook)(nr, ebuff, MyFlags)); } @@ -108,3 +141,109 @@ int my_message(uint error, const char *str, register myf MyFlags) { return (*error_handler_hook)(error, str, MyFlags); } + + +/* + Register error messages for use with my_error(). + + SYNOPSIS + my_error_register() + errmsgs array of pointers to error messages + first error number of first message in the array + last error number of last message in the array + + DESCRIPTION + The pointer array is expected to contain addresses to NUL-terminated + C character strings. The array contains (last - first + 1) pointers. + NULL pointers and empty strings ("") are allowed. These will be mapped to + "Unknown error" when my_error() is called with a matching error number. + This function registers the error numbers 'first' to 'last'. + No overlapping with previously registered error numbers is allowed. + + RETURN + 0 OK + != 0 Error +*/ + +int my_error_register(const char **errmsgs, int first, int last) +{ + struct my_err_head *meh_p; + struct my_err_head **search_meh_pp; + + /* Allocate a new header structure. */ + if (! (meh_p= (struct my_err_head*) my_malloc(sizeof(struct my_err_head), + MYF(MY_WME)))) + return 1; + meh_p->meh_errmsgs= errmsgs; + meh_p->meh_first= first; + meh_p->meh_last= last; + + /* Search for the right position in the list. */ + for (search_meh_pp= &my_errmsgs_list; + *search_meh_pp; + search_meh_pp= &(*search_meh_pp)->meh_next) + { + if ((*search_meh_pp)->meh_last > first) + break; + } + + /* Error numbers must be unique. No overlapping is allowed. */ + if (*search_meh_pp && ((*search_meh_pp)->meh_first <= last)) + return 1; + + /* Insert header into the chain. */ + meh_p->meh_next= *search_meh_pp; + *search_meh_pp= meh_p; + return 0; +} + + +/* + Unregister formerly registered error messages. + + SYNOPSIS + my_error_unregister() + first error number of first message + last error number of last message + + DESCRIPTION + This function unregisters the error numbers 'first' to 'last'. + These must have been previously registered by my_error_register(). + 'first' and 'last' must exactly match the registration. + If a matching registration is present, the header is removed from the + list and the pointer to the error messages pointers array is returned. + Otherwise, NULL is returned. + + RETURN + non-NULL OK, returns address of error messages pointers array. + NULL Error, no such number range registered. +*/ + +const char **my_error_unregister(int first, int last) +{ + struct my_err_head *meh_p; + struct my_err_head **search_meh_pp; + const char **errmsgs; + + /* Search for the registration in the list. */ + for (search_meh_pp= &my_errmsgs_list; + *search_meh_pp; + search_meh_pp= &(*search_meh_pp)->meh_next) + { + if (((*search_meh_pp)->meh_first == first) && + ((*search_meh_pp)->meh_last == last)) + break; + } + if (! *search_meh_pp) + return NULL; + + /* Remove header from the chain. */ + meh_p= *search_meh_pp; + *search_meh_pp= meh_p->meh_next; + + /* Save the return value and free the header. */ + errmsgs= meh_p->meh_errmsgs; + my_free((gptr) meh_p, MYF(0)); + + return errmsgs; +} diff --git a/sql/derror.cc b/sql/derror.cc index 09f43d20044..4690e76d0e3 100644 --- a/sql/derror.cc +++ b/sql/derror.cc @@ -24,15 +24,43 @@ static bool read_texts(const char *file_name,const char ***point, uint error_messages); static void init_myfunc_errs(void); - /* Read messages from errorfile */ +/* + Read messages from errorfile. + + SYNOPSIS + init_errmessage() + + DESCRIPTION + This function can be called multiple times to reload the messages. + + RETURN + FALSE OK + TRUE Error +*/ bool init_errmessage(void) { + const char **errmsgs; DBUG_ENTER("init_errmessage"); - if (read_texts(ERRMSG_FILE,&my_errmsg[ERRMAPP],ER_ERROR_MESSAGES)) + /* + Get a pointer to the old error messages pointer array. + read_texts() tries to free it. + */ + errmsgs= my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST); + + /* Read messages from file. */ + if (read_texts(ERRMSG_FILE, &errmsgs, ER_ERROR_LAST - ER_ERROR_FIRST + 1)) DBUG_RETURN(TRUE); - errmesg=my_errmsg[ERRMAPP]; /* Init global variabel */ + + /* Register messages for use with my_error(). */ + if (my_error_register(errmsgs, ER_ERROR_FIRST, ER_ERROR_LAST)) + { + x_free((gptr) errmsgs); + DBUG_RETURN(TRUE); + } + + errmesg= errmsgs; /* Init global variabel */ init_myfunc_errs(); /* Init myfunc messages */ DBUG_RETURN(FALSE); } @@ -148,20 +176,20 @@ static void init_myfunc_errs() init_glob_errs(); /* Initiate english errors */ if (!(specialflag & SPECIAL_ENGLISH)) { - globerrs[EE_FILENOTFOUND % ERRMOD] = ER(ER_FILE_NOT_FOUND); - globerrs[EE_CANTCREATEFILE % ERRMOD]= ER(ER_CANT_CREATE_FILE); - globerrs[EE_READ % ERRMOD] = ER(ER_ERROR_ON_READ); - globerrs[EE_WRITE % ERRMOD] = ER(ER_ERROR_ON_WRITE); - globerrs[EE_BADCLOSE % ERRMOD] = ER(ER_ERROR_ON_CLOSE); - globerrs[EE_OUTOFMEMORY % ERRMOD] = ER(ER_OUTOFMEMORY); - globerrs[EE_DELETE % ERRMOD] = ER(ER_CANT_DELETE_FILE); - globerrs[EE_LINK % ERRMOD] = ER(ER_ERROR_ON_RENAME); - globerrs[EE_EOFERR % ERRMOD] = ER(ER_UNEXPECTED_EOF); - globerrs[EE_CANTLOCK % ERRMOD] = ER(ER_CANT_LOCK); - globerrs[EE_DIR % ERRMOD] = ER(ER_CANT_READ_DIR); - globerrs[EE_STAT % ERRMOD] = ER(ER_CANT_GET_STAT); - globerrs[EE_GETWD % ERRMOD] = ER(ER_CANT_GET_WD); - globerrs[EE_SETWD % ERRMOD] = ER(ER_CANT_SET_WD); - globerrs[EE_DISK_FULL % ERRMOD] = ER(ER_DISK_FULL); + EE(EE_FILENOTFOUND) = ER(ER_FILE_NOT_FOUND); + EE(EE_CANTCREATEFILE) = ER(ER_CANT_CREATE_FILE); + EE(EE_READ) = ER(ER_ERROR_ON_READ); + EE(EE_WRITE) = ER(ER_ERROR_ON_WRITE); + EE(EE_BADCLOSE) = ER(ER_ERROR_ON_CLOSE); + EE(EE_OUTOFMEMORY) = ER(ER_OUTOFMEMORY); + EE(EE_DELETE) = ER(ER_CANT_DELETE_FILE); + EE(EE_LINK) = ER(ER_ERROR_ON_RENAME); + EE(EE_EOFERR) = ER(ER_UNEXPECTED_EOF); + EE(EE_CANTLOCK) = ER(ER_CANT_LOCK); + EE(EE_DIR) = ER(ER_CANT_READ_DIR); + EE(EE_STAT) = ER(ER_CANT_GET_STAT); + EE(EE_GETWD) = ER(ER_CANT_GET_WD); + EE(EE_SETWD) = ER(ER_CANT_SET_WD); + EE(EE_DISK_FULL) = ER(ER_DISK_FULL); } } diff --git a/sql/handler.cc b/sql/handler.cc index e43f2c2e888..ed17034907c 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -244,9 +244,99 @@ bool ha_caching_allowed(THD* thd, char* table_key, return 1; } + +/* + Register handler error messages for use with my_error(). + + SYNOPSIS + ha_init_errors() + + RETURN + 0 OK + != 0 Error +*/ + +static int ha_init_errors(void) +{ +#define SETMSG(nr, msg) errmsgs[(nr) - HA_ERR_FIRST]= (msg) + const char **errmsgs; + + /* Allocate a pointer array for the error message strings. */ + /* Zerofill it to avoid uninitialized gaps. */ + if (! (errmsgs= (const char**) my_malloc(HA_ERR_ERRORS * sizeof(char*), + MYF(MY_WME | MY_ZEROFILL)))) + return 1; + + /* Set the dedicated error messages. */ + SETMSG(HA_ERR_KEY_NOT_FOUND, ER(ER_KEY_NOT_FOUND)); + SETMSG(HA_ERR_FOUND_DUPP_KEY, ER(ER_DUP_KEY)); + SETMSG(HA_ERR_RECORD_CHANGED, "Update wich is recoverable"); + SETMSG(HA_ERR_WRONG_INDEX, "Wrong index given to function"); + SETMSG(HA_ERR_CRASHED, ER(ER_NOT_KEYFILE)); + SETMSG(HA_ERR_WRONG_IN_RECORD, ER(ER_CRASHED_ON_USAGE)); + SETMSG(HA_ERR_OUT_OF_MEM, "Table handler out of memory"); + SETMSG(HA_ERR_NOT_A_TABLE, "Incorrect file format '%.64s'"); + SETMSG(HA_ERR_WRONG_COMMAND, "Command not supported"); + SETMSG(HA_ERR_OLD_FILE, ER(ER_OLD_KEYFILE)); + SETMSG(HA_ERR_NO_ACTIVE_RECORD, "No record read in update"); + SETMSG(HA_ERR_RECORD_DELETED, "Intern record deleted"); + SETMSG(HA_ERR_RECORD_FILE_FULL, ER(ER_RECORD_FILE_FULL)); + SETMSG(HA_ERR_INDEX_FILE_FULL, "No more room in index file '%.64s'"); + SETMSG(HA_ERR_END_OF_FILE, "End in next/prev/first/last"); + SETMSG(HA_ERR_UNSUPPORTED, ER(ER_ILLEGAL_HA)); + SETMSG(HA_ERR_TO_BIG_ROW, "Too big row"); + SETMSG(HA_WRONG_CREATE_OPTION, "Wrong create option"); + SETMSG(HA_ERR_FOUND_DUPP_UNIQUE, ER(ER_DUP_UNIQUE)); + SETMSG(HA_ERR_UNKNOWN_CHARSET, "Can't open charset"); + SETMSG(HA_ERR_WRONG_MRG_TABLE_DEF, ER(ER_WRONG_MRG_TABLE)); + SETMSG(HA_ERR_CRASHED_ON_REPAIR, ER(ER_CRASHED_ON_REPAIR)); + SETMSG(HA_ERR_CRASHED_ON_USAGE, ER(ER_CRASHED_ON_USAGE)); + SETMSG(HA_ERR_LOCK_WAIT_TIMEOUT, ER(ER_LOCK_WAIT_TIMEOUT)); + SETMSG(HA_ERR_LOCK_TABLE_FULL, ER(ER_LOCK_TABLE_FULL)); + SETMSG(HA_ERR_READ_ONLY_TRANSACTION, ER(ER_READ_ONLY_TRANSACTION)); + SETMSG(HA_ERR_LOCK_DEADLOCK, ER(ER_LOCK_DEADLOCK)); + SETMSG(HA_ERR_CANNOT_ADD_FOREIGN, ER(ER_CANNOT_ADD_FOREIGN)); + SETMSG(HA_ERR_NO_REFERENCED_ROW, ER(ER_NO_REFERENCED_ROW)); + SETMSG(HA_ERR_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED)); + SETMSG(HA_ERR_NO_SAVEPOINT, "No savepoint with that name"); + SETMSG(HA_ERR_NON_UNIQUE_BLOCK_SIZE, "Non unique key block size"); + SETMSG(HA_ERR_NO_SUCH_TABLE, "No such table: '%.64s'"); + SETMSG(HA_ERR_TABLE_EXIST, ER(ER_TABLE_EXISTS_ERROR)); + SETMSG(HA_ERR_NO_CONNECTION, "Could not connect to storage engine"); + + /* Register the error messages for use with my_error(). */ + return my_error_register(errmsgs, HA_ERR_FIRST, HA_ERR_LAST); +} + + +/* + Unregister handler error messages. + + SYNOPSIS + ha_finish_errors() + + RETURN + 0 OK + != 0 Error +*/ + +static int ha_finish_errors(void) +{ + const char **errmsgs; + + /* Allocate a pointer array for the error message strings. */ + if (! (errmsgs= my_error_unregister(HA_ERR_FIRST, HA_ERR_LAST))) + return 1; + my_free((gptr) errmsgs, MYF(0)); + return 0; +} + + int ha_init() { int error= 0; + if (ha_init_errors()) + return 1; #ifdef HAVE_BERKELEY_DB if (have_berkeley_db == SHOW_OPTION_YES) { @@ -314,6 +404,8 @@ int ha_panic(enum ha_panic_function flag) if (have_ndbcluster == SHOW_OPTION_YES) error|=ndbcluster_end(); #endif + if (ha_finish_errors()) + error= 1; return error; } /* ha_panic */ @@ -1241,9 +1333,15 @@ void handler::print_error(int error, myf errflag) case HA_ERR_CRASHED: textno=ER_NOT_KEYFILE; break; + case HA_ERR_WRONG_IN_RECORD: + textno= ER_CRASHED_ON_USAGE; + break; case HA_ERR_CRASHED_ON_USAGE: textno=ER_CRASHED_ON_USAGE; break; + case HA_ERR_NOT_A_TABLE: + textno= error; + break; case HA_ERR_CRASHED_ON_REPAIR: textno=ER_CRASHED_ON_REPAIR; break; @@ -1262,6 +1360,9 @@ void handler::print_error(int error, myf errflag) case HA_ERR_RECORD_FILE_FULL: textno=ER_RECORD_FILE_FULL; break; + case HA_ERR_INDEX_FILE_FULL: + textno= errno; + break; case HA_ERR_LOCK_WAIT_TIMEOUT: textno=ER_LOCK_WAIT_TIMEOUT; break; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8eec97efd81..8d3c99bc146 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1005,7 +1005,9 @@ void clean_up(bool print_message) if (!opt_bootstrap) (void) my_delete(pidfile_name,MYF(0)); // This may not always exist #endif - x_free((gptr) my_errmsg[ERRMAPP]); /* Free messages */ + finish_client_errs(); + const char **errmsgs= my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST); + x_free((gptr) errmsgs); /* Free messages */ DBUG_PRINT("quit", ("Error messages freed")); /* Tell main we are ready */ (void) pthread_mutex_lock(&LOCK_thread_count); diff --git a/sql/table.cc b/sql/table.cc index c18a2557337..3cf6bbded58 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -76,6 +76,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, my_string record; const char **int_array; bool use_hash, null_field_first; + bool error_reported= FALSE; File file; Field **field_ptr,*reg_field; KEY *keyinfo; @@ -788,6 +789,11 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, error= 1; my_errno= ENOENT; } + else + { + outparam->file->print_error(err, MYF(0)); + error_reported= TRUE; + } goto err_not_open; /* purecov: inspected */ } } @@ -814,7 +820,8 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, err_end: /* Here when no file */ delete crypted; *root_ptr= old_root; - frm_error(error,outparam,name,ME_ERROR+ME_WAITTANG); + if (! error_reported) + frm_error(error,outparam,name,ME_ERROR+ME_WAITTANG); delete outparam->file; outparam->file=0; // For easier errorchecking outparam->db_stat=0; diff --git a/sql/unireg.h b/sql/unireg.h index 932bdf4dfc5..053ca393ad0 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -37,8 +37,8 @@ #define SHAREDIR "share/" #endif -#define ER(X) errmesg[(X)-1000] -#define ER_SAFE(X) (((X) >= 1000 && (X) < ER_ERROR_MESSAGES + 1000) ? ER(X) : "Invalid error code") +#define ER(X) errmesg[(X) - ER_ERROR_FIRST] +#define ER_SAFE(X) (((X) >= ER_ERROR_FIRST && (X) <= ER_ERROR_LAST) ? ER(X) : "Invalid error code") #define ERRMAPP 1 /* Errormap f|r my_error */