From 0dbe3dbe7929c209614ab5803084c101b433299c Mon Sep 17 00:00:00 2001 From: Monty Date: Wed, 24 Jan 2018 16:28:54 +0200 Subject: [PATCH 01/13] MDEV-15057 Crash when using an unknown identifier as an SP parameter It crashed because we accessed lex->current_select when it was a NULL, which is the case for SP parameters or local variables. --- mysql-test/r/sp.result | 28 ++++++++++++++++++++++++++++ mysql-test/t/sp.test | 33 +++++++++++++++++++++++++++++++++ sql/item.cc | 34 +++++++++++++++++++++------------- sql/sql_parse.cc | 1 + 4 files changed, 83 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index e1a610e02d6..c83c3f1d03f 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -8184,3 +8184,31 @@ END | CALL p1(); DROP PROCEDURE p1; +# +# MDEV-15057 Crash when using an unknown identifier as an SP parameter +# +CREATE OR REPLACE PROCEDURE p1 (a VARCHAR(10)) SELECT 1; +CALL p1(a); +ERROR 42S22: Unknown column 'a' in 'field list' +drop procedure p1; +CREATE OR REPLACE PROCEDURE p1 (a VARCHAR(10)) SELECT a| +CREATE OR REPLACE PROCEDURE p2 () +BEGIN +DECLARE name VARCHAR(10); +SET name="hello"; +call p1(name); +END| +CREATE OR REPLACE PROCEDURE p3 () +BEGIN +DECLARE name VARCHAR(10); +SET name="hello"; +call p1(name2); +END| +call p2(); +a +hello +call p3(); +ERROR 42S22: Unknown column 'name2' in 'field list' +drop procedure p1; +drop procedure p2; +drop procedure p3; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index b474aa00c18..cfd4ec3b194 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -9658,3 +9658,36 @@ DELIMITER ;| CALL p1(); DROP PROCEDURE p1; +--echo # +--echo # MDEV-15057 Crash when using an unknown identifier as an SP parameter +--echo # + +CREATE OR REPLACE PROCEDURE p1 (a VARCHAR(10)) SELECT 1; +--error ER_BAD_FIELD_ERROR +CALL p1(a); +drop procedure p1; + +DELIMITER |; + +CREATE OR REPLACE PROCEDURE p1 (a VARCHAR(10)) SELECT a| +CREATE OR REPLACE PROCEDURE p2 () +BEGIN + DECLARE name VARCHAR(10); + SET name="hello"; + call p1(name); +END| +CREATE OR REPLACE PROCEDURE p3 () +BEGIN + DECLARE name VARCHAR(10); + SET name="hello"; + call p1(name2); +END| + +DELIMITER ;| + +call p2(); +--error ER_BAD_FIELD_ERROR +call p3(); +drop procedure p1; +drop procedure p2; +drop procedure p3; diff --git a/sql/item.cc b/sql/item.cc index 72e24c8ec70..e0e015196e7 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5132,7 +5132,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) */ Name_resolution_context *last_checked_context= context; Item **ref= (Item **) not_found_item; - SELECT_LEX *current_sel= (SELECT_LEX *) thd->lex->current_select; + SELECT_LEX *current_sel= thd->lex->current_select; Name_resolution_context *outer_context= 0; SELECT_LEX *select= 0; /* Currently derived tables cannot be correlated */ @@ -5465,6 +5465,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) DBUG_ASSERT(fixed == 0); Field *from_field= (Field *)not_found_field; bool outer_fixed= false; + SELECT_LEX *select= thd->lex->current_select; if (!field) // If field is not checked { @@ -5486,13 +5487,14 @@ bool Item_field::fix_fields(THD *thd, Item **reference) not_found_field) { int ret; + /* Look up in current select's item_list to find aliased fields */ - if (thd->lex->current_select->is_item_list_lookup) + if (select && select->is_item_list_lookup) { uint counter; enum_resolution_type resolution; Item** res= find_item_in_list(this, - thd->lex->current_select->item_list, + select->item_list, &counter, REPORT_EXCEPT_NOT_FOUND, &resolution); if (!res) @@ -5524,7 +5526,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) We can not "move" aggregate function in the place where its arguments are not defined. */ - set_max_sum_func_level(thd, thd->lex->current_select); + set_max_sum_func_level(thd, select); set_field(new_field); return 0; } @@ -5544,7 +5546,6 @@ bool Item_field::fix_fields(THD *thd, Item **reference) if (err) return TRUE; - SELECT_LEX *select= thd->lex->current_select; thd->change_item_tree(reference, select->context_analysis_place == IN_GROUP_BY && alias_name_used ? *rf->ref : rf); @@ -5553,11 +5554,17 @@ bool Item_field::fix_fields(THD *thd, Item **reference) We can not "move" aggregate function in the place where its arguments are not defined. */ - set_max_sum_func_level(thd, thd->lex->current_select); + set_max_sum_func_level(thd, select); return FALSE; } } } + + if (!select) + { + my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd->where); + goto error; + } if ((ret= fix_outer_field(thd, &from_field, reference)) < 0) goto error; outer_fixed= TRUE; @@ -5586,9 +5593,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference) if (thd->lex->in_sum_func && thd->lex->in_sum_func->nest_level == - thd->lex->current_select->nest_level) + select->nest_level) set_if_bigger(thd->lex->in_sum_func->max_arg_level, - thd->lex->current_select->nest_level); + select->nest_level); /* if it is not expression from merged VIEW we will set this field. @@ -5654,11 +5661,12 @@ bool Item_field::fix_fields(THD *thd, Item **reference) fix_session_vcol_expr_for_read(thd, field, field->vcol_info); if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !outer_fixed && !thd->lex->in_sum_func && - thd->lex->current_select->cur_pos_in_select_list != UNDEF_POS && - thd->lex->current_select->join) + select && + select->cur_pos_in_select_list != UNDEF_POS && + select->join) { - thd->lex->current_select->join->non_agg_fields.push_back(this, thd->mem_root); - marker= thd->lex->current_select->cur_pos_in_select_list; + select->join->non_agg_fields.push_back(this, thd->mem_root); + marker= select->cur_pos_in_select_list; } mark_non_agg_field: /* @@ -5695,7 +5703,7 @@ mark_non_agg_field: if (outer_fixed) thd->lex->in_sum_func->outer_fields.push_back(this, thd->mem_root); else if (thd->lex->in_sum_func->nest_level != - thd->lex->current_select->nest_level) + select->nest_level) select_lex->set_non_agg_field_used(true); } } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 99c57fc7cfa..7e9159a9c9b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2881,6 +2881,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp) result of previous parsing. */ thd->lex->current_select= NULL; + thd->lex->in_sum_func= 0; // For Item_field::fix_fields() /* We never write CALL statements into binlog: From 7fc25cfbca3cadc53bdcd44572ac2d29d17cff0d Mon Sep 17 00:00:00 2001 From: Monty Date: Wed, 24 Jan 2018 23:33:21 +0200 Subject: [PATCH 02/13] Fix for MDEV-12730 Assertion `count > 0' failed in rpl_parallel_thread_pool:: get_thread, rpl.rpl_parallel failed in buildbot The reason for this is that one thread can call rpl_parallel_resize_pool_if_no_slaves() while another thread calls at the same time rpl_parallel_activate_pool(). If rpl_parallel_active_pool() is called before rpl_parallel_resize_pool_if_no_slaves() has finished, pool->count will be set to 0 even if there exists active slave threads. Added a mutex lock in rpl_parallel_activate_pool() to protect against this scenario, which seams to fix this issue. --- sql/rpl_parallel.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 973b9d899c1..34f9113f7fe 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -1623,10 +1623,19 @@ int rpl_parallel_resize_pool_if_no_slaves(void) } +/** + Resize pool if not active or busy (in which case we may be in + resize to 0 +*/ + int rpl_parallel_activate_pool(rpl_parallel_thread_pool *pool) { - if (!pool->count) + bool resize; + mysql_mutex_lock(&pool->LOCK_rpl_thread_pool); + resize= !pool->count || pool->busy; + mysql_mutex_unlock(&pool->LOCK_rpl_thread_pool); + if (resize) return rpl_parallel_change_thread_count(pool, opt_slave_parallel_threads, 0); return 0; From 859d100d70a9dba222b229bbc0d5a01194e8ed5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 25 Jan 2018 11:28:38 +0200 Subject: [PATCH 03/13] MDEV-15063: InnoDB assertion failure !is_owned() at dict0defrag_bg.cc:327 Probem was that dict_sys mutex was owned when calling function dict_stats_save_defrag_stats() that assumes we do not own dict_sys mutex. --- storage/innobase/dict/dict0defrag_bg.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/storage/innobase/dict/dict0defrag_bg.cc b/storage/innobase/dict/dict0defrag_bg.cc index 976e2ac3877..7b9a0373c48 100644 --- a/storage/innobase/dict/dict0defrag_bg.cc +++ b/storage/innobase/dict/dict0defrag_bg.cc @@ -240,6 +240,7 @@ dict_stats_process_entry_from_defrag_pool() return; } + mutex_exit(&dict_sys->mutex); dict_stats_save_defrag_stats(index); dict_table_close(table, FALSE, FALSE); } From 9891ee5a2aadd2672d8d7f6b217e852344ff86eb Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 12 Jan 2018 18:25:02 +0000 Subject: [PATCH 04/13] Fix and reenable Windows compiler warning C4800 (size_t conversion). --- cmake/os/Windows.cmake | 4 +-- libmariadb | 2 +- mysys/file_logger.c | 4 +-- pcre/pcregrep.c | 4 +-- pcre/pcretest.c | 4 +-- plugin/auth_examples/qa_auth_client.c | 2 +- plugin/auth_examples/qa_auth_interface.c | 2 +- plugin/auth_examples/test_plugin.c | 2 +- plugin/fulltext/plugin_example.c | 2 +- plugin/server_audit/server_audit.c | 30 +++++++++---------- plugin/server_audit/test_audit_v4.c | 6 ++-- .../simple_password_check.c | 2 +- sql/sql_bootstrap.cc | 6 ++-- strings/ctype-bin.c | 8 ++--- strings/ctype-mb.c | 4 +-- strings/ctype-simple.c | 10 +++---- strings/ctype-tis620.c | 10 +++---- strings/ctype-uca.c | 8 ++--- strings/ctype-ucs2.c | 4 +-- strings/ctype.c | 4 +-- strings/my_vsnprintf.c | 6 ++-- vio/viopipe.c | 4 +-- vio/viosocket.c | 4 +-- vio/viossl.c | 12 ++++---- 24 files changed, 72 insertions(+), 72 deletions(-) diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake index 4fd01e5914e..b089a7f59f0 100644 --- a/cmake/os/Windows.cmake +++ b/cmake/os/Windows.cmake @@ -139,8 +139,8 @@ IF(MSVC) ENDIF() #TODO: update the code and remove the disabled warnings - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4800 /wd4805 /wd4996 /we4700 /we4311 /we4477 /we4302 /we4090 /wd4267 ") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4800 /wd4805 /wd4996 /wd4291 /wd4577 /we4099 /we4700 /we4311 /we4477 /we4302 /we4090 /wd4267") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4805 /wd4996 /we4700 /we4311 /we4477 /we4302 /we4090") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4805 /wd4996 /wd4291 /wd4577 /we4099 /we4700 /we4311 /we4477 /we4302 /we4090 /wd4267") IF(MYSQL_MAINTAINER_MODE MATCHES "ERR") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") diff --git a/libmariadb b/libmariadb index f3944bbd36a..c038615c8a6 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit f3944bbd36af729b2f13313587018679c57de67d +Subproject commit c038615c8a6ad584893302b4852a719979afd2e5 diff --git a/mysys/file_logger.c b/mysys/file_logger.c index 078286cd7d0..35a077c4391 100644 --- a/mysys/file_logger.c +++ b/mysys/file_logger.c @@ -172,7 +172,7 @@ int logger_vprintf(LOGGER_HANDLE *log, const char* fmt, va_list ap) if (n_bytes >= sizeof(cvtbuf)) n_bytes= sizeof(cvtbuf) - 1; - result= my_write(log->file, (uchar *) cvtbuf, n_bytes, MYF(0)); + result= (int)my_write(log->file, (uchar *) cvtbuf, n_bytes, MYF(0)); exit: flogger_mutex_unlock(&log->lock); @@ -196,7 +196,7 @@ int logger_write(LOGGER_HANDLE *log, const char *buffer, size_t size) goto exit; /* Log rotation needed but failed */ } - result= my_write(log->file, (uchar *) buffer, size, MYF(0)); + result= (int)my_write(log->file, (uchar *) buffer, size, MYF(0)); exit: flogger_mutex_unlock(&log->lock); diff --git a/pcre/pcregrep.c b/pcre/pcregrep.c index 317f7454e13..a58ff823509 100644 --- a/pcre/pcregrep.c +++ b/pcre/pcregrep.c @@ -951,7 +951,7 @@ Returns: TRUE if the path is not excluded static BOOL test_incexc(char *path, patstr *ip, patstr *ep) { -int plen = strlen(path); +int plen = (int)strlen(path); for (; ep != NULL; ep = ep->next) { @@ -2502,7 +2502,7 @@ compile_pattern(patstr *p, int options, int popts, int fromfile, char buffer[PATBUFSIZE]; const char *error; char *ps = p->string; -int patlen = strlen(ps); +int patlen = (int)strlen(ps); int errptr; if (p->compiled != NULL) return TRUE; diff --git a/pcre/pcretest.c b/pcre/pcretest.c index f1303037281..a0e65ed9808 100644 --- a/pcre/pcretest.c +++ b/pcre/pcretest.c @@ -1904,7 +1904,7 @@ for (;;) { if (f == stdin) printf("%s", prompt); - if (fgets((char *)here, rlen, f) == NULL) + if (fgets((char *)here, (int)rlen, f) == NULL) return (here == start)? NULL : start; } @@ -2025,7 +2025,7 @@ pcre_uint32 c = 0; int yield = 0; if (length < 0) - length = strlen((char *)p); + length = (int)strlen((char *)p); while (length-- > 0) { diff --git a/plugin/auth_examples/qa_auth_client.c b/plugin/auth_examples/qa_auth_client.c index a7ee2f83a39..2153ee71504 100644 --- a/plugin/auth_examples/qa_auth_client.c +++ b/plugin/auth_examples/qa_auth_client.c @@ -90,7 +90,7 @@ static int test_plugin_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) return CR_ERROR; /* send the reply to the server */ res= vio->write_packet(vio, (const unsigned char *) reply, - strlen(reply) + 1); + (int)strlen(reply) + 1); if (res) return CR_ERROR; diff --git a/plugin/auth_examples/qa_auth_interface.c b/plugin/auth_examples/qa_auth_interface.c index c9bc6c5aae4..5002330fb80 100644 --- a/plugin/auth_examples/qa_auth_interface.c +++ b/plugin/auth_examples/qa_auth_interface.c @@ -226,7 +226,7 @@ static int test_plugin_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) return CR_ERROR; /* send the reply to the server */ res= vio->write_packet(vio, (const unsigned char *) reply, - strlen(reply) + 1); + (int)strlen(reply) + 1); if (res) return CR_ERROR; diff --git a/plugin/auth_examples/test_plugin.c b/plugin/auth_examples/test_plugin.c index 2b20a8cb56c..8cc17894be4 100644 --- a/plugin/auth_examples/test_plugin.c +++ b/plugin/auth_examples/test_plugin.c @@ -205,7 +205,7 @@ static int test_plugin_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) return CR_ERROR; /* send the reply to the server */ res= vio->write_packet(vio, (const unsigned char *) reply, - strlen(reply) + 1); + (int)strlen(reply) + 1); if (res) return CR_ERROR; diff --git a/plugin/fulltext/plugin_example.c b/plugin/fulltext/plugin_example.c index 778918cb439..72d78db50f1 100644 --- a/plugin/fulltext/plugin_example.c +++ b/plugin/fulltext/plugin_example.c @@ -150,7 +150,7 @@ static void add_word(MYSQL_FTPARSER_PARAM *param, const char *word, size_t len) MYSQL_FTPARSER_BOOLEAN_INFO bool_info= { FT_TOKEN_WORD, 0, 0, 0, 0, ' ', 0 }; - param->mysql_add_word(param, word, len, &bool_info); + param->mysql_add_word(param, word, (int)len, &bool_info); } /* diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index b75f6b9a863..e2097b58a17 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -300,7 +300,7 @@ static size_t big_buffer_alloced= 0; static unsigned int query_log_limit= 0; static char servhost[256]; -static size_t servhost_len; +static uint servhost_len; static char *syslog_ident; static char syslog_ident_buffer[128]= "mysql-server_auditing"; @@ -622,7 +622,7 @@ static void remove_blanks(char *user) struct user_name { - int name_len; + size_t name_len; char *name; }; @@ -657,7 +657,7 @@ static int cmp_users(const void *ia, const void *ib) { const struct user_name *a= (const struct user_name *) ia; const struct user_name *b= (const struct user_name *) ib; - int dl= a->name_len - b->name_len; + int dl= (int)(a->name_len - b->name_len); if (dl != 0) return dl; @@ -665,7 +665,7 @@ static int cmp_users(const void *ia, const void *ib) } -static char *coll_search(struct user_coll *c, const char *n, int len) +static char *coll_search(struct user_coll *c, const char *n, size_t len) { struct user_name un; struct user_name *found; @@ -677,7 +677,7 @@ static char *coll_search(struct user_coll *c, const char *n, int len) } -static int coll_insert(struct user_coll *c, char *n, int len) +static int coll_insert(struct user_coll *c, char *n, size_t len) { if (c->n_users >= c->n_alloced) { @@ -917,7 +917,7 @@ static void get_str_n(char *dest, int *dest_len, size_t dest_size, memcpy(dest, src, src_len); dest[src_len]= 0; - *dest_len= src_len; + *dest_len= (int)src_len; } @@ -1232,7 +1232,7 @@ static void change_connection(struct connection_info *cn, event->ip, event->ip_length); } -static int write_log(const char *message, int len) +static int write_log(const char *message, size_t len) { if (output_type == OUTPUT_FILE) { @@ -1246,7 +1246,7 @@ static int write_log(const char *message, int len) { syslog(syslog_facility_codes[syslog_facility] | syslog_priority_codes[syslog_priority], - "%s %.*s", syslog_info, len, message); + "%s %.*s", syslog_info, (int)len, message); } return 0; } @@ -1739,9 +1739,9 @@ static int log_table(const struct connection_info *cn, (void) time(&ctime); csize= log_header(message, sizeof(message)-1, &ctime, servhost, servhost_len, - event->user, SAFE_STRLEN(event->user), - event->host, SAFE_STRLEN(event->host), - event->ip, SAFE_STRLEN(event->ip), + event->user, (unsigned int)SAFE_STRLEN(event->user), + event->host, (unsigned int)SAFE_STRLEN(event->host), + event->ip, (unsigned int)SAFE_STRLEN(event->ip), event->thread_id, cn->query_id, type); csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize, ",%.*s,%.*s,",event->database_length, event->database, @@ -1761,9 +1761,9 @@ static int log_rename(const struct connection_info *cn, (void) time(&ctime); csize= log_header(message, sizeof(message)-1, &ctime, servhost, servhost_len, - event->user, SAFE_STRLEN(event->user), - event->host, SAFE_STRLEN(event->host), - event->ip, SAFE_STRLEN(event->ip), + event->user, (unsigned int)SAFE_STRLEN(event->user), + event->host, (unsigned int)SAFE_STRLEN(event->host), + event->ip, (unsigned int)SAFE_STRLEN(event->ip), event->thread_id, cn->query_id, "RENAME"); csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize, ",%.*s,%.*s|%.*s.%.*s,",event->database_length, event->database, @@ -2344,7 +2344,7 @@ static int server_audit_init(void *p __attribute__((unused))) if (gethostname(servhost, sizeof(servhost))) strcpy(servhost, "unknown"); - servhost_len= strlen(servhost); + servhost_len= (uint)strlen(servhost); logger_init_mutexes(); #if defined(HAVE_PSI_INTERFACE) && !defined(FLOGGER_NO_PSI) diff --git a/plugin/server_audit/test_audit_v4.c b/plugin/server_audit/test_audit_v4.c index ae7527f8449..85d45e35808 100644 --- a/plugin/server_audit/test_audit_v4.c +++ b/plugin/server_audit/test_audit_v4.c @@ -56,11 +56,11 @@ static int auditing_v4(MYSQL_THD thd, mysql_event_class_t class, const void *ev) ev_302.general_error_code= event->general_error_code; ev_302.general_thread_id= event->general_thread_id; ev_302.general_user= event->general_user.str; - ev_302.general_user_length= event->general_user.length; + ev_302.general_user_length= (unsigned int)event->general_user.length; ev_302.general_command= event->general_command.str; - ev_302.general_command_length= event->general_command.length; + ev_302.general_command_length= (unsigned int)event->general_command.length; ev_302.general_query= event->general_query.str; - ev_302.general_query_length= event->general_query.length; + ev_302.general_query_length= (unsigned int)event->general_query.length; ev_302.general_charset= event->general_charset; ev_302.general_time= event->general_time; ev_302.general_rows= event->general_rows; diff --git a/plugin/simple_password_check/simple_password_check.c b/plugin/simple_password_check/simple_password_check.c index 8b460c5ed9d..977a7487b78 100644 --- a/plugin/simple_password_check/simple_password_check.c +++ b/plugin/simple_password_check/simple_password_check.c @@ -25,7 +25,7 @@ static unsigned min_length, min_digits, min_letters, min_others; static int validate(MYSQL_LEX_STRING *username, MYSQL_LEX_STRING *password) { - unsigned digits=0 , uppers=0 , lowers=0, others=0, length= password->length; + unsigned digits=0 , uppers=0 , lowers=0, others=0, length= (unsigned)password->length; const char *ptr= password->str, *end= ptr + length; if (strncmp(password->str, username->str, length) == 0) diff --git a/sql/sql_bootstrap.cc b/sql/sql_bootstrap.cc index 4ef9885b34d..9733831b41f 100644 --- a/sql/sql_bootstrap.cc +++ b/sql/sql_bootstrap.cc @@ -82,14 +82,14 @@ int read_bootstrap_query(char *query, int *query_length, */ if (query_len + len + 1 >= MAX_BOOTSTRAP_QUERY_SIZE) { - int new_len= MAX_BOOTSTRAP_QUERY_SIZE - query_len - 1; + size_t new_len= MAX_BOOTSTRAP_QUERY_SIZE - query_len - 1; if ((new_len > 0) && (query_len < MAX_BOOTSTRAP_QUERY_SIZE)) { memcpy(query + query_len, line, new_len); query_len+= new_len; } query[query_len]= '\0'; - *query_length= query_len; + *query_length= (int)query_len; return READ_BOOTSTRAP_QUERY_SIZE; } @@ -111,7 +111,7 @@ int read_bootstrap_query(char *query, int *query_length, Return the query found. */ query[query_len]= '\0'; - *query_length= query_len; + *query_length= (int)query_len; return READ_BOOTSTRAP_SUCCESS; } } diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index 0bbbd282530..612fdbab38c 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -402,7 +402,7 @@ my_strnxfrm_8bit_bin(CHARSET_INFO *cs, if (dst != src) memcpy(dst, src, srclen); return my_strxfrm_pad_desc_and_reverse(cs, dst, dst + srclen, dst + dstlen, - nweights - srclen, flags, 0); + (uint)(nweights - srclen), flags, 0); } @@ -416,7 +416,7 @@ my_strnxfrm_8bit_nopad_bin(CHARSET_INFO *cs, if (dst != src) memcpy(dst, src, srclen); return my_strxfrm_pad_desc_and_reverse_nopad(cs, dst, dst + srclen, - dst + dstlen, nweights - srclen, + dst + dstlen,(uint)(nweights - srclen), flags, 0); } @@ -464,13 +464,13 @@ skip: if (nmatch > 0) { match[0].beg= 0; - match[0].end= (size_t) (str- (const uchar*)b-1); + match[0].end= (uint) (str- (const uchar*)b-1); match[0].mb_len= match[0].end; if (nmatch > 1) { match[1].beg= match[0].end; - match[1].end= match[0].end+s_length; + match[1].end= (uint)(match[0].end+s_length); match[1].mb_len= match[1].end-match[1].beg; } } diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c index bfd533e6f98..19caa22edb4 100644 --- a/strings/ctype-mb.c +++ b/strings/ctype-mb.c @@ -528,12 +528,12 @@ uint my_instr_mb(CHARSET_INFO *cs, if (nmatch) { match[0].beg= 0; - match[0].end= (size_t) (b-b0); + match[0].end= (uint) (b-b0); match[0].mb_len= res; if (nmatch > 1) { match[1].beg= match[0].end; - match[1].end= match[0].end+s_length; + match[1].end= (uint)(match[0].end+s_length); match[1].mb_len= 0; /* Not computed */ } } diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index fc5218caba1..d6e5f02d463 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -78,8 +78,8 @@ size_t my_strnxfrm_simple_internal(CHARSET_INFO * cs, const uchar *map= cs->sort_order; uchar *d0= dst; uint frmlen; - if ((frmlen= MY_MIN(dstlen, *nweights)) > srclen) - frmlen= srclen; + if ((frmlen= (uint)MY_MIN(dstlen, *nweights)) > srclen) + frmlen= (uint)srclen; if (dst != src) { const uchar *end; @@ -321,7 +321,7 @@ size_t my_snprintf_8bit(CHARSET_INFO *cs __attribute__((unused)), const char* fmt, ...) { va_list args; - int result; + size_t result; va_start(args,fmt); result= my_vsnprintf(to, n, fmt, args); va_end(args); @@ -1226,13 +1226,13 @@ skip: if (nmatch > 0) { match[0].beg= 0; - match[0].end= (size_t) (str- (const uchar*)b-1); + match[0].end= (uint) (str- (const uchar*)b-1); match[0].mb_len= match[0].end; if (nmatch > 1) { match[1].beg= match[0].end; - match[1].end= match[0].end+s_length; + match[1].end= (uint)(match[0].end+s_length); match[1].mb_len= match[1].end-match[1].beg; } } diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c index 5e24c84056c..bfd8b0db1d5 100644 --- a/strings/ctype-tis620.c +++ b/strings/ctype-tis620.c @@ -449,7 +449,7 @@ static const uchar sort_order_tis620[]= static size_t thai2sortable(uchar *tstr, size_t len) { uchar *p; - int tlen; + size_t tlen; uchar l2bias; tlen= len; @@ -609,10 +609,10 @@ my_strnxfrm_tis620(CHARSET_INFO *cs, set_if_smaller(dstlen, nweights); set_if_smaller(len, dstlen); len= my_strxfrm_pad_desc_and_reverse(cs, dst, dst + len, dst + dstlen, - dstlen - len, flags, 0); + (uint)(dstlen - len), flags, 0); if ((flags & MY_STRXFRM_PAD_TO_MAXLEN) && len < dstlen0) { - uint fill_length= dstlen0 - len; + size_t fill_length= dstlen0 - len; cs->cset->fill(cs, (char*) dst + len, fill_length, cs->pad_char); len= dstlen0; } @@ -632,10 +632,10 @@ my_strnxfrm_tis620_nopad(CHARSET_INFO *cs, set_if_smaller(dstlen, nweights); set_if_smaller(len, dstlen); len= my_strxfrm_pad_desc_and_reverse_nopad(cs, dst, dst + len, dst + dstlen, - dstlen - len, flags, 0); + (uint)(dstlen - len), flags, 0); if ((flags & MY_STRXFRM_PAD_TO_MAXLEN) && len < dstlen0) { - uint fill_length= dstlen0 - len; + size_t fill_length= dstlen0 - len; memset(dst + len, 0x00, fill_length); len= dstlen0; } diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c index e3ed531df93..f75b5c7c7a4 100644 --- a/strings/ctype-uca.c +++ b/strings/ctype-uca.c @@ -31260,7 +31260,7 @@ static my_bool my_uca_alloc_contractions(MY_CONTRACTIONS *contractions, MY_CHARSET_LOADER *loader, size_t n) { - uint size= n * sizeof(MY_CONTRACTION); + size_t size= n * sizeof(MY_CONTRACTION); if (!(contractions->item= (loader->once_alloc)(size)) || !(contractions->flags= (char *) (loader->once_alloc)(MY_UCA_CNT_FLAG_SIZE))) return 1; @@ -34005,7 +34005,7 @@ apply_one_rule(MY_CHARSET_LOADER *loader, { MY_CONTRACTIONS *contractions= &dst->contractions; to= my_uca_init_one_contraction(contractions, - r->curr, nshift, r->with_context); + r->curr, (uint)nshift, r->with_context); /* Store weights of the "reset to" character */ dst->contractions.nitems--; /* Temporarily hide - it's incomplete */ rc= my_char_weight_put(dst, @@ -34202,9 +34202,9 @@ init_weight_level(MY_CHARSET_LOADER *loader, MY_COLL_RULES *rules, ncontractions++; } - ncontractions += src->contractions.nitems; + ncontractions += (int)src->contractions.nitems; - if ((my_uca_generate_pages(loader, dst, src, npages))) + if ((my_uca_generate_pages(loader, dst, src, (uint)npages))) return TRUE; if (ncontractions) diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index cba44afc926..80bb6745b19 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -1078,7 +1078,7 @@ my_fill_mb2(CHARSET_INFO *cs, char *s, size_t slen, int fill) } -static int +static size_t my_vsnprintf_mb2(char *dst, size_t n, const char* fmt, va_list ap) { char *start=dst, *end= dst + n - 1; @@ -2327,7 +2327,7 @@ my_charlen_utf32(CHARSET_INFO *cs __attribute__((unused)), /* Defines my_well_formed_char_length_utf32 */ -static int +static size_t my_vsnprintf_utf32(char *dst, size_t n, const char* fmt, va_list ap) { char *start= dst, *end= dst + n; diff --git a/strings/ctype.c b/strings/ctype.c index 0aed6c8bf52..64ebd51676f 100644 --- a/strings/ctype.c +++ b/strings/ctype.c @@ -904,11 +904,11 @@ my_string_metadata_get(MY_STRING_METADATA *metadata, if (cs->mbmaxlen == 1 && !(cs->state & MY_CS_NONASCII)) { metadata->char_length= length; - metadata->repertoire= my_string_repertoire_8bit(cs, str, length); + metadata->repertoire= my_string_repertoire_8bit(cs, str, (ulong)length); } else { - my_string_metadata_get_mb(metadata, cs, str, length); + my_string_metadata_get_mb(metadata, cs, str, (ulong)length); } } diff --git a/strings/my_vsnprintf.c b/strings/my_vsnprintf.c index 34ec811adac..c6d9e8530dd 100644 --- a/strings/my_vsnprintf.c +++ b/strings/my_vsnprintf.c @@ -92,10 +92,10 @@ static const char *get_length(const char *fmt, size_t *length, uint *pre_zero) */ static const char *get_length_arg(const char *fmt, ARGS_INFO *args_arr, - uint *arg_count, size_t *length, uint *flags) + size_t *arg_count, size_t *length, uint *flags) { fmt= get_length(fmt+1, length, flags); - *arg_count= MY_MAX(*arg_count, (uint) *length); + *arg_count= MY_MAX(*arg_count, *length); (*length)--; DBUG_ASSERT(*fmt == '$' && *length < MAX_ARGS); args_arr[*length].arg_type= 'd'; @@ -330,7 +330,7 @@ static char *process_args(CHARSET_INFO *cs, char *to, char *end, { ARGS_INFO args_arr[MAX_ARGS]; PRINT_INFO print_arr[MAX_PRINT_INFO]; - uint idx= 0, arg_count= arg_index; + size_t idx= 0, arg_count= arg_index; start: /* Here we are at the beginning of positional argument, right after $ */ diff --git a/vio/viopipe.c b/vio/viopipe.c index f9af50bc3c9..d3447a95c6e 100644 --- a/vio/viopipe.c +++ b/vio/viopipe.c @@ -78,7 +78,7 @@ size_t vio_read_pipe(Vio *vio, uchar *buf, size_t count) disable_iocp_notification(&vio->overlapped); /* Attempt to read from the pipe (overlapped I/O). */ - if (ReadFile(vio->hPipe, buf, count, &transferred, &vio->overlapped)) + if (ReadFile(vio->hPipe, buf, (DWORD)count, &transferred, &vio->overlapped)) { /* The operation completed immediately. */ ret= transferred; @@ -101,7 +101,7 @@ size_t vio_write_pipe(Vio *vio, const uchar *buf, size_t count) disable_iocp_notification(&vio->overlapped); /* Attempt to write to the pipe (overlapped I/O). */ - if (WriteFile(vio->hPipe, buf, count, &transferred, &vio->overlapped)) + if (WriteFile(vio->hPipe, buf, (DWORD)count, &transferred, &vio->overlapped)) { /* The operation completed immediately. */ ret= transferred; diff --git a/vio/viosocket.c b/vio/viosocket.c index cb353c1ce75..6d76d99eb99 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -1296,7 +1296,7 @@ int vio_getnameinfo(const struct sockaddr *sa, } return getnameinfo(sa, sa_length, - hostname, hostname_size, - port, port_size, + hostname, (uint)hostname_size, + port, (uint)port_size, flags); } diff --git a/vio/viossl.c b/vio/viossl.c index e7cc85ea539..000a526a892 100644 --- a/vio/viossl.c +++ b/vio/viossl.c @@ -141,10 +141,10 @@ size_t vio_ssl_read(Vio *vio, uchar *buf, size_t size) vio->ssl_arg)); if (vio->async_context && vio->async_context->active) - ret= my_ssl_read_async(vio->async_context, (SSL *)vio->ssl_arg, buf, size); + ret= my_ssl_read_async(vio->async_context, (SSL *)vio->ssl_arg, buf, (int)size); else { - while ((ret= SSL_read(ssl, buf, size)) < 0) + while ((ret= SSL_read(ssl, buf, (int)size)) < 0) { enum enum_vio_io_event event; @@ -174,10 +174,10 @@ size_t vio_ssl_write(Vio *vio, const uchar *buf, size_t size) if (vio->async_context && vio->async_context->active) ret= my_ssl_write_async(vio->async_context, (SSL *)vio->ssl_arg, buf, - size); + (int)size); else { - while ((ret= SSL_write(ssl, buf, size)) < 0) + while ((ret= SSL_write(ssl, buf, (int)size)) < 0) { enum enum_vio_io_event event; @@ -200,7 +200,7 @@ size_t vio_ssl_write(Vio *vio, const uchar *buf, size_t size) static long yassl_recv(void *ptr, void *buf, size_t len, int flag __attribute__((unused))) { - return vio_read(ptr, buf, len); + return (long)vio_read(ptr, buf, len); } @@ -208,7 +208,7 @@ static long yassl_recv(void *ptr, void *buf, size_t len, static long yassl_send(void *ptr, const void *buf, size_t len, int flag __attribute__((unused))) { - return vio_write(ptr, buf, len); + return (long)vio_write(ptr, buf, len); } #endif From db28f0f8da5c5847366e6caeec4bf3e81781d94f Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sun, 14 Jan 2018 12:47:16 +0100 Subject: [PATCH 05/13] update C/C --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index c038615c8a6..cfafbb6babf 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit c038615c8a6ad584893302b4852a719979afd2e5 +Subproject commit cfafbb6babf276a4f78db626d192c6d844a9b4d1 From 477a1bc42b318e93baa3de5dbbd20c90aeaddc28 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 15 Jan 2018 18:59:27 +0000 Subject: [PATCH 06/13] Windows : fix compile warnings C4267, on 32bit first --- cmake/os/Windows.cmake | 7 +++++-- sql/create_options.cc | 3 ++- sql/log_event.cc | 3 ++- sql/sql_acl.cc | 3 ++- storage/connect/odbconn.cpp | 4 ++-- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake index b089a7f59f0..02c2d86617d 100644 --- a/cmake/os/Windows.cmake +++ b/cmake/os/Windows.cmake @@ -140,8 +140,11 @@ IF(MSVC) #TODO: update the code and remove the disabled warnings SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4805 /wd4996 /we4700 /we4311 /we4477 /we4302 /we4090") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4805 /wd4996 /wd4291 /wd4577 /we4099 /we4700 /we4311 /we4477 /we4302 /we4090 /wd4267") - + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4805 /wd4291 /wd4996 /we4099 /we4700 /we4311 /we4477 /we4302 /we4090") + IF(CMAKE_SIZEOF_VOID_P EQUAL 8) + # Temporarily disable size_t warnings, due to their amount + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267") + ENDIF() IF(MYSQL_MAINTAINER_MODE MATCHES "ERR") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX") diff --git a/sql/create_options.cc b/sql/create_options.cc index 96893aa172e..53258dac3fc 100644 --- a/sql/create_options.cc +++ b/sql/create_options.cc @@ -613,7 +613,8 @@ uchar *engine_option_value::frm_image(uchar *buff) { if (value.str) { - *buff++= name.length; + DBUG_ASSERT(name.length <= 0xff); + *buff++= (uchar)name.length; memcpy(buff, name.str, name.length); buff+= name.length; int2store(buff, value.length | (quoted_value ? FRM_QUOTED_VALUE : 0)); diff --git a/sql/log_event.cc b/sql/log_event.cc index d80f45dffc1..4120342c2c5 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -11791,7 +11791,8 @@ int Table_map_log_event::rewrite_db(const char* new_db, size_t new_len, cnt += header_len; // Write new db name length and new name - *ptr++ = new_len; + DBUG_ASSERT(new_len < 0xff); + *ptr++ = (char)new_len; memcpy(ptr, new_db, new_len + 1); ptr += new_len + 1; cnt += m_dblen + 2; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 1a2c7fc302f..029de16cfbb 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3007,7 +3007,8 @@ exit: (entry= (acl_entry*) malloc(sizeof(acl_entry)+key_length))) { entry->access=(db_access & host_access); - entry->length=key_length; + DBUG_ASSERT(key_length < 0xffff); + entry->length=(uint16)key_length; memcpy((uchar*) entry->key,key,key_length); acl_cache->add(entry); } diff --git a/storage/connect/odbconn.cpp b/storage/connect/odbconn.cpp index 3b0cb562672..45662779b81 100644 --- a/storage/connect/odbconn.cpp +++ b/storage/connect/odbconn.cpp @@ -2250,10 +2250,10 @@ public: return (SQLCHAR *) (m_part[i].length ? m_part[i].str : NULL); } // end of ptr - size_t length(uint i) + SQLSMALLINT length(uint i) { DBUG_ASSERT(i < max_parts); - return m_part[i].length; + return (SQLSMALLINT)m_part[i].length; } // end of length }; // end of class SQLQualifiedName From 067b90c7a9fcee603734324e08cc248b95e003f1 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 25 Jan 2018 14:50:11 +0000 Subject: [PATCH 07/13] Fix MinSizeRel build on Windows. do not include test suite in release zip anymore. --- .../build_configurations/mysql_release.cmake | 6 +++-- cmake/os/Windows.cmake | 11 ++++++++-- mysql-test/lib/My/SafeProcess/CMakeLists.txt | 22 +++++++++++-------- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/cmake/build_configurations/mysql_release.cmake b/cmake/build_configurations/mysql_release.cmake index fcac8dde6e9..8221029a2d6 100644 --- a/cmake/build_configurations/mysql_release.cmake +++ b/cmake/build_configurations/mysql_release.cmake @@ -62,7 +62,7 @@ IF(FEATURE_SET) SET(WITH_NONE ON) ENDIF() - IF(num GREATER FEATURE_SET_xsmall) + IF(num GREATER FEATURE_SET_xsmall AND NOT WIN32) SET(WITH_EMBEDDED_SERVER ON CACHE BOOL "") ENDIF() IF(num GREATER FEATURE_SET_small) @@ -88,7 +88,9 @@ ENDIF() OPTION(ENABLED_LOCAL_INFILE "" ON) SET(WITH_INNODB_SNAPPY OFF CACHE STRING "") IF(WIN32) - SET(WITH_LIBARCHIVE STATIC CACHE STRING "") + SET(INSTALL_MYSQLTESTDIR "" CACHE STRING "") + SET(INSTALL_SQLBENCHDIR "" CACHE STRING "") + SET(INSTALL_SUPPORTFILESDIR "" CACHE STRING "") ELSEIF(RPM) SET(WITH_SSL system CACHE STRING "") SET(WITH_ZLIB system CACHE STRING "") diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake index 02c2d86617d..48184947da5 100644 --- a/cmake/os/Windows.cmake +++ b/cmake/os/Windows.cmake @@ -86,8 +86,10 @@ IF(MSVC) # Enable debug info also in Release build, # and create PDB to be able to analyze crashes. FOREACH(type EXE SHARED MODULE) - SET(CMAKE_{type}_LINKER_FLAGS_RELEASE + SET(CMAKE_${type}_LINKER_FLAGS_RELEASE "${CMAKE_${type}_LINKER_FLAGS_RELEASE} /debug") + SET(CMAKE_${type}_LINKER_FLAGS_MINSIZEREL + "${CMAKE_${type}_LINKER_FLAGS_MINSIZEREL} /debug") ENDFOREACH() # Force static runtime libraries @@ -108,10 +110,15 @@ IF(MSVC) CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_DEBUG_INIT CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELWITHDEBINFO - CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG_INIT) + CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG_INIT + CMAKE_C_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_MINSIZEREL + ) STRING(REGEX REPLACE "/M[TD][d]?" "${MSVC_CRT_TYPE}" "${flag}" "${${flag}}" ) STRING(REGEX REPLACE "/D[ ]?_DEBUG" "" "${flag}" "${${flag}}") STRING(REPLACE "/Zi" "/Z7" "${flag}" "${${flag}}") + IF(NOT "${${flag}}" MATCHES "/Z7") + STRING(APPEND ${flag} " /Z7") + ENDIF() ENDFOREACH() diff --git a/mysql-test/lib/My/SafeProcess/CMakeLists.txt b/mysql-test/lib/My/SafeProcess/CMakeLists.txt index ff842f3468f..12e3599223e 100644 --- a/mysql-test/lib/My/SafeProcess/CMakeLists.txt +++ b/mysql-test/lib/My/SafeProcess/CMakeLists.txt @@ -13,7 +13,16 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -IF (NOT INSTALL_MYSQLTESTDIR) + + IF (WIN32) + ADD_EXECUTABLE(my_safe_process safe_process_win.cc) + ADD_EXECUTABLE(my_safe_kill safe_kill_win.cc) + TARGET_LINK_LIBRARIES(my_safe_kill dbghelp psapi) +ELSE() + ADD_EXECUTABLE(my_safe_process safe_process.cc) +ENDIF() + +IF(NOT INSTALL_MYSQLTESTDIR) RETURN() ENDIF() @@ -22,14 +31,9 @@ SET(INSTALL_ARGS COMPONENT Test ) +INSTALL(TARGETS my_safe_process ${INSTALL_ARGS}) IF (WIN32) - MYSQL_ADD_EXECUTABLE(my_safe_process safe_process_win.cc ${INSTALL_ARGS}) - MYSQL_ADD_EXECUTABLE(my_safe_kill safe_kill_win.cc ${INSTALL_ARGS}) - TARGET_LINK_LIBRARIES(my_safe_kill dbghelp psapi) -ELSE() - MYSQL_ADD_EXECUTABLE(my_safe_process safe_process.cc ${INSTALL_ARGS}) + INSTALL(TARGETS my_safe_kill ${INSTALL_ARGS}) ENDIF() -INSTALL(FILES Base.pm - DESTINATION "${INSTALL_MYSQLTESTDIR}/lib/My/SafeProcess" COMPONENT Test -) +INSTALL(FILES Base.pm ${INSTALL_ARGS}) From 204739df145077621797cd68cc18ecec609675be Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 26 Jan 2018 15:04:20 +0200 Subject: [PATCH 08/13] Fixed memory overrun in create_postjoin_aggr_table() --- sql/sql_select.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6b1d406bf8a..a98477d2839 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2910,6 +2910,7 @@ JOIN::create_postjoin_aggr_table(JOIN_TAB *tab, List *table_fields, THD_STAGE_INFO(thd, stage_sorting_for_group); if (ordered_index_usage != ordered_index_group_by && + !only_const_tables() && (join_tab + const_tables)->type != JT_CONST && // Don't sort 1 row !implicit_grouping && add_sorting_to_table(join_tab + const_tables, group_list)) @@ -2943,6 +2944,7 @@ JOIN::create_postjoin_aggr_table(JOIN_TAB *tab, List *table_fields, THD_STAGE_INFO(thd, stage_sorting_for_order); if (ordered_index_usage != ordered_index_order_by && + !only_const_tables() && add_sorting_to_table(join_tab + const_tables, order)) goto err; order= NULL; From c09371dce66c48393cb9d1c56f9add23664c772f Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Fri, 26 Jan 2018 23:26:39 +0200 Subject: [PATCH 09/13] MDEV-14721 Big transaction events get lost on semisync master when replicate_events_marked_for_skip=FILTER_ON_MASTER When events of a big transaction are binlogged offsetting over 2GB from the beginning of the log the semisync master's dump thread lost such events. The events were skipped by the Dump thread that found their skipping status erroneously. The current fixes make sure the skipping status is computed correctly. The test verifies them simulating the 2GB offset. --- .../rpl/r/rpl_semi_sync_skip_repl.result | 30 +++++++++ .../suite/rpl/t/rpl_semi_sync_skip_repl.test | 62 +++++++++++++++++++ sql/log_event.cc | 2 + sql/sql_repl.cc | 7 +-- 4 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_semi_sync_skip_repl.result create mode 100644 mysql-test/suite/rpl/t/rpl_semi_sync_skip_repl.test diff --git a/mysql-test/suite/rpl/r/rpl_semi_sync_skip_repl.result b/mysql-test/suite/rpl/r/rpl_semi_sync_skip_repl.result new file mode 100644 index 00000000000..811715d1439 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_semi_sync_skip_repl.result @@ -0,0 +1,30 @@ +include/master-slave.inc +[connection master] +connection master; +call mtr.add_suppression("Timeout waiting for reply of binlog"); +SET @@GLOBAL.rpl_semi_sync_master_enabled = 1; +SET @@GLOBAL.rpl_semi_sync_master_timeout=100; +connection slave; +include/stop_slave.inc +SET @@GLOBAL.replicate_events_marked_for_skip=FILTER_ON_MASTER; +SET @@GLOBAL. rpl_semi_sync_slave_enabled = 1; +include/start_slave.inc +connection master; +CREATE TABLE t1 (a INT) ENGINE=innodb; +SET @@GLOBAL.debug_dbug= "d,dbug_master_binlog_over_2GB"; +SET @@SESSION.skip_replication=1; +INSERT INTO t1 SET a=1; +SET @@SESSION.skip_replication=0; +INSERT INTO t1 SET a=0; +connection slave; +connection master; +SET @@GLOBAL.debug_dbug=""; +SET @@GLOBAL. rpl_semi_sync_master_timeout = 10000; +SET @@GLOBAL. rpl_semi_sync_master_enabled = 0; +connection master; +DROP TABLE t1; +connection slave; +include/stop_slave.inc +SET @@GLOBAL. rpl_semi_sync_slave_enabled = 0; +SET @@GLOBAL.replicate_events_marked_for_skip = REPLICATE; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_skip_repl.test b/mysql-test/suite/rpl/t/rpl_semi_sync_skip_repl.test new file mode 100644 index 00000000000..2f6da18067c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_skip_repl.test @@ -0,0 +1,62 @@ +# MDEV-14721 Big transaction events get lost on semisync master when +# replicate_events_marked_for_skip=FILTER_ON_MASTER +# +# When events of a big transaction are binlogged offsetting over 2GB from +# the beginning of the log the semisync master's dump thread +# lost such events. +# The test verifies the fixes' correctness simulating the 2GB offset. + +source include/have_semisync.inc; +source include/not_embedded.inc; +source include/have_innodb.inc; +source include/have_debug.inc; +source include/master-slave.inc; + +--connection master +# Suppress warnings that might be generated during the test +call mtr.add_suppression("Timeout waiting for reply of binlog"); + +--let $sav_enabled_master=`SELECT @@GLOBAL.rpl_semi_sync_master_enabled ` +--let $sav_timeout_master=`SELECT @@GLOBAL.rpl_semi_sync_master_timeout ` +SET @@GLOBAL.rpl_semi_sync_master_enabled = 1; +SET @@GLOBAL.rpl_semi_sync_master_timeout=100; + +--connection slave +source include/stop_slave.inc; +--let $sav_skip_marked_slave=`SELECT @@GLOBAL.replicate_events_marked_for_skip ` +SET @@GLOBAL.replicate_events_marked_for_skip=FILTER_ON_MASTER; +--let $sav_enabled_slave=`SELECT @@GLOBAL.rpl_semi_sync_slave_enabled ` +SET @@GLOBAL. rpl_semi_sync_slave_enabled = 1; + +source include/start_slave.inc; + +--connection master +CREATE TABLE t1 (a INT) ENGINE=innodb; + +# Make the following events as if they offset over 2GB from the beginning of binlog +SET @@GLOBAL.debug_dbug= "d,dbug_master_binlog_over_2GB"; +SET @@SESSION.skip_replication=1; +INSERT INTO t1 SET a=1; +SET @@SESSION.skip_replication=0; +INSERT INTO t1 SET a=0; + +--sync_slave_with_master + +# +# Clean up +# +--connection master +SET @@GLOBAL.debug_dbug=""; +--eval SET @@GLOBAL. rpl_semi_sync_master_timeout = $sav_timeout_master +--eval SET @@GLOBAL. rpl_semi_sync_master_enabled = $sav_enabled_master + +--connection master +DROP TABLE t1; + +--sync_slave_with_master +source include/stop_slave.inc; +--eval SET @@GLOBAL. rpl_semi_sync_slave_enabled = $sav_enabled_slave +--eval SET @@GLOBAL.replicate_events_marked_for_skip = $sav_skip_marked_slave + +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/sql/log_event.cc b/sql/log_event.cc index 4120342c2c5..30f1e88b86c 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1711,6 +1711,8 @@ bool Log_event::write_header(ulong event_data_length) */ log_pos= writer->pos() + data_written; + + DBUG_EXECUTE_IF("dbug_master_binlog_over_2GB", log_pos += (1ULL <<31);); } now= get_time(); // Query start time diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 78034badf8c..4ec70bf31da 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1904,11 +1904,8 @@ send_event_to_slave(binlog_send_info *info, Log_event_type event_type, */ if (info->thd->variables.option_bits & OPTION_SKIP_REPLICATION) { - /* - The first byte of the packet is a '\0' to distinguish it from an error - packet. So the actual event starts at offset +1. - */ - uint16 event_flags= uint2korr(&((*packet)[FLAGS_OFFSET+1])); + uint16 event_flags= uint2korr(&((*packet)[FLAGS_OFFSET + ev_offset])); + if (event_flags & LOG_EVENT_SKIP_REPLICATION_F) return NULL; } From 8ff5ddae231d31f0ff721d2fd518f65d96142c21 Mon Sep 17 00:00:00 2001 From: Monty Date: Sat, 27 Jan 2018 14:39:33 +0200 Subject: [PATCH 10/13] Disable rocksdb when building with ASAN I disabled rocksdb in ASAN build as I got a link error when it's included --- BUILD/SETUP.sh | 2 ++ BUILD/compile-pentium64-asan-max | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 3a1a861f2f8..721ed3a4c45 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -308,3 +308,5 @@ gprof_compile_flags="-O2 -pg -g" gprof_link_flags="--disable-shared $static_link" disable_gprof_plugins="--with-zlib-dir=bundled --without-plugin-oqgraph --without-plugin-mroonga" + +disable_asan_plugins="--without-plugin-rocksdb" diff --git a/BUILD/compile-pentium64-asan-max b/BUILD/compile-pentium64-asan-max index cd5a292d17c..666a0d89d8c 100755 --- a/BUILD/compile-pentium64-asan-max +++ b/BUILD/compile-pentium64-asan-max @@ -18,7 +18,7 @@ path=`dirname $0` . "$path/SETUP.sh" extra_flags="$pentium64_cflags $debug_cflags -lasan -O -g -fsanitize=address" -extra_configs="$pentium_configs $debug_configs $valgrind_configs $max_configs" +extra_configs="$pentium_configs $debug_configs $valgrind_configs $max_configs $disable_asan_plugins" export LDFLAGS="-ldl" . "$path/FINISH.sh" From 95f393394442437eea403d91c3c4bd68ec24fdf9 Mon Sep 17 00:00:00 2001 From: Monty Date: Sat, 27 Jan 2018 15:03:30 +0200 Subject: [PATCH 11/13] Fixed compiler warnings Only warnings, should not have caused any bugs in old code --- sql/opt_subselect.cc | 6 +++--- sql/table.cc | 9 +++++++-- storage/maria/ma_create.c | 5 +---- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index e048df6ef11..430481295f6 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2701,8 +2701,8 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, LooseScan detector in best_access_path) */ remaining_tables &= ~new_join_tab->table->map; - table_map dups_producing_tables, prev_dups_producing_tables, - prev_sjm_lookup_tables; + table_map dups_producing_tables, UNINIT_VAR(prev_dups_producing_tables), + UNINIT_VAR(prev_sjm_lookup_tables); if (idx == join->const_tables) dups_producing_tables= 0; @@ -2713,7 +2713,7 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, if ((emb_sj_nest= new_join_tab->emb_sj_nest)) dups_producing_tables |= emb_sj_nest->sj_inner_tables; - Semi_join_strategy_picker **strategy, **prev_strategy; + Semi_join_strategy_picker **strategy, **prev_strategy= 0; if (idx == join->const_tables) { /* First table, initialize pickers */ diff --git a/sql/table.cc b/sql/table.cc index 33f408f958a..3ff13fc9d87 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1174,7 +1174,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, char *keynames, *names, *comment_pos; const uchar *forminfo, *extra2; const uchar *frm_image_end = frm_image + frm_length; - uchar *record, *null_flags, *null_pos, *mysql57_vcol_null_pos; + uchar *record, *null_flags, *null_pos, *UNINIT_VAR(mysql57_vcol_null_pos); const uchar *disk_buff, *strpos; ulong pos, record_offset; ulong rec_buff_length; @@ -2407,6 +2407,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, DBUG_ASSERT(field_nr < share->fields); reg_field= share->field[field_nr]; } + else + { + reg_field= 0; + DBUG_ASSERT(name_length); + } vcol_screen_pos+= FRM_VCOL_NEW_HEADER_SIZE; vcol_info->set_vcol_type((enum_vcol_info_type) type); @@ -7411,7 +7416,7 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) DBUG_ASSERT(vcol_info); DBUG_ASSERT(vcol_info->expr); - bool update, swap_values= 0; + bool update= 0, swap_values= 0; switch (update_mode) { case VCOL_UPDATE_FOR_READ: update= !vcol_info->stored_in_db diff --git a/storage/maria/ma_create.c b/storage/maria/ma_create.c index 94c4c250bef..aec705bd540 100644 --- a/storage/maria/ma_create.c +++ b/storage/maria/ma_create.c @@ -76,7 +76,7 @@ int maria_create(const char *name, enum data_file_type datafile_type, uint internal_table= flags & HA_CREATE_INTERNAL_TABLE; ulong reclength, real_reclength,min_pack_length; char kfilename[FN_REFLEN], klinkname[FN_REFLEN], *klinkname_ptr; - char dfilename[FN_REFLEN], dlinkname[FN_REFLEN], *dlinkname_ptr; + char dfilename[FN_REFLEN], dlinkname[FN_REFLEN], *dlinkname_ptr= 0; ulong pack_reclength; ulonglong tot_length,max_rows, tmp; enum en_fieldtype type; @@ -1197,7 +1197,6 @@ int maria_create(const char *name, enum data_file_type datafile_type, { fn_format(dfilename,name,"", MARIA_NAME_DEXT, MY_UNPACK_FILENAME | MY_APPEND_EXT); - dlinkname_ptr= NullS; create_flag= (flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD; } if ((dfile= @@ -1251,8 +1250,6 @@ err_no_lock: switch (errpos) { case 3: mysql_file_close(dfile, MYF(0)); - /* fall through */ - case 2: if (! (flags & HA_DONT_TOUCH_DATA)) { mysql_file_delete(key_file_dfile, dfilename, MYF(sync_dir)); From ffcedfab46a7b2fad9b309aa1930e14068d968aa Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 28 Jan 2018 15:54:17 +0200 Subject: [PATCH 12/13] Added TRASH_FREED_MEMORY compilation option One can use -DTRASH_FREED_MEMORY to enable TRASH macros. Useful to do when one suspects that there is accesses to freed memory. Extended my_free() to TRASH freed memory --- include/my_valgrind.h | 2 +- mysys/my_malloc.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/my_valgrind.h b/include/my_valgrind.h index dbbc4fad5ab..dd95098cc44 100644 --- a/include/my_valgrind.h +++ b/include/my_valgrind.h @@ -32,7 +32,7 @@ # define MEM_CHECK_DEFINED(a,len) ((void) 0) #endif /* HAVE_VALGRIND_MEMCHECK_H */ -#ifndef DBUG_OFF +#if !defined(DBUG_OFF) || defined(TRASH_FREED_MEMORY) #define TRASH_FILL(A,B,C) do { const size_t trash_tmp= (B); memset(A, C, trash_tmp); MEM_UNDEFINED(A, trash_tmp); } while (0) #else #define TRASH_FILL(A,B,C) do{ const size_t trash_tmp __attribute__((unused)) = (B) ; MEM_CHECK_ADDRESSABLE(A,trash_tmp);MEM_UNDEFINED(A,trash_tmp);} while (0) diff --git a/mysys/my_malloc.c b/mysys/my_malloc.c index 719c13a040e..2b34c89f5e4 100644 --- a/mysys/my_malloc.c +++ b/mysys/my_malloc.c @@ -214,6 +214,13 @@ void my_free(void *ptr) my_bool old_flags; old_size= MALLOC_SIZE_AND_FLAG(ptr, &old_flags); update_malloc_size(- (longlong) old_size - MALLOC_PREFIX_SIZE, old_flags); +#ifndef SAFEMALLOC + /* + Trash memory if not safemalloc. We don't have to do this if safemalloc + is used as safemalloc will also do trashing + */ + TRASH_FREE(ptr, old_size); +#endif sf_free(MALLOC_FIX_POINTER_FOR_FREE(ptr)); } DBUG_VOID_RETURN; From b12430adc716be51810953920448563c87fe0521 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 29 Jan 2018 12:01:17 +0400 Subject: [PATCH 13/13] MDEV-15107 Add virtual Field::sp_prepare_and_store_item(), make sp_rcontext symmetric for scalar and ROW After MDEV-14212, the Virtual_tmp_table instance that stores a ROW variable elements is accessible from the underlying Field_row (rather than Item_field_row). This patch makes some further changes by moving the code from sp_instr_xxx, sp_rcontext, Item_xxx to Virtual_tmp_table and Field_xxx. The data type specific code (scalar vs ROW) now resides in a new virtual method Field_xxx::sp_prepare_and_store_item(). The the code in sp_rcontext::set_variable() and sp_eval_expr() is now symmetric for scalar and ROW values. The code in sp_rcontext::set_variable_row_field(), sp_rcontext::set_variable_row_field(), sp_rcontext::set_variable_row() is now symmetric for ROW elements (i.e. scalar and ROW elements inside a ROW). Rationale: Prepare the code to implement these tasks soon easier: - MDEV-12252 ROW data type for stored function return values - MDEV-12307 ROW data type for built-in function return values - MDEV-6121 Data type: Array - MDEV-10593 sql_mode=ORACLE: TYPE .. AS OBJECT: basic functionality - ROW with ROW fields (no MDEV yet) Details: 1. Moving the code in sp_eval_expr() responsible to backup/restore thd->count_cuted_fields, thd->abort_on_warning, thd->transaction.stmt.modified_non_trans_table into a new helper class Sp_eval_expr_state, to reuse it easier. Fixing sp_eval_expr() to use this new class. 2. Moving sp_eval_expr() and sp_prepare_func_item() from public functions to methods in THD, so they can be reused in *.cc files easier without a need to include "sp_head.h". Splitting sp_prepare_func_item() into two parts. Adding a new function sp_fix_func_item(), which fixes the underlying items, but does not do check_cols() for them. Reusing sp_fix_func_item() in Field_row::sp_prepare_and_store_item(). 3. Moving the code to find ROW fields by name from Item to Virtual_tmp_table Moving the code searching for ROW fields by their names from Item_field_row::element_index_by_name() to a new method Item_field_row to Virtual_tmp_table::sp_find_field_by_name(). Adding wrapper methods sp_rcontext::find_row_field_by_name() and find_row_field_by_name_or_error(), to search for a ROW variable fields by the variable offset and its field name. Changing Item_splocal_row_field_by_name::fix_fields() to do use sp_rcontext::find_row_field_by_name_or_error(). Removing virtual Item::element_index_by_name(). 4. Splitting sp_rcontext::set_variable() Adding a new virtual method Field::sp_prepare_and_store_item(). Spliting the two branches of the code in sp_rcontext::set_variable() into two virtual implementations of Field::sp_prepare_and_store_item(), (for Field and for Field_row). Moving the former part of sp_rcontext::set_variable() with the loop doing set_null() for all ROW fields into a new method Virtual_tmp_table::set_all_fields_to_null() and using it in Field_row::sp_prepare_and_store_item(). Moving the former part of sp_rcontext::set_variable() with the loop doing set_variable_row_field() into a new method Virtual_tmp_table::set_all_fields_from_item() and using it in Field_row::sp_prepare_and_store_item(). The loop in the new method now uses sp_prepare_and_store_item() instead of set_variable_row_field(), because saving/restoring THD flags is now done on the upper level. No needs to save/restore on every iteration. 5. Fixing sp_eval_expr() to simply do two things: - backup/restore THD flags - call result_field->sp_prepare_and_store_item() So now sp_eval_expr() can be used for both scalar and ROW variables. Reusing it in sp_rcontext::set_variable*(). 6. Moving the loop in sp_rcontext::set_variable_row() into a new method Virtual_tmp_table::sp_set_all_fields_from_item_list(). Changing the loop body to call field->sp_prepare_and_store_item() instead of doing set_variable_row_field(). This removes saving/restoring of the THD flags from every interation. Instead, adding the code to save/restore the flags around the entire loop in set_variable_row(), using Sp_eval_expr_state. So now saving/restoring is done only once for the entire ROW (a slight performance improvement). 7. Removing the code in sp_instr_set::exec_core() that sets a variable to NULL if the value evaluation failed. sp_rcontext::set_variable() now makes sure to reset the variable properly by effectively calling sp_eval_expr(), which calls virtual Field::sp_prepare_and_store_item(). Removing the similar code from sp_instr_set_row_field::exec_core() and sp_instr_set_row_field_by_name::exec_core(). Removing the method sp_rcontext::set_variable_row_field_to_null(), as it's not used any more. 8. Removing the call for sp_prepare_func_item() from sp_rcontext::set_variable_row_field(), as it was duplicate: it was done inside sp_eval_expr(). Now it's done inside virtual Field::sp_prepare_and_store_item(). 9. Moving the code from sp_instr_set_row_field_by_name::exec_core() into sp_rcontext::set_variable_row_field_by_name(), for symmetry with other sp_instr_set*::exec_core()/sp_rcontext::set_variable*() pairs. Now sp_instr_set_row_field_by_name::exec_core() calls sp_rcontext::set_variable_row_field_by_name(). 10. Misc: - Adding a helper private method sp_rcontext::virtual_tmp_table_for_row(), reusing it in a new sp_rcontext methods. - Removing Item_field_row::get_row_field(), as it's not used any more. - Removing the "Item *result_item" from sp_eval_expr(), as it's not needed any more. --- sql/field.cc | 74 +++++++++++++++++++++++++ sql/field.h | 2 + sql/item.cc | 33 ++--------- sql/item.h | 6 -- sql/sp_head.cc | 134 ++++++++++---------------------------------- sql/sp_head.h | 7 --- sql/sp_rcontext.cc | 135 +++++++++++++++------------------------------ sql/sp_rcontext.h | 9 ++- sql/sql_class.h | 47 ++++++++++++++++ sql/sql_select.cc | 64 +++++++++++++++++++++ sql/sql_select.h | 42 ++++++++++++++ 11 files changed, 317 insertions(+), 236 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 7b8ec18cad6..3fd76591117 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1267,6 +1267,45 @@ bool Field::load_data_set_null(THD *thd) } +bool Field::sp_prepare_and_store_item(THD *thd, Item **value) +{ + DBUG_ENTER("Field::sp_prepare_and_store_item"); + DBUG_ASSERT(value); + + Item *expr_item; + + if (!(expr_item= thd->sp_prepare_func_item(value, 1))) + goto error; + + /* + expr_item is now fixed, it's safe to call cmp_type() + */ + if (expr_item->cmp_type() == ROW_RESULT) + { + my_error(ER_OPERAND_COLUMNS, MYF(0), 1); + goto error; + } + + /* Save the value in the field. Convert the value if needed. */ + + expr_item->save_in_field(this, 0); + + if (!thd->is_error()) + DBUG_RETURN(false); + +error: + /* + In case of error during evaluation, leave the result field set to NULL. + Sic: we can't do it in the beginning of the function because the + result field might be needed for its own re-evaluation, e.g. case of + set x = x + 1; + */ + set_null(); + DBUG_ASSERT(thd->is_error()); + DBUG_RETURN(true); +} + + /** Numeric fields base class constructor. */ @@ -2295,6 +2334,41 @@ Field_row::~Field_row() } +bool Field_row::sp_prepare_and_store_item(THD *thd, Item **value) +{ + DBUG_ENTER("Field_row::sp_prepare_and_store_item"); + + if (value[0]->type() == Item::NULL_ITEM) + { + /* + We're in a auto-generated sp_inst_set, to assign + the explicit default NULL value to a ROW variable. + */ + m_table->set_all_fields_to_null(); + DBUG_RETURN(false); + } + + /** + - In case if we're assigning a ROW variable from another ROW variable, + value[0] points to Item_splocal. sp_fix_func_item() will return the + fixed underlying Item_field pointing to Field_row. + - In case if we're assigning from a ROW() value, src and value[0] will + point to the same Item_row. + */ + Item *src; + if (!(src= thd->sp_fix_func_item(value)) || + src->cmp_type() != ROW_RESULT || + src->cols() != m_table->s->fields) + { + my_error(ER_OPERAND_COLUMNS, MYF(0), m_table->s->fields); + m_table->set_all_fields_to_null(); + DBUG_RETURN(true); + } + + DBUG_RETURN(m_table->sp_set_all_fields_from_item(thd, src)); +} + + /**************************************************************************** Functions for the Field_decimal class This is an number stored as a pre-space (or pre-zero) string diff --git a/sql/field.h b/sql/field.h index 0d7d8e42615..287837ee1e7 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1521,6 +1521,7 @@ public: { return NULL; } + virtual bool sp_prepare_and_store_item(THD *thd, Item **value); friend int cre_myisam(char * name, register TABLE *form, uint options, ulonglong auto_increment_value); @@ -3834,6 +3835,7 @@ public: {} ~Field_row(); Virtual_tmp_table **virtual_tmp_table_addr() { return &m_table; } + bool sp_prepare_and_store_item(THD *thd, Item **value); }; diff --git a/sql/item.cc b/sql/item.cc index cc3543fe670..98d66df4682 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1968,14 +1968,11 @@ bool Item_splocal_row_field::set_value(THD *thd, sp_rcontext *ctx, Item **it) bool Item_splocal_row_field_by_name::fix_fields(THD *thd, Item **it) { m_thd= thd; - Item *item, *row= m_thd->spcont->get_item(m_var_idx); - if (row->element_index_by_name(&m_field_idx, m_field_name)) - { - my_error(ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD, MYF(0), - m_name.str, m_field_name.str); + if (thd->spcont->find_row_field_by_name_or_error(&m_field_idx, + m_var_idx, + m_field_name)) return true; - } - item= row->element_index(m_field_idx); + Item *item= thd->spcont->get_item(m_var_idx)->element_index(m_field_idx); set_handler(item->type_handler()); return fix_fields_from_item(thd, it, item); } @@ -7424,26 +7421,6 @@ void Item_field::print(String *str, enum_query_type query_type) } -bool Item_field_row::element_index_by_name(uint *idx, - const LEX_CSTRING &name) const -{ - Field *field; - for (uint i= 0; (field= get_row_field(i)); i++) - { - // Use the same comparison style with sp_context::find_variable() - if (!my_strnncoll(system_charset_info, - (const uchar *) field->field_name.str, - field->field_name.length, - (const uchar *) name.str, name.length)) - { - *idx= i; - return false; - } - } - return true; -} - - void Item_temptable_field::print(String *str, enum_query_type query_type) { /* @@ -9290,7 +9267,7 @@ void Item_trigger_field::set_required_privilege(bool rw) bool Item_trigger_field::set_value(THD *thd, sp_rcontext * /*ctx*/, Item **it) { - Item *item= sp_prepare_func_item(thd, it); + Item *item= thd->sp_prepare_func_item(it); if (!item) return true; diff --git a/sql/item.h b/sql/item.h index 46a65b31b38..f4fff4a0418 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1710,10 +1710,6 @@ public: // Row emulation virtual uint cols() const { return 1; } virtual Item* element_index(uint i) { return this; } - virtual bool element_index_by_name(uint *idx, const LEX_CSTRING &name) const - { - return true; // Error - } virtual Item** addr(uint i) { return 0; } virtual bool check_cols(uint c); bool check_type_traditional_scalar(const char *opname) const; @@ -2943,7 +2939,6 @@ public: const Type_handler *type_handler() const { return &type_handler_row; } uint cols() const { return arg_count; } - bool element_index_by_name(uint *idx, const LEX_CSTRING &name) const; Item* element_index(uint i) { return arg_count ? args[i] : this; } Item** addr(uint i) { return arg_count ? args + i : NULL; } bool check_cols(uint c) @@ -2956,7 +2951,6 @@ public: return false; } bool row_create_items(THD *thd, List *list); - Field *get_row_field(uint i) const; }; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 7f5c22eab89..ead04368acd 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -27,6 +27,7 @@ #include "sql_array.h" // Dynamic_array #include "log_event.h" // Query_log_event #include "sql_derived.h" // mysql_handle_derived +#include "sql_select.h" // Virtual_tmp_table #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation @@ -337,8 +338,8 @@ sp_get_flags_for_command(LEX *lex) /** Prepare an Item for evaluation (call of fix_fields). - @param thd thread handler @param it_addr pointer on item refernce + @param cols expected number of elements (1 for scalar, >=1 for ROWs) @retval NULL error @@ -346,21 +347,32 @@ sp_get_flags_for_command(LEX *lex) non-NULL prepared item */ -Item * -sp_prepare_func_item(THD* thd, Item **it_addr, uint cols) +Item *THD::sp_prepare_func_item(Item **it_addr, uint cols) { - DBUG_ENTER("sp_prepare_func_item"); + DBUG_ENTER("THD::sp_prepare_func_item"); + Item *res= sp_fix_func_item(it_addr); + if (res && res->check_cols(cols)) + DBUG_RETURN(NULL); + DBUG_RETURN(res); +} + + +/** + Fix an Item for evaluation for SP. +*/ +Item *THD::sp_fix_func_item(Item **it_addr) +{ + DBUG_ENTER("THD::sp_fix_func_item"); if (!(*it_addr)->fixed && - (*it_addr)->fix_fields(thd, it_addr)) + (*it_addr)->fix_fields(this, it_addr)) { DBUG_PRINT("info", ("fix_fields() failed")); DBUG_RETURN(NULL); } - it_addr= (*it_addr)->this_item_addr(thd, it_addr); + it_addr= (*it_addr)->this_item_addr(this, it_addr); - if ((!(*it_addr)->fixed && - (*it_addr)->fix_fields(thd, it_addr)) || - (*it_addr)->check_cols(cols)) + if (!(*it_addr)->fixed && + (*it_addr)->fix_fields(this, it_addr)) { DBUG_PRINT("info", ("fix_fields() failed")); DBUG_RETURN(NULL); @@ -372,7 +384,6 @@ sp_prepare_func_item(THD* thd, Item **it_addr, uint cols) /** Evaluate an expression and store the result in the field. - @param thd current thread object @param result_field the field to store the result @param expr_item_ptr the root item of the expression @@ -382,67 +393,13 @@ sp_prepare_func_item(THD* thd, Item **it_addr, uint cols) TRUE on error */ -bool -sp_eval_expr(THD *thd, Item *result_item, Field *result_field, - Item **expr_item_ptr) +bool THD::sp_eval_expr(Field *result_field, Item **expr_item_ptr) { - Item *expr_item; - enum_check_fields save_count_cuted_fields= thd->count_cuted_fields; - bool save_abort_on_warning= thd->abort_on_warning; - bool save_stmt_modified_non_trans_table= - thd->transaction.stmt.modified_non_trans_table; - - DBUG_ENTER("sp_eval_expr"); - - if (!*expr_item_ptr) - goto error; - - if (!(expr_item= sp_prepare_func_item(thd, expr_item_ptr, - result_item ? result_item->cols() : 1))) - goto error; - - /* - expr_item is now fixed, it's safe to call cmp_type() - If result_item is NULL, then we're setting the RETURN value. - */ - if ((!result_item || result_item->cmp_type() != ROW_RESULT) && - expr_item->cmp_type() == ROW_RESULT) - { - my_error(ER_OPERAND_COLUMNS, MYF(0), 1); - goto error; - } - - /* - Set THD flags to emit warnings/errors in case of overflow/type errors - during saving the item into the field. - - Save original values and restore them after save. - */ - - thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; - thd->abort_on_warning= thd->is_strict_mode(); - thd->transaction.stmt.modified_non_trans_table= FALSE; - + DBUG_ENTER("THD::sp_eval_expr"); + DBUG_ASSERT(*expr_item_ptr); + Sp_eval_expr_state state(this); /* Save the value in the field. Convert the value if needed. */ - - expr_item->save_in_field(result_field, 0); - - thd->count_cuted_fields= save_count_cuted_fields; - thd->abort_on_warning= save_abort_on_warning; - thd->transaction.stmt.modified_non_trans_table= save_stmt_modified_non_trans_table; - - if (!thd->is_error()) - DBUG_RETURN(FALSE); - -error: - /* - In case of error during evaluation, leave the result field set to NULL. - Sic: we can't do it in the beginning of the function because the - result field might be needed for its own re-evaluation, e.g. case of - set x = x + 1; - */ - result_field->set_null(); - DBUG_RETURN (TRUE); + DBUG_RETURN(result_field->sp_prepare_and_store_item(this, expr_item_ptr)); } @@ -3371,19 +3328,7 @@ int sp_instr_set::exec_core(THD *thd, uint *nextp) { int res= thd->spcont->set_variable(thd, m_offset, &m_value); - - if (res) - { - /* Failed to evaluate the value. Reset the variable to NULL. */ - - if (thd->spcont->set_variable(thd, m_offset, 0)) - { - /* If this also failed, let's abort. */ - my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); - } - } delete_explain_query(thd->lex); - *nextp = m_ip+1; return res; } @@ -3422,11 +3367,6 @@ sp_instr_set_row_field::exec_core(THD *thd, uint *nextp) { int res= thd->spcont->set_variable_row_field(thd, m_offset, m_field_offset, &m_value); - if (res) - { - /* Failed to evaluate the value. Reset the variable to NULL. */ - thd->spcont->set_variable_row_field_to_null(thd, m_offset, m_field_offset); - } delete_explain_query(thd->lex); *nextp= m_ip + 1; return res; @@ -3470,23 +3410,9 @@ sp_instr_set_row_field::print(String *str) int sp_instr_set_row_field_by_name::exec_core(THD *thd, uint *nextp) { - int res; - uint idx; - Item_field_row *row= (Item_field_row*) thd->spcont->get_item(m_offset); - if ((res= row->element_index_by_name(&idx, m_field_name))) - { - sp_variable *var= m_ctx->find_variable(m_offset); - my_error(ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD, MYF(0), - var->name.str, m_field_name.str); - goto error; - } - res= thd->spcont->set_variable_row_field(thd, m_offset, idx, &m_value); - if (res) - { - /* Failed to evaluate the value. Reset the variable to NULL. */ - thd->spcont->set_variable_row_field_to_null(thd, m_offset, idx); - } -error: + int res= thd->spcont->set_variable_row_field_by_name(thd, m_offset, + m_field_name, + &m_value); delete_explain_query(thd->lex); *nextp= m_ip + 1; return res; @@ -3650,7 +3576,7 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) Item *it; int res; - it= sp_prepare_func_item(thd, &m_expr); + it= thd->sp_prepare_func_item(&m_expr); if (! it) { res= -1; diff --git a/sql/sp_head.h b/sql/sp_head.h index f8a819bbe94..9f6d4cd95e5 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -1910,13 +1910,6 @@ sp_add_to_query_tables(THD *thd, LEX *lex, thr_lock_type locktype, enum_mdl_type mdl_type); -Item * -sp_prepare_func_item(THD* thd, Item **it_addr, uint cols= 1); - -bool -sp_eval_expr(THD *thd, Item *result_item, Field *result_field, - Item **expr_item_ptr); - /** @} (end of group Stored_Routines) */ diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 62b5439d84d..43d033ad83e 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -388,22 +388,13 @@ bool Item_field_row::row_create_items(THD *thd, List *list) } -Field *Item_field_row::get_row_field(uint i) const -{ - DBUG_ASSERT(field); - Virtual_tmp_table **ptable= field->virtual_tmp_table_addr(); - DBUG_ASSERT(ptable); - return ptable[0]->field[i]; -} - - bool sp_rcontext::set_return_value(THD *thd, Item **return_value_item) { DBUG_ASSERT(m_return_value_fld); m_return_value_set = true; - return sp_eval_expr(thd, NULL, m_return_value_fld, return_value_item); + return thd->sp_eval_expr(m_return_value_fld, return_value_item); } @@ -612,84 +603,31 @@ uint sp_rcontext::exit_handler(Diagnostics_area *da) int sp_rcontext::set_variable(THD *thd, uint idx, Item **value) { - Field *field= m_var_table->field[idx]; - if (!value) - { - field->set_null(); - return 0; - } - Item *dst= m_var_items[idx]; - - if (dst->cmp_type() != ROW_RESULT) - return sp_eval_expr(thd, dst, m_var_table->field[idx], value); - - DBUG_ASSERT(dst->type() == Item::FIELD_ITEM); - if (value[0]->type() == Item::NULL_ITEM) - { - /* - We're in a auto-generated sp_inst_set, to assign - the explicit default NULL value to a ROW variable. - */ - for (uint i= 0; i < dst->cols(); i++) - { - Item_field_row *item_field_row= (Item_field_row*) dst; - item_field_row->get_row_field(i)->set_null(); - } - return false; - } - - /** - - In case if we're assigning a ROW variable from another ROW variable, - value[0] points to Item_splocal. sp_prepare_func_item() will return the - fixed underlying Item_field_spvar with ROW members in its aguments(). - - In case if we're assigning from a ROW() value, src and value[0] will - point to the same Item_row. - */ - Item *src; - if (!(src= sp_prepare_func_item(thd, value, dst->cols())) || - src->cmp_type() != ROW_RESULT) - { - my_error(ER_OPERAND_COLUMNS, MYF(0), dst->cols()); - return true; - } - DBUG_ASSERT(dst->cols() == src->cols()); - for (uint i= 0; i < src->cols(); i++) - set_variable_row_field(thd, idx, i, src->addr(i)); - return false; -} - - -void sp_rcontext::set_variable_row_field_to_null(THD *thd, - uint var_idx, - uint field_idx) -{ - Item *dst= get_item(var_idx); - DBUG_ASSERT(dst->type() == Item::FIELD_ITEM); - DBUG_ASSERT(dst->cmp_type() == ROW_RESULT); - Item_field_row *item_field_row= (Item_field_row*) dst; - item_field_row->get_row_field(field_idx)->set_null(); + DBUG_ENTER("sp_rcontext::set_variable"); + DBUG_ASSERT(value); + DBUG_RETURN(thd->sp_eval_expr(m_var_table->field[idx], value)); } int sp_rcontext::set_variable_row_field(THD *thd, uint var_idx, uint field_idx, Item **value) { + DBUG_ENTER("sp_rcontext::set_variable_row_field"); DBUG_ASSERT(value); - Item *dst= get_item(var_idx); - DBUG_ASSERT(dst->type() == Item::FIELD_ITEM); - DBUG_ASSERT(dst->cmp_type() == ROW_RESULT); - Item_field_row *item_field_row= (Item_field_row*) dst; + Virtual_tmp_table *vtable= virtual_tmp_table_for_row(var_idx); + DBUG_RETURN(thd->sp_eval_expr(vtable->field[field_idx], value)); +} - Item *expr_item= sp_prepare_func_item(thd, value); - if (!expr_item) - { - DBUG_ASSERT(thd->is_error()); - return true; - } - return sp_eval_expr(thd, - item_field_row->arguments()[field_idx], - item_field_row->get_row_field(field_idx), - value); + +int sp_rcontext::set_variable_row_field_by_name(THD *thd, uint var_idx, + const LEX_CSTRING &field_name, + Item **value) +{ + DBUG_ENTER("sp_rcontext::set_variable_row_field_by_name"); + uint field_idx; + if (find_row_field_by_name_or_error(&field_idx, var_idx, field_name)) + DBUG_RETURN(1); + DBUG_RETURN(set_variable_row_field(thd, var_idx, field_idx, value)); } @@ -697,15 +635,32 @@ int sp_rcontext::set_variable_row(THD *thd, uint var_idx, List &items) { DBUG_ENTER("sp_rcontext::set_variable_row"); DBUG_ASSERT(get_item(var_idx)->cols() == items.elements); - List_iterator it(items); - Item *item; - for (uint i= 0 ; (item= it++) ; i++) - { - int rc; - if ((rc= set_variable_row_field(thd, var_idx, i, &item))) - DBUG_RETURN(rc); - } - DBUG_RETURN(0); + Virtual_tmp_table *vtable= virtual_tmp_table_for_row(var_idx); + Sp_eval_expr_state state(thd); + DBUG_RETURN(vtable->sp_set_all_fields_from_item_list(thd, items)); +} + + +Virtual_tmp_table *sp_rcontext::virtual_tmp_table_for_row(uint var_idx) +{ + DBUG_ASSERT(get_item(var_idx)->type() == Item::FIELD_ITEM); + DBUG_ASSERT(get_item(var_idx)->cmp_type() == ROW_RESULT); + Field *field= m_var_table->field[var_idx]; + Virtual_tmp_table **ptable= field->virtual_tmp_table_addr(); + DBUG_ASSERT(ptable); + DBUG_ASSERT(ptable[0]); + return ptable[0]; +} + + +bool sp_rcontext::find_row_field_by_name_or_error(uint *field_idx, + uint var_idx, + const LEX_CSTRING &field_name) +{ + Virtual_tmp_table *vtable= virtual_tmp_table_for_row(var_idx); + Field *row= m_var_table->field[var_idx]; + return vtable->sp_find_field_by_name_or_error(field_idx, + row->field_name, field_name); } @@ -728,7 +683,7 @@ Item_cache *sp_rcontext::create_case_expr_holder(THD *thd, bool sp_rcontext::set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr) { - Item *case_expr_item= sp_prepare_func_item(thd, case_expr_item_ptr); + Item *case_expr_item= thd->sp_prepare_func_item(case_expr_item_ptr); if (!case_expr_item) return true; diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index 26c06512417..ca438107593 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -190,9 +190,11 @@ public: ///////////////////////////////////////////////////////////////////////// int set_variable(THD *thd, uint var_idx, Item **value); - void set_variable_row_field_to_null(THD *thd, uint var_idx, uint field_idx); int set_variable_row_field(THD *thd, uint var_idx, uint field_idx, Item **value); + int set_variable_row_field_by_name(THD *thd, uint var_idx, + const LEX_CSTRING &field_name, + Item **value); int set_variable_row(THD *thd, uint var_idx, List &items); Item *get_item(uint var_idx) const { return m_var_items[var_idx]; } @@ -200,6 +202,9 @@ public: Item **get_item_addr(uint var_idx) const { return m_var_items.array() + var_idx; } + bool find_row_field_by_name_or_error(uint *field_idx, uint var_idx, + const LEX_CSTRING &field_name); + bool set_return_value(THD *thd, Item **return_value_item); bool is_return_value_set() const @@ -363,6 +368,8 @@ private: /// @return Pointer to valid object on success, or NULL in case of error. Item_cache *create_case_expr_holder(THD *thd, const Item *item) const; + Virtual_tmp_table *virtual_tmp_table_for_row(uint idx); + private: /// Top-level (root) parsing context for this runtime context. const sp_pcontext *m_root_parsing_ctx; diff --git a/sql/sql_class.h b/sql/sql_class.h index a4a631ee9f0..70a57fa22f7 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -4552,6 +4552,10 @@ public: See also sp_head::merge_lex(). */ bool restore_from_local_lex_to_old_lex(LEX *oldlex); + + Item *sp_fix_func_item(Item **it_addr); + Item *sp_prepare_func_item(Item **it_addr, uint cols= 1); + bool sp_eval_expr(Field *result_field, Item **expr_item_ptr); }; inline void add_to_active_threads(THD *thd) @@ -6162,6 +6166,49 @@ public: }; +/* + A helper class to set THD flags to emit warnings/errors in case of + overflow/type errors during assigning values into the SP variable fields. + Saves original flags values in constructor. + Restores original flags in destructor. +*/ +class Sp_eval_expr_state +{ + THD *m_thd; + enum_check_fields m_count_cuted_fields; + bool m_abort_on_warning; + bool m_stmt_modified_non_trans_table; + void start() + { + m_thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; + m_thd->abort_on_warning= m_thd->is_strict_mode(); + m_thd->transaction.stmt.modified_non_trans_table= false; + } + void stop() + { + m_thd->count_cuted_fields= m_count_cuted_fields; + m_thd->abort_on_warning= m_abort_on_warning; + m_thd->transaction.stmt.modified_non_trans_table= + m_stmt_modified_non_trans_table; + } +public: + Sp_eval_expr_state(THD *thd) + :m_thd(thd), + m_count_cuted_fields(thd->count_cuted_fields), + m_abort_on_warning(thd->abort_on_warning), + m_stmt_modified_non_trans_table(thd->transaction.stmt. + modified_non_trans_table) + { + start(); + } + ~Sp_eval_expr_state() + { + stop(); + } +}; + + + #endif /* MYSQL_SERVER */ #endif /* SQL_CLASS_INCLUDED */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index df03a0d30e7..2784938b654 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -17736,6 +17736,70 @@ bool Virtual_tmp_table::open() } +bool Virtual_tmp_table::sp_find_field_by_name(uint *idx, + const LEX_CSTRING &name) const +{ + Field *f; + for (uint i= 0; (f= field[i]); i++) + { + // Use the same comparison style with sp_context::find_variable() + if (!my_strnncoll(system_charset_info, + (const uchar *) f->field_name.str, + f->field_name.length, + (const uchar *) name.str, name.length)) + { + *idx= i; + return false; + } + } + return true; +} + + +bool +Virtual_tmp_table::sp_find_field_by_name_or_error(uint *idx, + const LEX_CSTRING &var_name, + const LEX_CSTRING &field_name) + const +{ + if (sp_find_field_by_name(idx, field_name)) + { + my_error(ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD, MYF(0), + var_name.str, field_name.str); + return true; + } + return false; +} + + +bool Virtual_tmp_table::sp_set_all_fields_from_item_list(THD *thd, + List &items) +{ + DBUG_ASSERT(s->fields == items.elements); + List_iterator it(items); + Item *item; + for (uint i= 0 ; (item= it++) ; i++) + { + if (field[i]->sp_prepare_and_store_item(thd, &item)) + return true; + } + return false; +} + + +bool Virtual_tmp_table::sp_set_all_fields_from_item(THD *thd, Item *value) +{ + DBUG_ASSERT(value->fixed); + DBUG_ASSERT(value->cols() == s->fields); + for (uint i= 0; i < value->cols(); i++) + { + if (field[i]->sp_prepare_and_store_item(thd, value->addr(i))) + return true; + } + return false; +} + + bool open_tmp_table(TABLE *table) { int error; diff --git a/sql/sql_select.h b/sql/sql_select.h index 4e2206dd098..7cfc35a3b7d 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -2127,6 +2127,48 @@ public: @return true - on error (e.g. could not allocate the record buffer). */ bool open(); + + void set_all_fields_to_null() + { + for (uint i= 0; i < s->fields; i++) + field[i]->set_null(); + } + /** + Set all fields from a compatible item list. + The number of fields in "this" must be equal to the number + of elements in "value". + */ + bool sp_set_all_fields_from_item_list(THD *thd, List &items); + + /** + Set all fields from a compatible item. + The number of fields in "this" must be the same with the number + of elements in "value". + */ + bool sp_set_all_fields_from_item(THD *thd, Item *value); + + /** + Find a ROW element index by its name + Assumes that "this" is used as a storage for a ROW-type SP variable. + @param [OUT] idx - the index of the found field is returned here + @param [IN] field_name - find a field with this name + @return true - on error (the field was not found) + @return false - on success (idx[0] was set to the field index) + */ + bool sp_find_field_by_name(uint *idx, const LEX_CSTRING &name) const; + + /** + Find a ROW element index by its name. + If the element is not found, and error is issued. + @param [OUT] idx - the index of the found field is returned here + @param [IN] var_name - the name of the ROW variable (for error reporting) + @param [IN] field_name - find a field with this name + @return true - on error (the field was not found) + @return false - on success (idx[0] was set to the field index) + */ + bool sp_find_field_by_name_or_error(uint *idx, + const LEX_CSTRING &var_name, + const LEX_CSTRING &field_name) const; };