summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extra/comp_err.c9
-rw-r--r--include/errmsg.h7
-rw-r--r--include/my_base.h6
-rw-r--r--include/my_sys.h5
-rw-r--r--include/mysys_err.h10
-rw-r--r--libmysql/errmsg.c28
-rw-r--r--libmysql/libmysql.c1
-rw-r--r--myisam/mi_delete.c32
-rw-r--r--myisam/mi_extra.c5
-rw-r--r--myisam/mi_info.c33
-rw-r--r--myisam/mi_key.c1
-rw-r--r--myisam/mi_keycache.c1
-rw-r--r--myisam/mi_locking.c6
-rw-r--r--myisam/mi_open.c13
-rw-r--r--myisam/mi_page.c2
-rw-r--r--myisam/mi_range.c4
-rw-r--r--myisam/mi_rkey.c1
-rw-r--r--myisam/mi_search.c17
-rw-r--r--myisam/mi_update.c9
-rw-r--r--myisam/mi_write.c20
-rw-r--r--myisam/myisamdef.h3
-rw-r--r--mysql-test/r/merge.result4
-rw-r--r--mysql-test/r/repair.result2
-rw-r--r--mysql-test/t/merge.test4
-rw-r--r--mysys/errors.c6
-rw-r--r--mysys/my_error.c163
-rw-r--r--sql/derror.cc64
-rw-r--r--sql/handler.cc101
-rw-r--r--sql/mysqld.cc4
-rw-r--r--sql/table.cc9
-rw-r--r--sql/unireg.h4
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,10 +31,31 @@
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
SYNOPSIS
@@ -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 */