summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2016-04-05 16:52:40 +0300
committerMonty <monty@mariadb.org>2016-04-05 18:00:03 +0300
commitd0b178fb45898486979a504de30ac186f734bb26 (patch)
tree7a78d5c3ecc02319615042a598a7530099cb217b /sql
parent38f39a9288dc826ac16ac81a67a4e3174451825d (diff)
downloadmariadb-git-d0b178fb45898486979a504de30ac186f734bb26.tar.gz
Added new range of MariaDB error messages, starting from 3000
This is done by splitting variables.errmsg and locale.errmsg to variables.errmsg_extra and locale.errmsg_extra The ER() macros in unireg.h now looks more complex than before, but this isn't critical as most usage of them are with constants and the compiler will remove most of the test code.
Diffstat (limited to 'sql')
-rw-r--r--sql/derror.cc253
-rw-r--r--sql/derror.h3
-rw-r--r--sql/handler.cc10
-rw-r--r--sql/log_event.cc2
-rw-r--r--sql/mysqld.cc7
-rw-r--r--sql/share/errmsg-utf8.txt17
-rw-r--r--sql/sql_class.h2
-rw-r--r--sql/sql_locale.h2
-rw-r--r--sql/sys_vars.cc3
-rw-r--r--sql/unireg.h19
10 files changed, 211 insertions, 107 deletions
diff --git a/sql/derror.cc b/sql/derror.cc
index bc4b89493aa..b3f0bacb3d8 100644
--- a/sql/derror.cc
+++ b/sql/derror.cc
@@ -30,16 +30,19 @@
#include "derror.h" // read_texts
#include "sql_class.h" // THD
+uint errors_per_range[MAX_ERROR_RANGES+1];
+
static bool check_error_mesg(const char *file_name, const char **errmsg);
static void init_myfunc_errs(void);
C_MODE_START
-static const char **get_server_errmsgs()
+static const char **get_server_errmsgs(int nr)
{
+ int section= (nr-ER_ERROR_FIRST) / ERRORS_PER_RANGE;
if (!current_thd)
- return DEFAULT_ERRMSGS;
- return CURRENT_THD_ERRMSGS;
+ return DEFAULT_ERRMSGS[section];
+ return CURRENT_THD_ERRMSGS[section];
}
C_MODE_END
@@ -60,61 +63,88 @@ C_MODE_END
TRUE Error
*/
+static const char ***original_error_messages;
+
bool init_errmessage(void)
{
- const char **errmsgs, **ptr, **org_errmsgs;
+ const char **errmsgs;
bool error= FALSE;
DBUG_ENTER("init_errmessage");
- /*
- Get a pointer to the old error messages pointer array.
- read_texts() tries to free it.
- */
- org_errmsgs= my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST);
+ free_error_messages();
+ my_free(original_error_messages);
+ original_error_messages= 0;
+
+ error_message_charset_info= system_charset_info;
/* Read messages from file. */
if (read_texts(ERRMSG_FILE, my_default_lc_messages->errmsgs->language,
- &errmsgs, ER_ERROR_LAST - ER_ERROR_FIRST + 1) &&
- !errmsgs)
+ &original_error_messages))
{
- my_free(errmsgs);
-
- if (org_errmsgs)
- {
- /* Use old error messages */
- errmsgs= org_errmsgs;
- }
- else
+ /*
+ No error messages. Create a temporary empty error message so
+ that we don't get a crash if some code wrongly tries to access
+ a non existing error message.
+ */
+ if (!(original_error_messages= (const char***)
+ my_malloc(MAX_ERROR_RANGES * sizeof(char**) +
+ (ERRORS_PER_RANGE * sizeof(char*)),
+ MYF(0))))
+ DBUG_RETURN(TRUE);
+ errmsgs= (const char**) (original_error_messages + MAX_ERROR_RANGES);
+
+ for (uint i=0 ; i < MAX_ERROR_RANGES ; i++)
{
- /*
- No error messages. Create a temporary empty error message so
- that we don't get a crash if some code wrongly tries to access
- a non existing error message.
- */
- if (!(errmsgs= (const char**) my_malloc((ER_ERROR_LAST-ER_ERROR_FIRST+1)*
- sizeof(char*), MYF(0))))
- DBUG_RETURN(TRUE);
- for (ptr= errmsgs; ptr < errmsgs + ER_ERROR_LAST - ER_ERROR_FIRST; ptr++)
- *ptr= "";
- error= TRUE;
+ original_error_messages[i]= errmsgs;
+ errors_per_range[i]= ERRORS_PER_RANGE;
}
+ errors_per_range[2]= 0; // MYSYS error messages
+
+ for (const char **ptr= errmsgs;
+ ptr < errmsgs + ERRORS_PER_RANGE ;
+ ptr++)
+ *ptr= "";
+
+ error= TRUE;
}
- else
- my_free(org_errmsgs); // Free old language
/* Register messages for use with my_error(). */
- if (my_error_register(get_server_errmsgs, ER_ERROR_FIRST, ER_ERROR_LAST))
+ for (uint i=0 ; i < MAX_ERROR_RANGES ; i++)
{
- my_free(errmsgs);
- DBUG_RETURN(TRUE);
+ if (errors_per_range[i])
+ {
+ if (my_error_register(get_server_errmsgs, (i+1)*ERRORS_PER_RANGE,
+ (i+1)*ERRORS_PER_RANGE +
+ errors_per_range[i]-1))
+ {
+ my_free(original_error_messages);
+ original_error_messages= 0;
+ DBUG_RETURN(TRUE);
+ }
+ }
}
-
- DEFAULT_ERRMSGS= errmsgs; /* Init global variable */
+ DEFAULT_ERRMSGS= original_error_messages;
init_myfunc_errs(); /* Init myfunc messages */
DBUG_RETURN(error);
}
+void free_error_messages()
+{
+ /* We don't need to free errmsg as it's done in cleanup_errmsg */
+ for (uint i= 0 ; i < MAX_ERROR_RANGES ; i++)
+ {
+ if (errors_per_range[i])
+ {
+ my_error_unregister((i+1)*ERRORS_PER_RANGE,
+ (i+1)*ERRORS_PER_RANGE +
+ errors_per_range[i]-1);
+ errors_per_range[i]= 0;
+ }
+ }
+}
+
+
/**
Check the error messages array contains all relevant error messages
*/
@@ -125,11 +155,17 @@ static bool check_error_mesg(const char *file_name, const char **errmsg)
The last MySQL error message can't be an empty string; If it is,
it means that the error file doesn't contain all MySQL messages
and is probably from an older version of MySQL / MariaDB.
+ We also check that each section has enough error messages.
*/
- if (errmsg[ER_LAST_MYSQL_ERROR_MESSAGE -1 - ER_ERROR_FIRST][0] == 0)
+ if (errmsg[ER_LAST_MYSQL_ERROR_MESSAGE -1 - ER_ERROR_FIRST][0] == 0 ||
+ (errors_per_range[0] < ER_ERROR_LAST_SECTION_2 - ER_ERROR_FIRST + 1) ||
+ errors_per_range[1] != 0 ||
+ (errors_per_range[2] < ER_ERROR_LAST_SECTION_4 -
+ ER_ERROR_FIRST_SECTION_4 +1) ||
+ (errors_per_range[2] < ER_ERROR_LAST - ER_ERROR_FIRST_SECTION_5 + 1))
{
sql_print_error("Error message file '%s' is probably from and older "
- "version of MariaDB / MYSQL as it doesn't contain all "
+ "version of MariaDB as it doesn't contain all "
"error messages", file_name);
return 1;
}
@@ -137,27 +173,27 @@ static bool check_error_mesg(const char *file_name, const char **errmsg)
}
-/**
- Read text from packed textfile in language-directory.
+struct st_msg_file
+{
+ uint sections;
+ uint errors;
+ size_t text_length;
+};
- If we can't read messagefile then it's panic- we can't continue.
+/**
+ Open file for packed textfile in language-directory.
*/
-bool read_texts(const char *file_name, const char *language,
- const char ***point, uint error_messages)
+static File open_error_msg_file(const char *file_name, const char *language,
+ uint error_messages, struct st_msg_file *ret)
{
- register uint i;
- uint count,funktpos;
- size_t offset, length;
+ int error_pos= 0;
File file;
char name[FN_REFLEN];
char lang_path[FN_REFLEN];
- uchar *UNINIT_VAR(buff);
- uchar head[32],*pos;
- DBUG_ENTER("read_texts");
+ uchar head[32];
+ DBUG_ENTER("open_error_msg_file");
- *point= 0;
- funktpos=0;
convert_dirname(lang_path, language, NullS);
(void) my_load_path(lang_path, lang_path, lc_messages_dir);
if ((file= mysql_file_open(key_file_ERRMSG,
@@ -168,69 +204,120 @@ bool read_texts(const char *file_name, const char *language,
/*
Trying pre-5.4 sematics of the --language parameter.
It included the language-specific part, e.g.:
-
--language=/path/to/english/
*/
if ((file= mysql_file_open(key_file_ERRMSG,
- fn_format(name, file_name, lc_messages_dir, "", 4),
+ fn_format(name, file_name, lc_messages_dir, "",
+ 4),
O_RDONLY | O_SHARE | O_BINARY,
MYF(0))) < 0)
goto err;
sql_print_warning("An old style --language or -lc-message-dir value with language specific part detected: %s", lc_messages_dir);
sql_print_warning("Use --lc-messages-dir without language specific part instead.");
}
-
- funktpos=1;
+ error_pos=1;
if (mysql_file_read(file, (uchar*) head, 32, MYF(MY_NABP)))
goto err;
- funktpos=2;
+ error_pos=2;
if (head[0] != (uchar) 254 || head[1] != (uchar) 254 ||
- head[2] != 2 || head[3] != 3)
+ head[2] != 2 || head[3] != 4)
goto err; /* purecov: inspected */
- error_message_charset_info= system_charset_info;
- length=uint4korr(head+6); count=uint2korr(head+10);
+ ret->text_length= uint4korr(head+6);
+ ret->errors= uint2korr(head+10);
+ ret->sections= uint2korr(head+12);
- if (count < error_messages)
+ if (ret->errors < error_messages || ret->sections != MAX_ERROR_RANGES)
{
sql_print_error("\
Error message file '%s' had only %d error messages, but it should contain at least %d error messages.\nCheck that the above file is the right version for this program!",
- name,count,error_messages);
+ name,ret->errors,error_messages);
(void) mysql_file_close(file, MYF(MY_WME));
- DBUG_RETURN(1);
+ DBUG_RETURN(FERR);
}
+ DBUG_RETURN(file);
- if (!(*point= (const char**)
- my_malloc((size_t) (MY_MAX(length,count*2)+count*sizeof(char*)),MYF(0))))
- {
- funktpos=3; /* purecov: inspected */
+err:
+ sql_print_error((error_pos == 2) ?
+ "Incompatible header in messagefile '%s'. Probably from "
+ "another version of MariaDB" :
+ ((error_pos == 1) ? "Can't read from messagefile '%s'" :
+ "Can't find messagefile '%s'"), name);
+ if (file != FERR)
+ (void) mysql_file_close(file, MYF(MY_WME));
+ DBUG_RETURN(FERR);
+}
+
+
+/*
+ Define the number of normal and extra error messages in the errmsg.sys
+ file
+*/
+
+static const uint error_messages= ER_ERROR_LAST - ER_ERROR_FIRST+1;
+
+/**
+ Read text from packed textfile in language-directory.
+*/
+
+bool read_texts(const char *file_name, const char *language,
+ const char ****data)
+{
+ uint i, range_size;
+ const char **point;
+ size_t offset;
+ File file;
+ uchar *buff, *pos;
+ struct st_msg_file msg_file;
+ DBUG_ENTER("read_texts");
+
+ if ((file= open_error_msg_file(file_name, language, error_messages,
+ &msg_file)) == FERR)
+ DBUG_RETURN(1);
+
+ if (!(*data= (const char***)
+ my_malloc((size_t) ((MAX_ERROR_RANGES+1) * sizeof(char**) +
+ MY_MAX(msg_file.text_length, msg_file.errors * 2)+
+ msg_file.errors * sizeof(char*)),
+ MYF(MY_WME))))
goto err; /* purecov: inspected */
- }
- buff= (uchar*) (*point + count);
- if (mysql_file_read(file, buff, (size_t) count*2, MYF(MY_NABP)))
+ point= (const char**) ((*data) + MAX_ERROR_RANGES);
+ buff= (uchar*) (point + msg_file.errors);
+
+ if (mysql_file_read(file, buff,
+ (size_t) (msg_file.errors + msg_file.sections) * 2,
+ MYF(MY_NABP | MY_WME)))
goto err;
- for (i=0, offset=0, pos= buff ; i< count ; i++)
+
+ pos= buff;
+ /* read in sections */
+ for (i= 0, offset= 0; i < msg_file.sections ; i++)
{
- (*point)[i]= (char*) buff+offset;
- offset+= uint2korr(pos);
+ (*data)[i]= point + offset;
+ errors_per_range[i]= range_size= uint2korr(pos);
+ offset+= range_size;
+ pos+= 2;
+ }
+
+ /* Calculate pointers to text data */
+ for (i=0, offset=0 ; i < msg_file.errors ; i++)
+ {
+ point[i]= (char*) buff+offset;
+ offset+=uint2korr(pos);
pos+=2;
}
- if (mysql_file_read(file, buff, length, MYF(MY_NABP)))
+
+ /* Read error message texts */
+ if (mysql_file_read(file, buff, msg_file.text_length, MYF(MY_NABP | MY_WME)))
goto err;
- (void) mysql_file_close(file, MYF(0));
+ (void) mysql_file_close(file, MYF(MY_WME));
- i= check_error_mesg(file_name, *point);
- DBUG_RETURN(i);
+ DBUG_RETURN(check_error_mesg(file_name, point));
err:
- sql_print_error((funktpos == 3) ? "Not enough memory for messagefile '%s'" :
- (funktpos == 2) ? "Incompatible header in messagefile '%s'. Probably from another version of MariaDB" :
- ((funktpos == 1) ? "Can't read from messagefile '%s'" :
- "Can't find messagefile '%s'"), name);
- if (file != FERR)
- (void) mysql_file_close(file, MYF(MY_WME));
+ (void) mysql_file_close(file, MYF(0));
DBUG_RETURN(1);
} /* read_texts */
diff --git a/sql/derror.h b/sql/derror.h
index b2f6331e048..9f2aee71c7e 100644
--- a/sql/derror.h
+++ b/sql/derror.h
@@ -19,7 +19,8 @@
#include "my_global.h" /* uint */
bool init_errmessage(void);
+void free_error_messages();
bool read_texts(const char *file_name, const char *language,
- const char ***point, uint error_messages);
+ const char ****data);
#endif /* DERROR_INCLUDED */
diff --git a/sql/handler.cc b/sql/handler.cc
index 748a51f5c59..a03a0912908 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -295,7 +295,7 @@ handler *get_ha_partition(partition_info *part_info)
static const char **handler_errmsgs;
C_MODE_START
-static const char **get_handler_errmsgs()
+static const char **get_handler_errmsgs(int nr)
{
return handler_errmsgs;
}
@@ -386,12 +386,10 @@ int ha_init_errors(void)
*/
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(errmsgs);
+ my_error_unregister(HA_ERR_FIRST, HA_ERR_LAST);
+ my_free(handler_errmsgs);
+ handler_errmsgs= 0;
return 0;
}
diff --git a/sql/log_event.cc b/sql/log_event.cc
index b56a9e2aee3..3715f0cc4d4 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -4523,7 +4523,7 @@ compare_errors:
"Error on master: message (format)='%s' error code=%d ; "
"Error on slave: actual message='%s', error code=%d. "
"Default database: '%s'. Query: '%s'",
- ER_SAFE_THD(thd, expected_error),
+ ER_THD(thd, expected_error),
expected_error,
actual_error ? thd->get_stmt_da()->message() : "no error",
actual_error,
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index e7d7f90d44e..f53a41ead18 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -2234,13 +2234,12 @@ void clean_up(bool print_message)
if (print_message && my_default_lc_messages && server_start_time)
sql_print_information(ER_DEFAULT(ER_SHUTDOWN_COMPLETE),my_progname);
- cleanup_errmsgs();
MYSQL_CALLBACK(thread_scheduler, end, ());
thread_scheduler= 0;
mysql_library_end();
finish_client_errs();
- (void) my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST); // finish server errs
- DBUG_PRINT("quit", ("Error messages freed"));
+ cleanup_errmsgs();
+ free_error_messages();
/* Tell main we are ready */
logger.cleanup_end();
sys_var_end();
@@ -6012,6 +6011,8 @@ int mysqld_main(int argc, char **argv)
mysqld_port,
MYSQL_COMPILATION_COMMENT);
+ sql_print_information(ER_DEFAULT(ER_EXTRA_TEST)); // QQ
+
// try to keep fd=0 busy
if (!freopen(IF_WIN("NUL","/dev/null"), "r", stdin))
{
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 0d168e937a9..bcad75de25d 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -7154,3 +7154,20 @@ ER_WRONG_ORDER_IN_WITH_CLAUSE
eng "The definition of the table '%s' refers to the table '%s' defined later in a non-recursive WITH clause"
ER_RECURSIVE_QUERY_IN_WITH_CLAUSE
eng "Recursive queries in WITH clause are not supported yet"
+
+#
+# Internal errors, not used
+#
+skip-to-error-number 2000
+
+# MySQL 5.7 error numbers starts here
+skip-to-error-number 3000
+
+ER_MYSQL_57_TEST
+ eng "5.7 test"
+
+# MariaDB extra error numbers starts from 4000
+skip-to-error-number 4000
+
+ER_EXTRA_TEST
+ eng "10.2 test"
diff --git a/sql/sql_class.h b/sql/sql_class.h
index be652e6dd01..7eb00d948a2 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -658,7 +658,7 @@ typedef struct system_variables
/* Error messages */
MY_LOCALE *lc_messages;
- const char **errmsgs; /* lc_messages->errmsg->errmsgs */
+ const char ***errmsgs; /* lc_messages->errmsg->errmsgs */
/* Locale Support */
MY_LOCALE *lc_time_names;
diff --git a/sql/sql_locale.h b/sql/sql_locale.h
index 8357a9ecba4..e231393eec6 100644
--- a/sql/sql_locale.h
+++ b/sql/sql_locale.h
@@ -19,7 +19,7 @@
typedef struct my_locale_errmsgs
{
const char *language;
- const char **errmsgs;
+ const char ***errmsgs;
} MY_LOCALE_ERRMSGS;
#include "my_global.h" /* uint */
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 9d871703bfe..4bf202813f3 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -4629,8 +4629,7 @@ static bool check_locale(sys_var *self, THD *thd, set_var *var)
mysql_mutex_lock(&LOCK_error_messages);
res= (!locale->errmsgs->errmsgs &&
read_texts(ERRMSG_FILE, locale->errmsgs->language,
- &locale->errmsgs->errmsgs,
- ER_ERROR_LAST - ER_ERROR_FIRST + 1));
+ &locale->errmsgs->errmsgs));
mysql_mutex_unlock(&LOCK_error_messages);
if (res)
{
diff --git a/sql/unireg.h b/sql/unireg.h
index 10751b6ec93..251597c1884 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -43,15 +43,16 @@
#define PLUGINDIR "lib/plugin"
#endif
-#define CURRENT_THD_ERRMSGS current_thd->variables.errmsgs
-#define DEFAULT_ERRMSGS my_default_lc_messages->errmsgs->errmsgs
-
-#define ER(X) CURRENT_THD_ERRMSGS[(X) - ER_ERROR_FIRST]
-#define ER_DEFAULT(X) DEFAULT_ERRMSGS[(X) - ER_ERROR_FIRST]
-#define ER_SAFE(X) (((X) >= ER_ERROR_FIRST && (X) <= ER_ERROR_LAST) ? ER(X) : "Invalid error code")
-#define ER_SAFE_THD(T,X) (((X) >= ER_ERROR_FIRST && (X) <= ER_ERROR_LAST) ? ER_THD(T,X) : "Invalid error code")
-#define ER_THD(thd,X) ((thd)->variables.errmsgs[(X) - ER_ERROR_FIRST])
-#define ER_THD_OR_DEFAULT(thd,X) ((thd) ? ER_THD(thd, X) : ER_DEFAULT(X))
+#define MAX_ERROR_RANGES 4 /* 1000-2000, 2000-3000, 3000-4000, 4000-5000 */
+#define ERRORS_PER_RANGE 1000
+
+#define DEFAULT_ERRMSGS my_default_lc_messages->errmsgs->errmsgs
+#define CURRENT_THD_ERRMSGS (current_thd)->variables.errmsgs
+
+#define ER_DEFAULT(X) DEFAULT_ERRMSGS[((X)-ER_ERROR_FIRST) / ERRORS_PER_RANGE][(X)% ERRORS_PER_RANGE]
+#define ER_THD(thd,X) ((thd)->variables.errmsgs[((X)-ER_ERROR_FIRST) / ERRORS_PER_RANGE][(X) % ERRORS_PER_RANGE])
+#define ER(X) ER_THD(current_thd, (X))
+#define ER_THD_OR_DEFAULT(thd,X) ((thd) ? ER_THD(thd, (X)) : ER_DEFAULT(X))
#define ME_INFO (ME_HOLDTANG+ME_OLDWIN+ME_NOREFRESH)
#define ME_ERROR (ME_BELL+ME_OLDWIN+ME_NOREFRESH)