summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Petrunia <psergey@askmonty.org>2016-04-07 00:54:39 +0300
committerSergei Petrunia <psergey@askmonty.org>2016-04-07 00:54:39 +0300
commit59e5f5b47e1f12a1426319a905dbc8cc55219c0d (patch)
treeb2095faf431949d31e2ea69200bea27a8cf2f629 /sql
parent306de8a927916db98c67fa338b5a275735f78240 (diff)
parent89b744eb6c2484412f476a53087cea7bf28dc917 (diff)
downloadmariadb-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.cc255
-rw-r--r--sql/derror.h3
-rw-r--r--sql/events.cc2
-rw-r--r--sql/field.cc16
-rw-r--r--sql/handler.cc11
-rw-r--r--sql/item.h2
-rw-r--r--sql/item_cmpfunc.cc2
-rw-r--r--sql/key.cc5
-rw-r--r--sql/log_event.cc2
-rw-r--r--sql/mysqld.cc5
-rw-r--r--sql/opt_subselect.cc1
-rw-r--r--sql/rpl_parallel.cc1
-rw-r--r--sql/share/errmsg-utf8.txt15
-rw-r--r--sql/sql_class.h2
-rw-r--r--sql/sql_connect.cc2
-rw-r--r--sql/sql_load.cc459
-rw-r--r--sql/sql_locale.h2
-rw-r--r--sql/sql_select.cc2
-rw-r--r--sql/sql_show.cc8
-rw-r--r--sql/sql_string.cc2
-rw-r--r--sql/sql_trigger.cc1
-rw-r--r--sql/strfunc.cc2
-rw-r--r--sql/sys_vars.cc3
-rw-r--r--sql/unireg.h19
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)