diff options
author | Sergei Petrunia <psergey@askmonty.org> | 2016-04-07 00:54:39 +0300 |
---|---|---|
committer | Sergei Petrunia <psergey@askmonty.org> | 2016-04-07 00:54:39 +0300 |
commit | 59e5f5b47e1f12a1426319a905dbc8cc55219c0d (patch) | |
tree | b2095faf431949d31e2ea69200bea27a8cf2f629 /sql/derror.cc | |
parent | 306de8a927916db98c67fa338b5a275735f78240 (diff) | |
parent | 89b744eb6c2484412f476a53087cea7bf28dc917 (diff) | |
download | mariadb-git-59e5f5b47e1f12a1426319a905dbc8cc55219c0d.tar.gz |
Merge branch '10.2' into bb-10.2-mdev9543
- Make Window Functions errors use the MariaDB's extra error range.
- Fix a trivial bug in check_error_mesg
Diffstat (limited to 'sql/derror.cc')
-rw-r--r-- | sql/derror.cc | 255 |
1 files changed, 172 insertions, 83 deletions
diff --git a/sql/derror.cc b/sql/derror.cc index bc4b89493aa..5a1bee23f4a 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[3] < 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,28 @@ 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 max_error; + 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 +205,121 @@ 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->max_error= uint2korr(head+10); + ret->errors= uint2korr(head+12); + ret->sections= uint2korr(head+14); - if (count < error_messages) + if (ret->max_error < 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 */ |