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 | |
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')
-rw-r--r-- | sql/derror.cc | 255 | ||||
-rw-r--r-- | sql/derror.h | 3 | ||||
-rw-r--r-- | sql/events.cc | 2 | ||||
-rw-r--r-- | sql/field.cc | 16 | ||||
-rw-r--r-- | sql/handler.cc | 11 | ||||
-rw-r--r-- | sql/item.h | 2 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 2 | ||||
-rw-r--r-- | sql/key.cc | 5 | ||||
-rw-r--r-- | sql/log_event.cc | 2 | ||||
-rw-r--r-- | sql/mysqld.cc | 5 | ||||
-rw-r--r-- | sql/opt_subselect.cc | 1 | ||||
-rw-r--r-- | sql/rpl_parallel.cc | 1 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 15 | ||||
-rw-r--r-- | sql/sql_class.h | 2 | ||||
-rw-r--r-- | sql/sql_connect.cc | 2 | ||||
-rw-r--r-- | sql/sql_load.cc | 459 | ||||
-rw-r--r-- | sql/sql_locale.h | 2 | ||||
-rw-r--r-- | sql/sql_select.cc | 2 | ||||
-rw-r--r-- | sql/sql_show.cc | 8 | ||||
-rw-r--r-- | sql/sql_string.cc | 2 | ||||
-rw-r--r-- | sql/sql_trigger.cc | 1 | ||||
-rw-r--r-- | sql/strfunc.cc | 2 | ||||
-rw-r--r-- | sql/sys_vars.cc | 3 | ||||
-rw-r--r-- | sql/unireg.h | 19 |
24 files changed, 484 insertions, 338 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 */ 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/events.cc b/sql/events.cc index f428bc17927..5ef4d6f55a5 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -102,7 +102,7 @@ ulong Events::inited; int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs) { return cs->coll->strnncollsp(cs, (uchar *) s.str,s.length, - (uchar *) t.str,t.length, 0); + (uchar *) t.str,t.length); } diff --git a/sql/field.cc b/sql/field.cc index 6be45005d48..a5d2d759edc 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1224,7 +1224,8 @@ bool Field::test_if_equality_guarantees_uniqueness(const Item *item) const for temporal columns, so the query: WHERE temporal_column='string' cannot return multiple distinct temporal values. - QQ: perhaps we could allow INT/DECIMAL/DOUBLE types for temporal items. + + TODO: perhaps we could allow INT/DECIMAL/DOUBLE types for temporal items. */ return result_type() == item->result_type(); } @@ -7136,8 +7137,7 @@ int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr) */ return field_charset->coll->strnncollsp(field_charset, a_ptr, a_len, - b_ptr, b_len, - 0); + b_ptr, b_len); } @@ -7511,7 +7511,7 @@ int Field_varstring::cmp_max(const uchar *a_ptr, const uchar *b_ptr, a_length, b_ptr+ length_bytes, - b_length,0); + b_length); return diff; } @@ -7534,7 +7534,7 @@ int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length) length, key_ptr+ HA_KEY_BLOB_LENGTH, - uint2korr(key_ptr), 0); + uint2korr(key_ptr)); } @@ -7552,8 +7552,7 @@ int Field_varstring::key_cmp(const uchar *a,const uchar *b) a + HA_KEY_BLOB_LENGTH, uint2korr(a), b + HA_KEY_BLOB_LENGTH, - uint2korr(b), - 0); + uint2korr(b)); } @@ -8053,8 +8052,7 @@ int Field_blob::cmp(const uchar *a,uint32 a_length, const uchar *b, uint32 b_length) { return field_charset->coll->strnncollsp(field_charset, - a, a_length, b, b_length, - 0); + a, a_length, b, b_length); } diff --git a/sql/handler.cc b/sql/handler.cc index 748a51f5c59..2186d389056 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; } @@ -3079,6 +3077,7 @@ int handler::update_auto_increment() if (unlikely(nr == ULONGLONG_MAX)) DBUG_RETURN(HA_ERR_AUTOINC_ERANGE); + DBUG_ASSERT(nr != 0); DBUG_PRINT("info",("auto_increment: %llu nb_reserved_values: %llu", nr, append ? nb_reserved_values : 0)); diff --git a/sql/item.h b/sql/item.h index 863265a73f7..674ff6e99dc 100644 --- a/sql/item.h +++ b/sql/item.h @@ -189,7 +189,7 @@ public: { return collation->coll->strnncollsp(collation, (uchar *) s->ptr(), s->length(), - (uchar *) t->ptr(), t->length(), 0); + (uchar *) t->ptr(), t->length()); } }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 187d2820531..335228c37fa 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4074,7 +4074,7 @@ static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y) { return cs->coll->strnncollsp(cs, (uchar *) x->ptr(),x->length(), - (uchar *) y->ptr(),y->length(), 0); + (uchar *) y->ptr(),y->length()); } void Item_func_in::fix_length_and_dec() diff --git a/sql/key.cc b/sql/key.cc index 1b00e951de0..31b65adabe9 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -328,7 +328,7 @@ bool key_cmp_if_same(TABLE *table,const uchar *key,uint idx,uint key_length) } if (cs->coll->strnncollsp(cs, (const uchar*) key, length, - (const uchar*) pos, char_length, 0)) + (const uchar*) pos, char_length)) return 1; continue; } @@ -891,8 +891,7 @@ bool key_buf_cmp(KEY *key_info, uint used_key_parts, if (length1 != length2 || cs->coll->strnncollsp(cs, pos1 + pack_length, byte_len1, - pos2 + pack_length, byte_len2, - 1)) + pos2 + pack_length, byte_len2)) return TRUE; key1+= pack_length; key2+= pack_length; } 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..f5ed61446f7 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(); diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 33c406bd756..55c6c075f48 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -4167,7 +4167,6 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd) field->null_ptr, field->null_bit))) goto err; - key_part_info->key_part_flag|= HA_END_SPACE_ARE_EQUAL; //todo need this? } keyinfo->key_length+= key_part_info->length; } diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index acdedd6e0a0..df036d0e23f 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -987,7 +987,6 @@ handle_rpl_parallel_thread(void *arg) thd->client_capabilities = CLIENT_LOCAL_FILES; thd->net.reading_or_writing= 0; thd_proc_info(thd, "Waiting for work from main SQL threads"); - thd->set_time(); thd->variables.lock_wait_timeout= LONG_TIMEOUT; thd->system_thread_info.rpl_sql_info= &sql_info; /* diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index d6b180b79aa..376c1eb9d0d 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7154,6 +7154,21 @@ 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_WRONG_WINDOW_SPEC_NAME eng "Window specification with name '%s' is not defined" ER_DUP_WINDOW_NAME diff --git a/sql/sql_class.h b/sql/sql_class.h index f2b8481ff7f..b68a6e5ebd9 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_connect.cc b/sql/sql_connect.cc index ea114bf40a5..66564bd5e94 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1192,7 +1192,6 @@ void prepare_new_connection_state(THD* thd) */ thd->proc_info= 0; thd->set_command(COM_SLEEP); - thd->set_time(); thd->init_for_queries(); if (opt_init_connect.length && !(sctx->master_access & SUPER_ACL)) @@ -1234,7 +1233,6 @@ void prepare_new_connection_state(THD* thd) } thd->proc_info=0; - thd->set_time(); thd->init_for_queries(); } } diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 94b0fe72ac3..a4044dd0d59 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -61,24 +61,128 @@ XML_TAG::XML_TAG(int l, String f, String v) } +/* + Field and line terminators must be interpreted as sequence of unsigned char. + Otherwise, non-ascii terminators will be negative on some platforms, + and positive on others (depending on the implementation of char). +*/ +class Term_string +{ + const uchar *m_ptr; + uint m_length; + int m_initial_byte; +public: + Term_string(const String &str) : + m_ptr(static_cast<const uchar*>(static_cast<const void*>(str.ptr()))), + m_length(str.length()), + m_initial_byte((uchar) (str.length() ? str.ptr()[0] : INT_MAX)) + { } + void set(const uchar *str, uint length, int initial_byte) + { + m_ptr= str; + m_length= length; + m_initial_byte= initial_byte; + } + void reset() { set(NULL, 0, INT_MAX); } + const uchar *ptr() const { return m_ptr; } + uint length() const { return m_length; } + int initial_byte() const { return m_initial_byte; } + bool eq(const Term_string &other) const + { + return length() == other.length() && !memcmp(ptr(), other.ptr(), length()); + } +}; + + #define GET (stack_pos != stack ? *--stack_pos : my_b_get(&cache)) #define PUSH(A) *(stack_pos++)=(A) class READ_INFO { File file; - uchar *buffer, /* Buffer for read text */ - *end_of_buff; /* Data in bufferts ends here */ - uint buff_length, /* Length of buffert */ - max_length; /* Max length of row */ - const uchar *field_term_ptr,*line_term_ptr; - const char *line_start_ptr,*line_start_end; - uint field_term_length,line_term_length,enclosed_length; - int field_term_char,line_term_char,enclosed_char,escape_char; + String data; /* Read buffer */ + uint fixed_length; /* Length of the fixed length record */ + uint max_length; /* Max length of row */ + Term_string m_field_term; /* FIELDS TERMINATED BY 'string' */ + Term_string m_line_term; /* LINES TERMINATED BY 'string' */ + Term_string m_line_start; /* LINES STARTING BY 'string' */ + int enclosed_char,escape_char; int *stack,*stack_pos; bool found_end_of_line,start_of_line,eof; NET *io_net; int level; /* for load xml */ + bool getbyte(char *to) + { + int chr= GET; + if (chr == my_b_EOF) + return (eof= true); + *to= chr; + return false; + } + + /** + Read a tail of a multi-byte character. + The first byte of the character is assumed to be already + read from the file and appended to "str". + + @returns true - if EOF happened unexpectedly + @returns false - no EOF happened: found a good multi-byte character, + or a bad byte sequence + + Note: + The return value depends only on EOF: + - read_mbtail() returns "false" is a good character was read, but also + - read_mbtail() returns "false" if an incomplete byte sequence was found + and no EOF happened. + + For example, suppose we have an ujis file with bytes 0x8FA10A, where: + - 0x8FA1 is an incomplete prefix of a 3-byte character + (it should be [8F][A1-FE][A1-FE] to make a full 3-byte character) + - 0x0A is a line demiliter + This file has some broken data, the trailing [A1-FE] is missing. + + In this example it works as follows: + - 0x8F is read from the file and put into "data" before the call + for read_mbtail() + - 0xA1 is read from the file and put into "data" by read_mbtail() + - 0x0A is kept in the read queue, so the next read iteration after + the current read_mbtail() call will normally find it and recognize as + a line delimiter + - the current call for read_mbtail() returns "false", + because no EOF happened + */ + bool read_mbtail(String *str) + { + int chlen; + if ((chlen= my_charlen(read_charset, str->end() - 1, str->end())) == 1) + return false; // Single byte character found + for (uint32 length0= str->length() - 1 ; MY_CS_IS_TOOSMALL(chlen); ) + { + int chr= GET; + if (chr == my_b_EOF) + { + DBUG_PRINT("info", ("read_mbtail: chlen=%d; unexpected EOF", chlen)); + return true; // EOF + } + str->append(chr); + chlen= my_charlen(read_charset, str->ptr() + length0, str->end()); + if (chlen == MY_CS_ILSEQ) + { + /** + It has been an incomplete (but a valid) sequence so far, + but the last byte turned it into a bad byte sequence. + Unget the very last byte. + */ + str->length(str->length() - 1); + PUSH(chr); + DBUG_PRINT("info", ("read_mbtail: ILSEQ")); + return false; // Bad byte sequence + } + } + DBUG_PRINT("info", ("read_mbtail: chlen=%d", chlen)); + return false; // Good multi-byte character + } + public: bool error,line_cuted,found_null,enclosed; uchar *row_start, /* Found row starts here */ @@ -94,7 +198,11 @@ public: int read_fixed_length(void); int next_line(void); char unescape(char chr); - int terminator(const uchar *ptr, uint length); + bool terminator(const uchar *ptr, uint length); + bool terminator(const Term_string &str) + { return terminator(str.ptr(), str.length()); } + bool terminator(int chr, const Term_string &str) + { return str.initial_byte() == chr && terminator(str); } bool find_start_of_fields(); /* load xml */ List<XML_TAG> taglist; @@ -1344,63 +1452,40 @@ READ_INFO::READ_INFO(THD *thd, File file_par, uint tot_length, CHARSET_INFO *cs, String &field_term, String &line_start, String &line_term, String &enclosed_par, int escape, bool get_it_from_net, bool is_fifo) - :file(file_par), buffer(NULL), buff_length(tot_length), escape_char(escape), - found_end_of_line(false), eof(false), + :file(file_par), fixed_length(tot_length), + m_field_term(field_term), m_line_term(line_term), m_line_start(line_start), + escape_char(escape), found_end_of_line(false), eof(false), error(false), line_cuted(false), found_null(false), read_charset(cs) { + data.set_thread_specific(); /* Field and line terminators must be interpreted as sequence of unsigned char. Otherwise, non-ascii terminators will be negative on some platforms, and positive on others (depending on the implementation of char). */ - field_term_ptr= - static_cast<const uchar*>(static_cast<const void*>(field_term.ptr())); - field_term_length= field_term.length(); - line_term_ptr= - static_cast<const uchar*>(static_cast<const void*>(line_term.ptr())); - line_term_length= line_term.length(); level= 0; /* for load xml */ - if (line_start.length() == 0) - { - line_start_ptr=0; - start_of_line= 0; - } - else - { - line_start_ptr= line_start.ptr(); - line_start_end=line_start_ptr+line_start.length(); - start_of_line= 1; - } + start_of_line= line_start.length() != 0; /* If field_terminator == line_terminator, don't use line_terminator */ - if (field_term_length == line_term_length && - !memcmp(field_term_ptr,line_term_ptr,field_term_length)) - { - line_term_length=0; - line_term_ptr= NULL; - } - enclosed_char= (enclosed_length=enclosed_par.length()) ? - (uchar) enclosed_par[0] : INT_MAX; - field_term_char= field_term_length ? field_term_ptr[0] : INT_MAX; - line_term_char= line_term_length ? line_term_ptr[0] : INT_MAX; + if (m_field_term.eq(m_line_term)) + m_line_term.reset(); + enclosed_char= enclosed_par.length() ? (uchar) enclosed_par[0] : INT_MAX; /* Set of a stack for unget if long terminators */ - uint length= MY_MAX(cs->mbmaxlen, MY_MAX(field_term_length, line_term_length)) + 1; + uint length= MY_MAX(cs->mbmaxlen, MY_MAX(m_field_term.length(), + m_line_term.length())) + 1; set_if_bigger(length,line_start.length()); stack= stack_pos= (int*) thd->alloc(sizeof(int) * length); - if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(MY_THREAD_SPECIFIC)))) + if (data.reserve(tot_length)) error=1; /* purecov: inspected */ else { - end_of_buff=buffer+buff_length; if (init_io_cache(&cache,(get_it_from_net) ? -1 : file, 0, (get_it_from_net) ? READ_NET : (is_fifo ? READ_FIFO : READ_CACHE),0L,1, MYF(MY_WME | MY_THREAD_SPECIFIC))) { - my_free(buffer); /* purecov: inspected */ - buffer= NULL; error=1; } else @@ -1423,7 +1508,6 @@ READ_INFO::READ_INFO(THD *thd, File file_par, uint tot_length, CHARSET_INFO *cs, READ_INFO::~READ_INFO() { ::end_io_cache(&cache); - my_free(buffer); List_iterator<XML_TAG> xmlit(taglist); XML_TAG *t; while ((t= xmlit++)) @@ -1431,7 +1515,7 @@ READ_INFO::~READ_INFO() } -inline int READ_INFO::terminator(const uchar *ptr,uint length) +inline bool READ_INFO::terminator(const uchar *ptr, uint length) { int chr=0; // Keep gcc happy uint i; @@ -1443,18 +1527,17 @@ inline int READ_INFO::terminator(const uchar *ptr,uint length) } } if (i == length) - return 1; + return true; PUSH(chr); while (i-- > 1) PUSH(*--ptr); - return 0; + return false; } int READ_INFO::read_field() { int chr,found_enclosed_char; - uchar *to,*new_buffer; found_null=0; if (found_end_of_line) @@ -1473,11 +1556,11 @@ int READ_INFO::read_field() found_end_of_line=eof=1; return 1; } - to=buffer; + data.length(0); if (chr == enclosed_char) { found_enclosed_char=enclosed_char; - *to++=(uchar) chr; // If error + data.append(chr); // If error } else { @@ -1487,7 +1570,8 @@ int READ_INFO::read_field() for (;;) { - while ( to < end_of_buff) + // Make sure we have enough space for the longest multi-byte character. + while (data.length() + read_charset->mbmaxlen <= data.alloced_length()) { chr = GET; if (chr == my_b_EOF) @@ -1496,7 +1580,7 @@ int READ_INFO::read_field() { if ((chr=GET) == my_b_EOF) { - *to++= (uchar) escape_char; + data.append(escape_char); goto found_eof; } /* @@ -1508,24 +1592,24 @@ int READ_INFO::read_field() */ if (escape_char != enclosed_char || chr == escape_char) { - *to++ = (uchar) unescape((char) chr); + data.append(unescape((char) chr)); continue; } PUSH(chr); chr= escape_char; } #ifdef ALLOW_LINESEPARATOR_IN_STRINGS - if (chr == line_term_char) + if (chr == m_line_term.initial_byte()) #else - if (chr == line_term_char && found_enclosed_char == INT_MAX) + if (chr == m_line_term.initial_byte() && found_enclosed_char == INT_MAX) #endif { - if (terminator(line_term_ptr,line_term_length)) + if (terminator(m_line_term)) { // Maybe unexpected linefeed enclosed=0; found_end_of_line=1; - row_start=buffer; - row_end= to; + row_start= (uchar *) data.ptr(); + row_end= (uchar *) data.end(); return 0; } } @@ -1533,27 +1617,24 @@ int READ_INFO::read_field() { if ((chr=GET) == found_enclosed_char) { // Remove dupplicated - *to++ = (uchar) chr; + data.append(chr); continue; } // End of enclosed field if followed by field_term or line_term - if (chr == my_b_EOF || - (chr == line_term_char && terminator(line_term_ptr, - line_term_length))) + if (chr == my_b_EOF || terminator(chr, m_line_term)) { /* Maybe unexpected linefeed */ enclosed=1; found_end_of_line=1; - row_start=buffer+1; - row_end= to; + row_start= (uchar *) data.ptr() + 1; + row_end= (uchar *) data.end(); return 0; } - if (chr == field_term_char && - terminator(field_term_ptr,field_term_length)) + if (terminator(chr, m_field_term)) { enclosed=1; - row_start=buffer+1; - row_end= to; + row_start= (uchar *) data.ptr() + 1; + row_end= (uchar *) data.end(); return 0; } /* @@ -1564,68 +1645,33 @@ int READ_INFO::read_field() /* copy the found term character to 'to' */ chr= found_enclosed_char; } - else if (chr == field_term_char && found_enclosed_char == INT_MAX) + else if (chr == m_field_term.initial_byte() && + found_enclosed_char == INT_MAX) { - if (terminator(field_term_ptr,field_term_length)) + if (terminator(m_field_term)) { enclosed=0; - row_start=buffer; - row_end= to; + row_start= (uchar *) data.ptr(); + row_end= (uchar *) data.end(); return 0; } } -#ifdef USE_MB - if (my_mbcharlen(read_charset, chr) > 1 && - to + my_mbcharlen(read_charset, chr) <= end_of_buff) - { - uchar* p= to; - int ml, i; - *to++ = chr; - - ml= my_mbcharlen(read_charset, chr); - - for (i= 1; i < ml; i++) - { - chr= GET; - if (chr == my_b_EOF) - { - /* - Need to back up the bytes already ready from illformed - multi-byte char - */ - to-= i; - goto found_eof; - } - *to++ = chr; - } - if (my_ismbchar(read_charset, - (const char *)p, - (const char *)to)) - continue; - for (i= 0; i < ml; i++) - PUSH(*--to); - chr= GET; - } -#endif - *to++ = (uchar) chr; + data.append(chr); + if (use_mb(read_charset) && read_mbtail(&data)) + goto found_eof; } /* ** We come here if buffer is too small. Enlarge it and continue */ - if (!(new_buffer=(uchar*) my_realloc((char*) buffer,buff_length+1+IO_SIZE, - MYF(MY_WME | MY_THREAD_SPECIFIC)))) - return (error=1); - to=new_buffer + (to-buffer); - buffer=new_buffer; - buff_length+=IO_SIZE; - end_of_buff=buffer+buff_length; + if (data.reserve(IO_SIZE)) + return (error= 1); } found_eof: enclosed=0; found_end_of_line=eof=1; - row_start=buffer; - row_end=to; + row_start= (uchar *) data.ptr(); + row_end= (uchar *) data.end(); return 0; } @@ -1647,7 +1693,6 @@ found_eof: int READ_INFO::read_fixed_length() { int chr; - uchar *to; if (found_end_of_line) return 1; // One have to call next_line @@ -1658,8 +1703,7 @@ int READ_INFO::read_fixed_length() return 1; } - to=row_start=buffer; - while (to < end_of_buff) + for (data.length(0); data.length() < fixed_length ; ) { if ((chr=GET) == my_b_EOF) goto found_eof; @@ -1667,105 +1711,129 @@ int READ_INFO::read_fixed_length() { if ((chr=GET) == my_b_EOF) { - *to++= (uchar) escape_char; + data.append(escape_char); goto found_eof; } - *to++ =(uchar) unescape((char) chr); + data.append((uchar) unescape((char) chr)); continue; } - if (chr == line_term_char) - { - if (terminator(line_term_ptr,line_term_length)) - { // Maybe unexpected linefeed - found_end_of_line=1; - row_end= to; - return 0; - } + if (terminator(chr, m_line_term)) + { // Maybe unexpected linefeed + found_end_of_line= true; + break; } - *to++ = (uchar) chr; + data.append(chr); } - row_end=to; // Found full line + row_start= (uchar *) data.ptr(); + row_end= (uchar *) data.end(); // Found full line return 0; found_eof: found_end_of_line=eof=1; - row_start=buffer; - row_end=to; - return to == buffer ? 1 : 0; + row_start= (uchar *) data.ptr(); + row_end= (uchar *) data.end(); + return data.length() == 0 ? 1 : 0; } int READ_INFO::next_line() { line_cuted=0; - start_of_line= line_start_ptr != 0; + start_of_line= m_line_start.length() != 0; if (found_end_of_line || eof) { found_end_of_line=0; return eof; } found_end_of_line=0; - if (!line_term_length) + if (!m_line_term.length()) return 0; // No lines for (;;) { - int chr = GET; -#ifdef USE_MB - if (my_mbcharlen(read_charset, chr) > 1) - { - for (uint i=1; - chr != my_b_EOF && i<my_mbcharlen(read_charset, chr); - i++) - chr = GET; - if (chr == escape_char) - continue; - } -#endif - if (chr == my_b_EOF) - { - eof=1; - return 1; + int chlen; + char buf[MY_CS_MBMAXLEN]; + + if (getbyte(&buf[0])) + return 1; // EOF + + if (use_mb(read_charset) && + (chlen= my_charlen(read_charset, buf, buf + 1)) != 1) + { + uint i; + for (i= 1; MY_CS_IS_TOOSMALL(chlen); ) + { + DBUG_ASSERT(i < sizeof(buf)); + DBUG_ASSERT(chlen != 1); + if (getbyte(&buf[i++])) + return 1; // EOF + chlen= my_charlen(read_charset, buf, buf + i); + } + + /* + Either a complete multi-byte sequence, + or a broken byte sequence was found. + Check if the sequence is a prefix of the "LINES TERMINATED BY" string. + */ + if ((uchar) buf[0] == m_line_term.initial_byte() && + i <= m_line_term.length() && + !memcmp(buf, m_line_term.ptr(), i)) + { + if (m_line_term.length() == i) + { + /* + We found a "LINES TERMINATED BY" string that consists + of a single multi-byte character. + */ + return 0; + } + /* + buf[] is a prefix of "LINES TERMINATED BY". + Now check the suffix. Length of the suffix of line_term_ptr + that still needs to be checked is (line_term_length - i). + Note, READ_INFO::terminator() assumes that the leftmost byte of the + argument is already scanned from the file and is checked to + be a known prefix (e.g. against line_term.initial_char()). + So we need to pass one extra byte. + */ + if (terminator(m_line_term.ptr() + i - 1, + m_line_term.length() - i + 1)) + return 0; + } + /* + Here we have a good multi-byte sequence or a broken byte sequence, + and the sequence is not equal to "LINES TERMINATED BY". + No needs to check for escape_char, because: + - multi-byte escape characters in "FIELDS ESCAPED BY" are not + supported and are rejected at parse time. + - broken single-byte sequences are not recognized as escapes, + they are considered to be a part of the data and are converted to + question marks. + */ + line_cuted= true; + continue; } - if (chr == escape_char) + if (buf[0] == escape_char) { - line_cuted=1; + line_cuted= true; if (GET == my_b_EOF) - return 1; + return 1; continue; } - if (chr == line_term_char && terminator(line_term_ptr,line_term_length)) + if (terminator(buf[0], m_line_term)) return 0; - line_cuted=1; + line_cuted= true; } } bool READ_INFO::find_start_of_fields() { - int chr; - try_again: - do - { - if ((chr=GET) == my_b_EOF) - { - found_end_of_line=eof=1; - return 1; - } - } while ((char) chr != line_start_ptr[0]); - for (const char *ptr=line_start_ptr+1 ; ptr != line_start_end ; ptr++) + for (int chr= GET ; chr != my_b_EOF ; chr= GET) { - chr=GET; // Eof will be checked later - if ((char) chr != *ptr) - { // Can't be line_start - PUSH(chr); - while (--ptr != line_start_ptr) - { // Restart with next char - PUSH( *ptr); - } - goto try_again; - } + if (terminator(chr, m_line_start)) + return false; } - return 0; + return (found_end_of_line= eof= true); } @@ -1846,26 +1914,8 @@ int READ_INFO::read_value(int delim, String *val) int chr; String tmp; - for (chr= GET; my_tospace(chr) != delim && chr != my_b_EOF;) + for (chr= GET; my_tospace(chr) != delim && chr != my_b_EOF; chr= GET) { -#ifdef USE_MB - if (my_mbcharlen(read_charset, chr) > 1) - { - DBUG_PRINT("read_xml",("multi byte")); - int i, ml= my_mbcharlen(read_charset, chr); - for (i= 1; i < ml; i++) - { - val->append(chr); - /* - Don't use my_tospace() in the middle of a multi-byte character - TODO: check that the multi-byte sequence is valid. - */ - chr= GET; - if (chr == my_b_EOF) - return chr; - } - } -#endif if(chr == '&') { tmp.length(0); @@ -1885,8 +1935,11 @@ int READ_INFO::read_value(int delim, String *val) } } else + { val->append(chr); - chr= GET; + if (use_mb(read_charset) && read_mbtail(val)) + return my_b_EOF; + } } return my_tospace(chr); } @@ -1955,11 +2008,11 @@ int READ_INFO::read_xml(THD *thd) } // row tag should be in ROWS IDENTIFIED BY '<row>' - stored in line_term - if((tag.length() == line_term_length -2) && - (memcmp(tag.ptr(), line_term_ptr + 1, tag.length()) == 0)) + if((tag.length() == m_line_term.length() - 2) && + (memcmp(tag.ptr(), m_line_term.ptr() + 1, tag.length()) == 0)) { DBUG_PRINT("read_xml", ("start-of-row: %i %s %s", - level,tag.c_ptr_safe(), line_term_ptr)); + level,tag.c_ptr_safe(), m_line_term.ptr())); } if(chr == ' ' || chr == '>') @@ -2026,8 +2079,8 @@ int READ_INFO::read_xml(THD *thd) chr= my_tospace(GET); } - if((tag.length() == line_term_length -2) && - (memcmp(tag.ptr(), line_term_ptr + 1, tag.length()) == 0)) + if((tag.length() == m_line_term.length() - 2) && + (memcmp(tag.ptr(), m_line_term.ptr() + 1, tag.length()) == 0)) { DBUG_PRINT("read_xml", ("found end-of-row %i %s", level, tag.c_ptr_safe())); 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/sql_select.cc b/sql/sql_select.cc index 44e00b099ed..024c8cf0428 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -16729,8 +16729,6 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, cur_group->buff++; // Pointer to field data group_buff++; // Skipp null flag } - /* In GROUP BY 'a' and 'a ' are equal for VARCHAR fields */ - key_part_info->key_part_flag|= HA_END_SPACE_ARE_EQUAL; group_buff+= cur_group->field->pack_length(); } keyinfo->key_length+= key_part_info->length; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 00881adff1d..aa2b47fa4b7 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3524,7 +3524,7 @@ bool get_lookup_value(THD *thd, Item_func *item_func, /* Lookup value is database name */ if (!cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1), (uchar *) item_field->field_name, - strlen(item_field->field_name), 0)) + strlen(item_field->field_name))) { thd->make_lex_string(&lookup_field_vals->db_value, tmp_str->ptr(), tmp_str->length()); @@ -3533,7 +3533,7 @@ bool get_lookup_value(THD *thd, Item_func *item_func, else if (!cs->coll->strnncollsp(cs, (uchar *) field_name2, strlen(field_name2), (uchar *) item_field->field_name, - strlen(item_field->field_name), 0)) + strlen(item_field->field_name))) { thd->make_lex_string(&lookup_field_vals->table_value, tmp_str->ptr(), tmp_str->length()); @@ -3619,10 +3619,10 @@ bool uses_only_table_name_fields(Item *item, TABLE_LIST *table) if (table->table != item_field->field->table || (cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1), (uchar *) item_field->field_name, - strlen(item_field->field_name), 0) && + strlen(item_field->field_name)) && cs->coll->strnncollsp(cs, (uchar *) field_name2, strlen(field_name2), (uchar *) item_field->field_name, - strlen(item_field->field_name), 0))) + strlen(item_field->field_name)))) return 0; } else if (item->type() == Item::REF_ITEM) diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 20772adcb22..40339d599af 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -759,7 +759,7 @@ int sortcmp(const String *s,const String *t, CHARSET_INFO *cs) { return cs->coll->strnncollsp(cs, (uchar *) s->ptr(),s->length(), - (uchar *) t->ptr(),t->length(), 0); + (uchar *) t->ptr(),t->length()); } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 7a61279fc9c..63093620805 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1581,7 +1581,6 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, DBUG_RETURN(0); err_with_lex_cleanup: - // QQ: anything else ? lex_end(&lex); thd->lex= old_lex; thd->spcont= save_spcont; diff --git a/sql/strfunc.cc b/sql/strfunc.cc index b8100e05ce5..bf5fe9d6f00 100644 --- a/sql/strfunc.cc +++ b/sql/strfunc.cc @@ -337,7 +337,7 @@ int find_string_in_array(LEX_STRING * const haystack, LEX_STRING * const needle, const LEX_STRING *pos; for (pos= haystack; pos->str; pos++) if (!cs->coll->strnncollsp(cs, (uchar *) pos->str, pos->length, - (uchar *) needle->str, needle->length, 0)) + (uchar *) needle->str, needle->length)) { return (pos - haystack); } 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) |