From 9ae160af7647139a321203fa02c4122744e2ba63 Mon Sep 17 00:00:00 2001 From: Aakanksha Verma Date: Thu, 31 Aug 2017 15:44:42 +0530 Subject: --- sql/ha_partition.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 414f9d52536..17596fb924c 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2751,7 +2751,15 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) name_buffer_ptr= m_name_buffer_ptr; m_start_key.length= 0; m_rec0= table->record[0]; - m_rec_length= table_share->reclength; + legacy_db_type db_type = ha_legacy_type(m_part_info->default_engine_type); + if (db_type == DB_TYPE_HEAP) + { + m_rec_length= table_share->rec_buff_length; + } else { + m_rec_length= table_share->reclength; + } + DBUG_ASSERT(db_type != DB_TYPE_UNKNOWN); + if (!m_part_ids_sorted_by_num_of_records) { if (!(m_part_ids_sorted_by_num_of_records= -- cgit v1.2.1 From ad00de40772614e79ef8f14647d37a7d356cff5c Mon Sep 17 00:00:00 2001 From: Sreeharsha Ramanavarapu Date: Wed, 6 Sep 2017 06:45:50 +0530 Subject: Bug #26704451: INCORRECT BEHAVIOR WITH USE OF CERTAIN CHARSETS AND SHA2 Missed pushing to 5.5. --- sql/item_strfunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index ed02f668060..e2a2ee1b6d8 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -266,9 +266,9 @@ String *Item_func_sha2::val_str_ascii(String *str) size_t input_len; uint digest_length= 0; + input_string= args[0]->val_str(str); str->set_charset(&my_charset_bin); - input_string= args[0]->val_str(str); if (input_string == NULL) { null_value= TRUE; -- cgit v1.2.1 From aa6e69db10a991e5c3ca213a8c3a60350c1462c2 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Mon, 9 Oct 2017 16:24:11 +0200 Subject: Backport patch for Bug#16877045 5.6-CLUSTER-7.3 WIN32 SQL_YACC.CC BUILD PROBLEM Building with ninja shows the problem: cmake .. -G Ninja ninja ninja: error: dependency cycle: sql/GenServerSource -> sql/CMakeFiles/GenServerSource -> sql/sql_builtin.cc -> cmake_order_depends_target_sq sql/GenServerSource Bug#16877045 5.6-CLUSTER-7.3 WIN32 SQL_YACC.CC BUILD PROBLEM - Somewhat circular dependency caused by the configured files sql_builtin.cc being included as part of the files to generate in sql/ - Move sql_builtin.cc out of GEN_SOURCES variable. - Create new variable CONF_SOURCES to be used for configured files. --- sql/CMakeLists.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index b0a44b9a1d4..531561ac36d 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -22,14 +22,16 @@ ${SSL_INCLUDE_DIRS} ${CMAKE_BINARY_DIR}/sql ) +SET(CONF_SOURCES + ${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc +) SET(GEN_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.h ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.cc -${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc ${CMAKE_CURRENT_BINARY_DIR}/lex_hash.h ) -SET_SOURCE_FILES_PROPERTIES(${GEN_SOURCES} PROPERTIES GENERATED 1) +SET_SOURCE_FILES_PROPERTIES(${GEN_SOURCES} ${CONF_SOURCES} PROPERTIES GENERATED 1) ADD_DEFINITIONS(-DMYSQL_SERVER -DHAVE_EVENT_SCHEDULER) IF(SSL_DEFINES) @@ -78,6 +80,7 @@ SET (SQL_SOURCE transaction.cc sys_vars.cc sql_truncate.cc datadict.cc sql_reload.cc ${GEN_SOURCES} + ${CONF_SOURCES} ${MYSYS_LIBWRAP_SOURCE}) # These files have unused result errors, so we skip Werror -- cgit v1.2.1 From 84c32cdbe746fdabc33988fc17b1f11b08fd22e0 Mon Sep 17 00:00:00 2001 From: Sreeharsha Ramanavarapu Date: Thu, 19 Oct 2017 10:19:36 +0530 Subject: Bug #26867652: INCORRECT BEHAVIOR WITH PREPARE STATEMENT AND PARAM IN ORDER BY Issue: ------ This issue can occur when the ORDER BY list refers to a column that contains a parameter in the select list. Solution: --------- In JOIN::update_depend_map and get_sort_by_table, the ORDER BY list's used_tables isn't checked for parameters. This can result in incorrect behavior. This is a partial backport of Roy's --- sql/sql_select.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 80d4b87e916..eb38d8be382 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -7430,7 +7430,8 @@ static void update_depend_map(JOIN *join, ORDER *order) { table_map depend_map; order->item[0]->update_used_tables(); - order->depend_map=depend_map=order->item[0]->used_tables(); + order->depend_map=depend_map= + order->item[0]->used_tables() & ~PARAM_TABLE_BIT; order->used= 0; // Not item_sum(), RAND() and no reference to table outside of sub select if (!(order->depend_map & (OUTER_REF_TABLE_BIT | RAND_TABLE_BIT)) @@ -15583,6 +15584,7 @@ get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables) DBUG_RETURN(0); map|=a->item[0]->used_tables(); } + map&= ~PARAM_TABLE_BIT; if (!map || (map & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT))) DBUG_RETURN(0); -- cgit v1.2.1 From a542209b9e70e28e88ba60d2e4441a8c2d3e746c Mon Sep 17 00:00:00 2001 From: Karthik Kamath Date: Mon, 23 Oct 2017 10:56:20 +0530 Subject: BUG#26529369: CREATE INDEX WITH LONG COMMENT CAUSE UNEXPECTED ERROR ANALYSIS: ========= Creating many indexes with large amount of index information causes a server exit. FIX: ==== A appropriate error is reported when the cumulative index information length exceeds the 2 byte range (i.e 65535). --- sql/unireg.cc | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/unireg.cc b/sql/unireg.cc index d77a6b06275..788046cfae4 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -283,6 +283,25 @@ bool mysql_create_frm(THD *thd, const char *file_name, keybuff=(uchar*) my_malloc(key_buff_length, MYF(0)); key_info_length= pack_keys(keybuff, keys, key_info, data_offset); + /* key_info_length is currently stored in 2 bytes */ + if (key_info_length > 65535U) + { + char *real_table_name= (char*) table; + List_iterator it(create_fields); + Create_field *field; + while ((field=it++)) + { + if (field->field && field->field->table && + (real_table_name= field->field->table->s->table_name.str)) + break; + } + my_printf_error(ER_UNKNOWN_ERROR, + "Index information size for the table %s.%s exceeds the " + "maximum limit (Max: 2 bytes). Please recreate indexes " + "accordingly.", MYF(0), db, real_table_name); + goto err; + } + /* Ensure that there are no forms in this newly created form file. Even if the form file exists, create_frm must truncate it to -- cgit v1.2.1 From f06443ce5f9ca8a65b60b595b2095f76d8f65206 Mon Sep 17 00:00:00 2001 From: Sreeharsha Ramanavarapu Date: Thu, 16 Nov 2017 09:31:12 +0530 Subject: Bug #26881946: INCORRECT BEHAVIOR WITH "VALUES" Issue: ------ VALUES doesn't have a type() function and is considered a Item_field. Solution for 5.7: ----------------- Add a new type() function for Item_values_insert. On 8.0 and trunk it was fixed by Mithun's Bug#19601973. Solution for 5.6: ----------------- Additionally Bug#17458914 is backported. This will address the problem of using VALUES() in INSERT ... ON DUPLICATE KEY UPDATE. Create a field object only if it is in the UPDATE clause, else return a NULL item. This will also address the problems mentioned in Bug#14789787 and Bug#16756402. Solution for 5.5: ----------------- As mentioned above Bug#17458914 is backported. Additionally Bug#14786324 is also backported. When VALUES() is detected outside its meaningful place, it should be treated as NULL and is thus replaced with a Field_null object, with the same name as the original field. Fields with type NULL are generally not handled well inside the server (e.g Innodb will not accept them and it is impossible to create them in regular tables). So create a new const NULL item instead. --- sql/item.cc | 27 ++++++++++++++------------- sql/item.h | 2 ++ sql/sql_insert.cc | 8 +++++++- sql/sql_lex.cc | 5 +++-- sql/sql_lex.h | 4 +++- 5 files changed, 29 insertions(+), 17 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 6f1fdaae398..a37a61453e8 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -7120,7 +7120,7 @@ Item *Item_default_value::transform(Item_transformer transformer, uchar *args) bool Item_insert_value::eq(const Item *item, bool binary_cmp) const { return item->type() == INSERT_VALUE_ITEM && - ((Item_default_value *)item)->arg->eq(arg, binary_cmp); + ((Item_insert_value *)item)->arg->eq(arg, binary_cmp); } @@ -7149,11 +7149,12 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) Item_field *field_arg= (Item_field *)arg; - if (field_arg->field->table->insert_values) + if (field_arg->field->table->insert_values && + thd->lex->in_update_value_clause) { Field *def_field= (Field*) sql_alloc(field_arg->field->size_of()); if (!def_field) - return TRUE; + return true; memcpy(def_field, field_arg->field, field_arg->field->size_of()); def_field->move_field_offset((my_ptrdiff_t) (def_field->table->insert_values - @@ -7162,17 +7163,17 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) } else { - Field *tmp_field= field_arg->field; - /* charset doesn't matter here, it's to avoid sigsegv only */ - tmp_field= new Field_null(0, 0, Field::NONE, field_arg->field->field_name, - &my_charset_bin); - if (tmp_field) - { - tmp_field->init(field_arg->field->table); - set_field(tmp_field); - } + // VALUES() is used out-of-scope - its value is always NULL + Query_arena backup; + Query_arena *const arena= thd->activate_stmt_arena_if_needed(&backup); + Item *const item= new Item_null(this->name); + if (arena) + thd->restore_active_arena(arena, &backup); + if (!item) + return TRUE; + *items= item; } - return FALSE; + return false; } void Item_insert_value::print(String *str, enum_query_type query_type) diff --git a/sql/item.h b/sql/item.h index 9f4e1d24424..3556a58ff82 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3150,6 +3150,8 @@ public: :Item_field(context_arg, (const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {} + + enum Type type() const { return INSERT_VALUE_ITEM; } bool eq(const Item *item, bool binary_cmp) const; bool fix_fields(THD *, Item **); virtual void print(String *str, enum_query_type query_type); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index dc7cb698476..5d1905bf4ba 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1393,9 +1393,12 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, thd->abort_on_warning= saved_abort_on_warning; } + thd->lex->in_update_value_clause= true; if (!res) res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0); + thd->lex->in_update_value_clause= false; + if (!res && duplic == DUP_UPDATE) { select_lex->no_wrap_view_item= TRUE; @@ -3263,8 +3266,11 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) table_list->next_name_resolution_table= ctx_state.get_first_name_resolution_table(); + thd->lex->in_update_value_clause= true; res= res || setup_fields(thd, 0, *info.update_values, MARK_COLUMNS_READ, 0, 0); + + thd->lex->in_update_value_clause= false; if (!res) { /* diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 50cdabe341a..f7e9fd8570d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2376,7 +2376,8 @@ void Query_tables_list::destroy_query_tables_list() */ LEX::LEX() - :result(0), option_type(OPT_DEFAULT), is_lex_started(0) + :result(0), option_type(OPT_DEFAULT), is_lex_started(0), + in_update_value_clause(false) { my_init_dynamic_array2(&plugins, sizeof(plugin_ref), diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 867997feb39..3c950ebe117 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2491,6 +2491,8 @@ struct LEX: public Query_tables_list bool escape_used; bool is_lex_started; /* If lex_start() did run. For debugging. */ + /// Set to true while resolving values in ON DUPLICATE KEY UPDATE clause + bool in_update_value_clause; /* The set of those tables whose fields are referenced in all subqueries -- cgit v1.2.1 From 6293e3bbcfc866397809b844485b9fdede97dc1b Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 10 Jan 2018 12:22:56 +0100 Subject: MDEV-14743: Server crashes in Item_func_match::init_search Remove non prepared (and so belonging to removed clauses FT functions) from the list. in later version it will be fixed by building the list during preparation. --- sql/sql_base.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c06c4fcff29..f5864256440 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -9550,7 +9550,17 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order) DBUG_PRINT("info",("Performing FULLTEXT search")); while ((ifm=li++)) - ifm->init_search(no_order); +#if MYSQL_VERSION_ID < 100213 + if (unlikely(!ifm->fixed)) + /* + it mean that clause where was FT function was removed, so we have + to remove the function from the list. + */ + li.remove(); + else +#endif + ifm->init_search(no_order); + } return 0; } -- cgit v1.2.1 From abc123391f5a22e18c8e260541dbdbde1375e8b5 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 12 Jan 2018 00:14:40 -0800 Subject: Fixed mdev-6706 Wrong result (missing rows) with joins, SQ, ORDER BY, semijoin=on A bug in get_sort_by_table() could mislead the function setup_semijoin_dups_elimination(). As a result the optimizer could produce invalid execution plans for queries with ORDER BY and subquery predicates that could be converted to semi-joins. --- sql/sql_select.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c7f547edbc0..5a7fa4d2c6f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -21159,6 +21159,7 @@ get_sort_by_table(ORDER *a,ORDER *b, List &tables, if (!map || (map & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT))) DBUG_RETURN(0); + map&= ~const_tables; while ((table= ti++) && !(map & table->table->map)) ; if (map != table->table->map) DBUG_RETURN(0); // More than one table -- cgit v1.2.1 From 5fe1d7d07611855963ea62ca39461289d8f8d25e Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Fri, 12 Jan 2018 18:17:55 +0100 Subject: MDEV-14526: MariaDB keeps crashing under load when query_cache_type is changed The problem was in such scenario: T1 - starts registering query and locked QC T2 - starts disabling QC and wait for UNLOCK T1 - unlock QC T2 - disable QC and destroy signals without waiting for query unlock T1 a) - not yet unlocked query in qc and crash on attempt to unlock because QC signals are destroyed b) if above was done before destruction, it execute end_of results first time at exit on after try_lock which see QC disables and return TRUE. But it do not reset query_cache_tls->first_query_block which lead to second call of end_of_result when diagnostic arena has already inappropriate status (not is_eof()). Fix is: 1) wait for all queries unlocked before destroying them by locking and unlocking 2) remove query_cache_tls->first_query_block if QC disabled --- sql/sql_cache.cc | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 2ec870f314f..3fc1edfcb56 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1184,7 +1184,11 @@ void Query_cache::end_of_result(THD *thd) #endif if (try_lock(thd, Query_cache::WAIT)) + { + if (is_disabled()) + query_cache_tls->first_query_block= NULL; // do not try again with QC DBUG_VOID_RETURN; + } query_block= query_cache_tls->first_query_block; if (query_block) @@ -1556,6 +1560,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", unlock(); + DEBUG_SYNC(thd, "wait_in_query_cache_store_query"); + // init_n_lock make query block locked BLOCK_UNLOCK_WR(query_block); } @@ -2679,13 +2685,17 @@ void Query_cache::make_disabled() This function frees all resources allocated by the cache. You have to call init_cache() before using the cache again. This function - requires the structure_guard_mutex to be locked. + requires the cache to be locked (LOCKED_NO_WAIT, lock_and_suspend) or + disabling. */ void Query_cache::free_cache() { DBUG_ENTER("Query_cache::free_cache"); + DBUG_ASSERT(m_cache_lock_status == LOCKED_NO_WAIT || + m_cache_status == DISABLE_REQUEST); + /* Destroy locks */ Query_cache_block *block= queries_blocks; if (block) @@ -2693,6 +2703,13 @@ void Query_cache::free_cache() do { Query_cache_query *query= block->query(); + /* + There will not be new requests but some maybe not finished yet, + so wait for them by trying lock/unlock + */ + BLOCK_LOCK_WR(block); + BLOCK_UNLOCK_WR(block); + mysql_rwlock_destroy(&query->lock); block= block->next; } while (block != queries_blocks); -- cgit v1.2.1 From 943c62a5d4729786cb310f4a6af226184eb26196 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 26 Sep 2014 15:54:42 +0200 Subject: Backport 4bb49d84a9df, correct handling on defaults[-extra]-file is SST scripts (from 10.1 to 10.0-galera) This conflicted signficantly with 7d550c76be13c58551e203f4eeb4f87ebd58ba4b which added --defaults-group-suffix support. Took the approach of 4bb49d84a9df and adapted the --defaults-group-suffix handling to be consistent. The following changes as follows: SST scripts now use $MY_PRINT_DEFAULTS rather than the lowercase for consistency and this include all required --default arguements. Backport/merge by Daniel Black --- sql/wsrep_sst.cc | 46 +++++++++++++++++++++++++++++++++++++--------- sql/wsrep_sst.h | 1 + 2 files changed, 38 insertions(+), 9 deletions(-) (limited to 'sql') diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index e4ec1adb35f..ca5dcd91216 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -30,8 +30,10 @@ #include #include -extern const char wsrep_defaults_file[]; -extern const char wsrep_defaults_group_suffix[]; +static char wsrep_defaults_file[FN_REFLEN * 2 + 10 + 30 + + sizeof(WSREP_SST_OPT_CONF) + + sizeof(WSREP_SST_OPT_CONF_SUFFIX) + + sizeof(WSREP_SST_OPT_CONF_EXTRA)] = {0}; const char* wsrep_sst_method = WSREP_SST_DEFAULT; const char* wsrep_sst_receive_address = WSREP_SST_ADDRESS_AUTO; @@ -61,6 +63,28 @@ bool wsrep_sst_method_update (sys_var *self, THD* thd, enum_var_type type) return 0; } + +static void make_wsrep_defaults_file() +{ + if (!wsrep_defaults_file[0]) + { + char *ptr= wsrep_defaults_file; + char *end= ptr + sizeof(wsrep_defaults_file); + if (my_defaults_file) + ptr= strxnmov(ptr, end - ptr, + WSREP_SST_OPT_CONF, " '", my_defaults_file, "' ", NULL); + + if (my_defaults_extra_file) + ptr= strxnmov(ptr, end - ptr, + WSREP_SST_OPT_CONF_EXTRA, " '", my_defaults_extra_file, "' ", NULL); + + if (my_defaults_group_suffix) + ptr= strxnmov(ptr, end - ptr, + WSREP_SST_OPT_CONF_SUFFIX, " '", my_defaults_group_suffix, "' ", NULL); + } +} + + // TODO: Improve address verification. static bool sst_receive_address_check (const char* str) { @@ -512,17 +536,18 @@ static ssize_t sst_prepare_other (const char* method, } if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG; + make_wsrep_defaults_file(); + ret= snprintf (cmd_str(), cmd_len, "wsrep_sst_%s " WSREP_SST_OPT_ROLE" 'joiner' " WSREP_SST_OPT_ADDR" '%s' " WSREP_SST_OPT_DATA" '%s' " - WSREP_SST_OPT_CONF" '%s' " - WSREP_SST_OPT_CONF_SUFFIX" '%s' " + " %s " WSREP_SST_OPT_PARENT" '%d'" " %s '%s' ", method, addr_in, mysql_real_data_home, - wsrep_defaults_file, wsrep_defaults_group_suffix, + wsrep_defaults_file, (int)getpid(), binlog_opt, binlog_opt_val); my_free(binlog_opt_val); @@ -785,12 +810,14 @@ static int sst_donate_mysqldump (const char* addr, if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE); + make_wsrep_defaults_file(); + int ret= snprintf (cmd_str(), cmd_len, "wsrep_sst_mysqldump " WSREP_SST_OPT_ADDR" '%s' " WSREP_SST_OPT_LPORT" '%u' " WSREP_SST_OPT_SOCKET" '%s' " - WSREP_SST_OPT_CONF" '%s' " + " '%s' " WSREP_SST_OPT_GTID" '%s:%lld'" "%s", addr, mysqld_port, mysqld_unix_port, @@ -1091,19 +1118,20 @@ static int sst_donate_other (const char* method, } if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG; + make_wsrep_defaults_file(); + ret= snprintf (cmd_str(), cmd_len, "wsrep_sst_%s " WSREP_SST_OPT_ROLE" 'donor' " WSREP_SST_OPT_ADDR" '%s' " WSREP_SST_OPT_SOCKET" '%s' " WSREP_SST_OPT_DATA" '%s' " - WSREP_SST_OPT_CONF" '%s' " - WSREP_SST_OPT_CONF_SUFFIX" '%s' " + " %s " " %s '%s' " WSREP_SST_OPT_GTID" '%s:%lld'" "%s", method, addr, mysqld_unix_port, mysql_real_data_home, - wsrep_defaults_file, wsrep_defaults_group_suffix, + wsrep_defaults_file, binlog_opt, binlog_opt_val, uuid, (long long) seqno, bypass ? " " WSREP_SST_OPT_BYPASS : ""); diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h index 42f1055bde2..631480e7986 100644 --- a/sql/wsrep_sst.h +++ b/sql/wsrep_sst.h @@ -25,6 +25,7 @@ #define WSREP_SST_OPT_DATA "--datadir" #define WSREP_SST_OPT_CONF "--defaults-file" #define WSREP_SST_OPT_CONF_SUFFIX "--defaults-group-suffix" +#define WSREP_SST_OPT_CONF_EXTRA "--defaults-extra-file" #define WSREP_SST_OPT_PARENT "--parent" #define WSREP_SST_OPT_BINLOG "--binlog" -- cgit v1.2.1 From 88a9b23396531f0f0f63c1f989af69772216d442 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 15 Jan 2018 13:50:28 +0400 Subject: MDEV-14609 XA Transction unable to ROLLBACK TO SAVEPOINT The function trans_rollback_to_savepoint(), unlike trans_savepoint(), did not allow xa_state=XA_ACTIVE, so an attempt to do ROLLBCK TO SAVEPOINT inside an XA transaction incorrectly returned an error "...command cannot be executed ... in the ACTIVE state...". Partially merging a MySQL patch: 7fb5c47390311d9b1b5367f97cb8fedd4102dd05 This is WL#7193 (Decouple THD and st_transactions)... The currently merged part includes these changes: - Introducing st_xid_state::check_has_uncommitted_xa() - Reusing it in both trans_rollback_to_savepoint() and trans_savepoint(), so now both allow XA_ACTIVE. --- sql/sql_class.h | 24 ++++++++++++++++++++++++ sql/transaction.cc | 12 ++---------- 2 files changed, 26 insertions(+), 10 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.h b/sql/sql_class.h index f4be996c9a9..e8f50f13ebc 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -991,6 +991,30 @@ typedef struct st_xid_state { bool in_thd; /* Error reported by the Resource Manager (RM) to the Transaction Manager. */ uint rm_error; + + /** + Check that XA transaction has an uncommitted work. Report an error + to the user in case when there is an uncommitted work for XA transaction. + + @return result of check + @retval false XA transaction is NOT in state IDLE, PREPARED + or ROLLBACK_ONLY. + @retval true XA transaction is in state IDLE or PREPARED + or ROLLBACK_ONLY. + */ + + bool check_has_uncommitted_xa() const + { + if (xa_state == XA_IDLE || + xa_state == XA_PREPARED || + xa_state == XA_ROLLBACK_ONLY) + { + my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]); + return true; + } + return false; + } + } XID_STATE; extern mysql_mutex_t LOCK_xid_cache; diff --git a/sql/transaction.cc b/sql/transaction.cc index ae38e920a1d..6b09bd18d4c 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -433,12 +433,8 @@ bool trans_savepoint(THD *thd, LEX_STRING name) !opt_using_transactions) DBUG_RETURN(FALSE); - enum xa_states xa_state= thd->transaction.xid_state.xa_state; - if (xa_state != XA_NOTR && xa_state != XA_ACTIVE) - { - my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]); + if (thd->transaction.xid_state.check_has_uncommitted_xa()) DBUG_RETURN(TRUE); - } sv= find_savepoint(thd, name); @@ -513,12 +509,8 @@ bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name) DBUG_RETURN(TRUE); } - enum xa_states xa_state= thd->transaction.xid_state.xa_state; - if (xa_state != XA_NOTR) - { - my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]); + if (thd->transaction.xid_state.check_has_uncommitted_xa()) DBUG_RETURN(TRUE); - } if (ha_rollback_to_savepoint(thd, sv)) res= TRUE; -- cgit v1.2.1 From d31ee64da68a8fee9334c7b0bcab98cb636af36f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 15 Jan 2018 01:23:30 +0100 Subject: compiler warning --- sql/item_subselect.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 90f2bd5b9eb..46d41fd61e3 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -4927,7 +4927,7 @@ int subselect_hash_sj_engine::exec() if (has_covering_null_row) { - DBUG_ASSERT(count_partial_match_columns = field_count); + DBUG_ASSERT(count_partial_match_columns == field_count); count_pm_keys= 0; } else if (has_covering_null_columns) -- cgit v1.2.1 From 6267be460ab5147e3bc0fffd03e690b3650f2fe2 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 12 Jan 2018 15:51:10 -0800 Subject: Fixed mdev-14911: zero_date is considered as NULL, depending on optimizer_switch For DATE and DATETIME columns defined as NOT NULL, "date_notnull IS NULL" has to be modified to: "date_notnull IS NULL OR date_notnull == 0" if date_notnull is from an inner table of outer join); "date_notnull == 0" - otherwise. This must hold for such columns of mergeable views and derived tables as well. So far the code did the above re-writing only for columns of base tables and temporary tables. --- sql/sql_select.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5a7fa4d2c6f..8c2e90d8e57 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13980,9 +13980,9 @@ bool cond_is_datetime_is_null(Item *cond) ((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC) { Item **args= ((Item_func_isnull*) cond)->arguments(); - if (args[0]->type() == Item::FIELD_ITEM) + if (args[0]->real_item()->type() == Item::FIELD_ITEM) { - Field *field=((Item_field*) args[0])->field; + Field *field=((Item_field*) (args[0]->real_item()))->field; if (((field->type() == MYSQL_TYPE_DATE) || (field->type() == MYSQL_TYPE_DATETIME)) && @@ -14308,14 +14308,14 @@ internal_remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) */ Item **args= ((Item_func_isnull*) cond)->arguments(); - Field *field=((Item_field*) args[0])->field; + Field *field=((Item_field*) (args[0]->real_item()))->field; Item *item0= new(thd->mem_root) Item_int((longlong)0, 1); Item *eq_cond= new(thd->mem_root) Item_func_eq(args[0], item0); if (!eq_cond) return cond; - if (field->table->pos_in_table_list->is_inner_table_of_outer_join()) + if (field->table->pos_in_table_list->is_inner_table_of_outer_join()) { // outer join: transform "col IS NULL" to "col IS NULL or col=0" Item *or_cond= new(thd->mem_root) Item_cond_or(eq_cond, cond); -- cgit v1.2.1 From 444587d8a3c4b91421cd4cfd7bda2e3f4d1aebe4 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 16 Jan 2018 23:00:21 +0100 Subject: BIT field woes * get_rec_bits() was always reading two bytes, even if the bit field contained only of one byte * In various places the code used field->pack_length() bytes starting from field->ptr, while it should be field->pack_length_in_rec() * Field_bit::key_cmp and Field_bit::cmp_max passed field_length as an argument to memcmp(), but field_length is the number of bits! --- sql/field.cc | 6 +++--- sql/field_conv.cc | 6 +++--- sql/sql_join_cache.cc | 2 +- sql/sql_select.cc | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 08ba437fa30..5b111ab5e03 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1758,7 +1758,7 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) { uint store_length; copy->str= ptr; - copy->length= pack_length(); + copy->length= pack_length_in_rec(); copy->field= this; if (flags & BLOB_FLAG) { @@ -8422,7 +8422,7 @@ int Field_bit::cmp_max(const uchar *a, const uchar *b, uint max_len) if ((flag= (int) (bits_a - bits_b))) return flag; } - return memcmp(a, b, field_length); + return memcmp(a, b, bytes_in_rec); } @@ -8437,7 +8437,7 @@ int Field_bit::key_cmp(const uchar *str, uint length) str++; length--; } - return memcmp(ptr, str, length); + return memcmp(ptr, str, bytes_in_rec); } diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 5781f1da576..09792aa1660 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -589,7 +589,7 @@ void Copy_field::set(uchar *to,Field *from) { from_ptr=from->ptr; to_ptr=to; - from_length=from->pack_length(); + from_length=from->pack_length_in_rec(); if (from->maybe_null()) { from_null_ptr=from->null_ptr; @@ -640,9 +640,9 @@ void Copy_field::set(Field *to,Field *from,bool save) from_field=from; to_field=to; from_ptr=from->ptr; - from_length=from->pack_length(); + from_length=from->pack_length_in_rec(); to_ptr= to->ptr; - to_length=to_field->pack_length(); + to_length=to_field->pack_length_in_rec(); // set up null handling from_null_ptr=to_null_ptr=0; diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index 820ac75c885..13f06024b22 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -394,7 +394,7 @@ void JOIN_CACHE::create_flag_fields() TABLE *table= tab->table; /* Create a field for the null bitmap from table if needed */ - if (tab->used_null_fields || tab->used_uneven_bit_fields) + if (tab->used_null_fields || tab->used_uneven_bit_fields) length+= add_flag_field_to_join_cache(table->null_flags, table->s->null_bytes, ©); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8c2e90d8e57..c752d48e7c5 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15537,7 +15537,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List &fields, else { field->set_notnull(); - memcpy(field->ptr, orig_field->ptr, field->pack_length()); + memcpy(field->ptr, orig_field->ptr, field->pack_length_in_rec()); } orig_field->move_field_offset(-diff); // Back to record[0] } -- cgit v1.2.1 From 0d59b1db8349f449b2cc7854bb1d8382ecd1b893 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 17 Jan 2018 12:27:39 +0100 Subject: cleanup --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c752d48e7c5..66f25bcd119 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11222,8 +11222,8 @@ static void update_depend_map(JOIN *join) uint i; for (i=0 ; i < ref->key_parts ; i++,item++) depend_map|=(*item)->used_tables(); - ref->depend_map=depend_map & ~OUTER_REF_TABLE_BIT; depend_map&= ~OUTER_REF_TABLE_BIT; + ref->depend_map= depend_map; for (JOIN_TAB **tab=join->map2table; depend_map ; tab++,depend_map>>=1 ) -- cgit v1.2.1 From 8aff418ec867419950bc2e0010f679b8f0216829 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 17 Jan 2018 13:09:47 +0100 Subject: crash with too long index comments --- sql/unireg.cc | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) (limited to 'sql') diff --git a/sql/unireg.cc b/sql/unireg.cc index 528c3025c57..2527d44bbd0 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -89,6 +89,28 @@ handle_condition(THD *, return is_handled; } +/* + In ALTER TABLE, mysql_create_frm() gets the temporary table name, + like #sql-3696_2. It's used for error messages, when a table cannot + be created because of some OS error. + If there's a user error (like, too long comment), we want to show + the real table name, though. +*/ +static const char *get_real_table_name(const char *table, + List &fields) +{ + const char *real_table_name= table; + List_iterator it(fields); + Create_field *field; + while ((field=it++)) + { + if (field->field && field->field->table && + (real_table_name= field->field->table->s->table_name.str)) + break; + } + return real_table_name; +} + /* Create a frm (table definition) file @@ -232,15 +254,7 @@ bool mysql_create_frm(THD *thd, const char *file_name, if (tmp_len < create_info->comment.length) { - char *real_table_name= (char*) table; - List_iterator it(create_fields); - Create_field *field; - while ((field=it++)) - { - if (field->field && field->field->table && - (real_table_name= field->field->table->s->table_name.str)) - break; - } + const char *real_table_name= get_real_table_name(table, create_fields); if ((thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))) { @@ -285,6 +299,15 @@ bool mysql_create_frm(THD *thd, const char *file_name, keybuff=(uchar*) my_malloc(key_buff_length, MYF(0)); key_info_length= pack_keys(keybuff, keys, key_info, data_offset); + if (key_info_length > UINT_MAX16) + { + my_printf_error(ER_CANT_CREATE_TABLE, + "Cannot create table %`s.%`s: index information is too long. " + "Decrease number of indexes or use shorter index names or shorter comments.", + MYF(0), db, get_real_table_name(table, create_fields)); + goto err; + } + /* Ensure that there are no forms in this newly created form file. Even if the form file exists, create_frm must truncate it to -- cgit v1.2.1 From 4f96b401d9dd9f876c2d3e6e266e8670d30ca2c8 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 18 Jan 2018 09:20:55 -0800 Subject: Fixed mdev-14960 [ERROR] mysqld got signal 11 with join_buffer and join_cache In the function JOIN::shrink_join_buffers the iteration over joined tables was organized in a wrong way. This could cause a crash if the optimizer chose to materialize a semi-join that used join caches for which the sizes must be adjusted. --- sql/sql_select.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9f89a261540..42b3420a9b6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2085,8 +2085,11 @@ bool JOIN::shrink_join_buffers(JOIN_TAB *jt, ulonglong curr_space, ulonglong needed_space) { + JOIN_TAB *tab; JOIN_CACHE *cache; - for (JOIN_TAB *tab= join_tab+const_tables; tab < jt; tab++) + for (tab= first_linear_tab(this, WITHOUT_BUSH_ROOTS, WITHOUT_CONST_TABLES); + tab != jt; + tab= next_linear_tab(this, tab, WITHOUT_BUSH_ROOTS)) { cache= tab->cache; if (cache) -- cgit v1.2.1 From a7a4519a40c58947796c6d9b2e4e58acc18aeef8 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Fri, 19 Jan 2018 13:29:31 +0530 Subject: MDEV-14241: Server crash in key_copy / get_matching_chain_by_join_key or valgrind warnings In this case we were using the optimization derived_with_keys but we could not create a key because the length of the key was greater than the max allowed(MI_MAX_KEY_LENGTH). To do the join we needed to create a hash join key instead, but in the explain output it showed that we were still referring to derived keys which were created but not used. --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 42b3420a9b6..d35a5a8094c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9513,7 +9513,7 @@ void JOIN::drop_unused_derived_keys() table->use_index(tab->ref.key); if (table->s->keys) { - if (tab->ref.key >= 0) + if (tab->ref.key >= 0 && tab->ref.key < MAX_KEY) tab->ref.key= 0; else table->s->keys= 0; -- cgit v1.2.1 From 204cb85aab3e6326e9f7a51c478efd6fad44801a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 20 Jan 2018 11:45:23 +0100 Subject: Fix compilation without dlopen --- sql/item_func.cc | 2 ++ sql/sql_plugin.cc | 5 +++++ 2 files changed, 7 insertions(+) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index 00006a25a8d..9e4edfc14de 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -595,6 +595,7 @@ my_decimal *Item_real_func::val_decimal(my_decimal *decimal_value) } +#ifdef HAVE_DLOPEN void Item_udf_func::fix_num_length_and_dec() { uint fl_length= 0; @@ -611,6 +612,7 @@ void Item_udf_func::fix_num_length_and_dec() max_length= float_length(NOT_FIXED_DEC); } } +#endif /** diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index d1e855e272e..ccefb04451c 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -477,6 +477,11 @@ static st_plugin_dl *plugin_dl_insert_or_reuse(struct st_plugin_dl *plugin_dl) sizeof(struct st_plugin_dl)); DBUG_RETURN(tmp); } +#else +static struct st_plugin_dl *plugin_dl_find(const LEX_STRING *) +{ + return 0; +} #endif /* HAVE_DLOPEN */ -- cgit v1.2.1 From 22ae3843db6c8b2a84ca5d16cd99025abb52cc27 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 20 Jan 2018 17:59:11 +0100 Subject: Correct TRASH() macro usage TRASH was mapped to TRASH_FREE and was supposed to be used for memory that should not be accessed anymore, while TRASH_ALLOC() is to be used for uninitialized but to-be-used memory. But sometimes TRASH() was used in the latter sense. Remove TRASH() macro, always use explicit TRASH_ALLOC() or TRASH_FREE(). --- sql/field.h | 2 +- sql/item.h | 2 +- sql/opt_range.cc | 2 +- sql/sql_cursor.cc | 2 +- sql/sql_lex.h | 4 ++-- sql/sql_lifo_buffer.h | 4 ++-- sql/sql_list.h | 4 ++-- sql/sql_plugin.cc | 2 +- sql/sql_select.cc | 2 +- sql/sql_show.cc | 2 +- sql/sql_string.h | 2 +- sql/sql_union.cc | 16 ---------------- sql/table.cc | 2 +- 13 files changed, 15 insertions(+), 31 deletions(-) (limited to 'sql') diff --git a/sql/field.h b/sql/field.h index f8fc7427618..d484b31d682 100644 --- a/sql/field.h +++ b/sql/field.h @@ -208,7 +208,7 @@ class Field public: static void *operator new(size_t size) throw () { return sql_alloc(size); } - static void operator delete(void *ptr_arg, size_t size) { TRASH(ptr_arg, size); } + static void operator delete(void *ptr_arg, size_t size) { TRASH_FREE(ptr_arg, size); } uchar *ptr; // Position to field in record /** diff --git a/sql/item.h b/sql/item.h index e01cf5384b9..4daca60f68e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -580,7 +580,7 @@ public: { return sql_alloc(size); } static void *operator new(size_t size, MEM_ROOT *mem_root) throw () { return alloc_root(mem_root, size); } - static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); } + static void operator delete(void *ptr,size_t size) { TRASH_FREE(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) {} enum Type {FIELD_ITEM= 0, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM, diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 25a9e729a8b..04ab8415dfe 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2651,7 +2651,7 @@ public: /* Table read plans are allocated on MEM_ROOT and are never deleted */ static void *operator new(size_t size, MEM_ROOT *mem_root) { return (void*) alloc_root(mem_root, (uint) size); } - static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); } + static void operator delete(void *ptr,size_t size) { TRASH_FREE(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) { /* Never called */ } virtual ~TABLE_READ_PLAN() {} /* Remove gcc warning */ diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index 230a8b2c802..f7ffd86fe83 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -187,7 +187,7 @@ void Server_side_cursor::operator delete(void *ptr, size_t size) MEM_ROOT own_root= *cursor->mem_root; DBUG_ENTER("Server_side_cursor::operator delete"); - TRASH(ptr, size); + TRASH_FREE(ptr, size); /* If this cursor has never been opened mem_root is empty. Otherwise mem_root points to the memory the cursor object was allocated in. diff --git a/sql/sql_lex.h b/sql/sql_lex.h index cf34c567626..57129cfedc7 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -548,7 +548,7 @@ public: } static void *operator new(size_t size, MEM_ROOT *mem_root) throw () { return (void*) alloc_root(mem_root, (uint) size); } - static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); } + static void operator delete(void *ptr,size_t size) { TRASH_FREE(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) {} // Ensures that at least all members used during cleanup() are initialized. @@ -2949,7 +2949,7 @@ struct st_lex_local: public LEX return (void*) alloc_root(mem_root, (uint) size); } static void operator delete(void *ptr,size_t size) - { TRASH(ptr, size); } + { TRASH_FREE(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) { /* Never called */ } }; diff --git a/sql/sql_lifo_buffer.h b/sql/sql_lifo_buffer.h index feec4aeb4c2..f551cc48c23 100644 --- a/sql/sql_lifo_buffer.h +++ b/sql/sql_lifo_buffer.h @@ -84,7 +84,7 @@ public: start= start_arg; end= end_arg; if (end != start) - TRASH(start, end - start); + TRASH_ALLOC(start, end - start); reset(); } @@ -224,7 +224,7 @@ public: { DBUG_ASSERT(unused_end >= unused_start); DBUG_ASSERT(end == unused_start); - TRASH(unused_start, unused_end - unused_start); + TRASH_ALLOC(unused_start, unused_end - unused_start); end= unused_end; } /* Return pointer to start of the memory area that is occupied by the data */ diff --git a/sql/sql_list.h b/sql/sql_list.h index 7538f69766d..08667bed02a 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -41,12 +41,12 @@ public: { return alloc_root(mem_root, size); } static void *operator new(size_t size, MEM_ROOT *mem_root) throw () { return alloc_root(mem_root, size); } - static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); } + static void operator delete(void *ptr, size_t size) { TRASH_FREE(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) { /* never called */ } static void operator delete[](void *ptr, MEM_ROOT *mem_root) { /* never called */ } - static void operator delete[](void *ptr, size_t size) { TRASH(ptr, size); } + static void operator delete[](void *ptr, size_t size) { TRASH_FREE(ptr, size); } #ifdef HAVE_valgrind bool dummy; inline Sql_alloc() :dummy(0) {} diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index ccefb04451c..e616b0a09e4 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -267,7 +267,7 @@ public: static void *operator new(size_t size, MEM_ROOT *mem_root) { return (void*) alloc_root(mem_root, size); } static void operator delete(void *ptr_arg,size_t size) - { TRASH(ptr_arg, size); } + { TRASH_FREE(ptr_arg, size); } sys_var_pluginvar(sys_var_chain *chain, const char *name_arg, struct st_mysql_sys_var *plugin_var_arg, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d35a5a8094c..f7624b2b56c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11530,7 +11530,7 @@ public: } static void operator delete(void *ptr __attribute__((unused)), size_t size __attribute__((unused))) - { TRASH(ptr, size); } + { TRASH_FREE(ptr, size); } Item *and_level; Item_func *cmp_func; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 8789f0c9f24..06d5a6f570a 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2111,7 +2111,7 @@ public: } static void operator delete(void *ptr __attribute__((unused)), size_t size __attribute__((unused))) - { TRASH(ptr, size); } + { TRASH_FREE(ptr, size); } ulong thread_id; time_t start_time; diff --git a/sql/sql_string.h b/sql/sql_string.h index 1fce3ae6c6f..3175a6616bf 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -102,7 +102,7 @@ public: { (void) ptr_arg; (void) size; - TRASH(ptr_arg, size); + TRASH_FREE(ptr_arg, size); } static void operator delete(void *, MEM_ROOT *) { /* never called */ } diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 2d816e0309d..bbb4133417e 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -935,22 +935,6 @@ bool st_select_lex_unit::cleanup() void st_select_lex_unit::reinit_exec_mechanism() { prepared= optimized= executed= 0; -#ifndef DBUG_OFF - if (is_union()) - { - List_iterator_fast it(item_list); - Item *field; - while ((field= it++)) - { - /* - we can't cleanup here, because it broke link to temporary table field, - but have to drop fixed flag to allow next fix_field of this field - during re-executing - */ - field->fixed= 0; - } - } -#endif } diff --git a/sql/table.cc b/sql/table.cc index 9cade76cb78..6795621b719 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3991,7 +3991,7 @@ void TABLE::init(THD *thd, TABLE_LIST *tl) DBUG_ASSERT(key_read == 0); /* mark the record[0] uninitialized */ - TRASH(record[0], s->reclength); + TRASH_ALLOC(record[0], s->reclength); /* Initialize the null marker bits, to ensure that if we are doing a read -- cgit v1.2.1 From 36eb0b7a558542689ad654a770c3f1ce8f18dd87 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 21 Jan 2018 12:50:49 +0100 Subject: improve ASAN instrumentation: table->record[0] instrument table->record[0], table->record[1] and share->default_values. One should not access record image beyond share->reclength, even if table->record[0] has some unused space after it (functions that work with records, might get a copy of the record as an argument, and that copy - not being record[0] - might not have this buffer space at the end). See b80fa4000d6 and 444587d8a3c --- sql/table.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/table.cc b/sql/table.cc index 6795621b719..5d73d7dffd2 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1269,9 +1269,10 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, extra_rec_buf_length= uint2korr(head+59); rec_buff_length= ALIGN_SIZE(share->reclength + 1 + extra_rec_buf_length); share->rec_buff_length= rec_buff_length; - if (!(record= (uchar *) alloc_root(&share->mem_root, - rec_buff_length))) + if (!(record= (uchar *) alloc_root(&share->mem_root, rec_buff_length))) goto err; /* purecov: inspected */ + MEM_NOACCESS(record, rec_buff_length); + MEM_UNDEFINED(record, share->reclength); share->default_values= record; if (mysql_file_pread(file, record, (size_t) share->reclength, record_offset, MYF(MY_NABP))) @@ -2430,6 +2431,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias, if (!(record= (uchar*) alloc_root(&outparam->mem_root, share->rec_buff_length * records))) goto err; /* purecov: inspected */ + MEM_NOACCESS(record, share->rec_buff_length * records); if (records == 0) { @@ -2444,6 +2446,8 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias, else outparam->record[1]= outparam->record[0]; // Safety } + MEM_UNDEFINED(outparam->record[0], share->reclength); + MEM_UNDEFINED(outparam->record[1], share->reclength); if (!(field_ptr = (Field **) alloc_root(&outparam->mem_root, (uint) ((share->fields+1)* -- cgit v1.2.1 From 6d826e3d7ee9af0af2b81d96b69edd6cf8d00423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Sun, 21 Jan 2018 13:12:33 +0200 Subject: Remove commented out code post merge fix in 2011 --- sql/sql_select.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f7624b2b56c..02a3f0590ac 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -696,12 +696,11 @@ JOIN::prepare(Item ***rref_pointer_array, } table_count= select_lex->leaf_tables.elements; - + TABLE_LIST *tbl; List_iterator_fast li(select_lex->leaf_tables); while ((tbl= li++)) { - //table_count++; /* Count the number of tables in the join. */ /* If the query uses implicit grouping where the select list contains both aggregate functions and non-aggregate fields, any non-aggregated field -- cgit v1.2.1 From b20c3dc664314a3045fa31e2245d4613e9efa508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Sun, 21 Jan 2018 21:18:57 +0200 Subject: MDEV-14715: Assertion `!table || (!table->read_set... failed in Field_num::val_decimal The assertion failure was caused by an incorrectly set read_set for functions in the ORDER BY clause in part of a union, when we are using a mergeable view and the order by clause can be skipped (removed). An order by clause can be skipped if it's part of one part of the UNION as the result set is not meaningful when multiple SELECT queries are UNIONed. The server is aware of this optimization and tries to remove the order by clause before JOIN::prepare. The problem is that we need to throw an error when the ORDER BY clause contains invalid columns. To do this, we attempt resolving the ORDER BY expressions, then subsequently drop them if resolution succeeded. However, ORDER BY resolution had the side effect of adding the expressions to the all_fields list, which is used to construct temporary tables to store the result. We may be ignoring the ORDER BY statement, but the tmp table still tried to compute the values for the expressions, even if the columns are never used. The assertion only shows itself if the order by clause contains members which were not previously in the select list, and are part of a function. There is an additional question as to why this only manifests when using VIEWS and not when using a regular table. The difference lies with the "reset" of the read_set for the temporary table during SELECT_LEX::update_used_tables() in JOIN::optimize(). The changes introduced in fdf789a7eadf864ecc0e617f25f795fafda55026 cleared the read_set when a mergeable view is encountered in the TABLE_LIST defintion. Upon initial order_list resolution, the table's read_set is updated correctly. JOIN::optimize() will only reset the read_set if it encounters a VIEW. Since we no longer have ORDER BY clause in JOIN::optimize() we never get to correctly update the read_set again. Other relevant commit by Timour, which first introduced the order resolution when we "can_skip_sort_order": 883af99e7dac91e3f258135a2053e6b8e3c05fc3 Solution: Don't add the resolved ORDER BY elements to all_fields. We only resolve them to check if an error should be returned for the query. Ignore them completely otherwise. --- sql/sql_select.cc | 32 ++++++++++++++++++++++++-------- sql/sql_select.h | 2 +- 2 files changed, 25 insertions(+), 9 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 02a3f0590ac..5db503cd266 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -279,6 +279,10 @@ enum enum_exec_or_opt {WALK_OPTIMIZATION_TABS , WALK_EXECUTION_TABS}; JOIN_TAB *first_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind); JOIN_TAB *next_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind, JOIN_TAB *tab); +static bool +find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, + ORDER *order, List &fields, List &all_fields, + bool is_group_field, bool add_to_all_fields); /** This handles SELECT with and without UNION. @@ -735,9 +739,15 @@ JOIN::prepare(Item ***rref_pointer_array, /* Resolve the ORDER BY that was skipped, then remove it. */ if (skip_order_by && select_lex != select_lex->master_unit()->global_parameters) { - if (setup_order(thd, (*rref_pointer_array), tables_list, fields_list, - all_fields, select_lex->order_list.first)) - DBUG_RETURN(-1); + thd->where= "order clause"; + for (ORDER *order= select_lex->order_list.first; order; order= order->next) + { + /* Don't add the order items to all fields. Just resolve them to ensure + the query is valid, we'll drop them immediately after. */ + if (find_order_in_list(thd, *rref_pointer_array, tables_list, order, + fields_list, all_fields, false, false)) + DBUG_RETURN(-1); + } select_lex->order_list.empty(); } @@ -20625,7 +20635,10 @@ cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref) SELECT list) @param[in,out] all_fields All select, group and order by fields @param[in] is_group_field True if order is a GROUP field, false if - ORDER by field + ORDER by field + @param[in] add_to_all_fields If the item is to be added to all_fields and + ref_pointer_array, this flag can be set to + false to stop the automatic insertion. @retval FALSE if OK @@ -20636,7 +20649,7 @@ cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref) static bool find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, ORDER *order, List &fields, List &all_fields, - bool is_group_field) + bool is_group_field, bool add_to_all_fields) { Item *order_item= *order->item; /* The item from the GROUP/ORDER caluse. */ Item::Type order_item_type; @@ -20755,6 +20768,9 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, thd->is_error())) return TRUE; /* Wrong field. */ + if (!add_to_all_fields) + return FALSE; + uint el= all_fields.elements; DBUG_ASSERT(all_fields.elements <= thd->lex->current_select->ref_pointer_array_size); @@ -20784,13 +20800,13 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, */ int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, - List &fields, List &all_fields, ORDER *order) + List &fields, List &all_fields, ORDER *order) { thd->where="order clause"; for (; order; order=order->next) { if (find_order_in_list(thd, ref_pointer_array, tables, order, fields, - all_fields, FALSE)) + all_fields, FALSE, true)) return 1; } return 0; @@ -20842,7 +20858,7 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, for (ord= order; ord; ord= ord->next) { if (find_order_in_list(thd, ref_pointer_array, tables, ord, fields, - all_fields, TRUE)) + all_fields, TRUE, true)) return 1; (*ord->item)->marker= UNDEF_POS; /* Mark found */ if ((*ord->item)->with_sum_func) diff --git a/sql/sql_select.h b/sql/sql_select.h index 1bc1e4c2b7a..e208377e275 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1757,7 +1757,7 @@ int get_quick_record(SQL_SELECT *select); SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length, SORT_FIELD *sortorder); int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, - List &fields, List &all_fields, ORDER *order); + List &fields, List &all_fields, ORDER *order); int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, List &fields, List &all_fields, ORDER *order, bool *hidden_group_fields); -- cgit v1.2.1 From 3532a421f6e272c739f4c435e80a354ba13da824 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 23 Jan 2018 11:57:54 +0300 Subject: fix build for recent clang /home/kevg/work/mariadb/sql/sql_partition.cc:286:47: error: cannot initialize a parameter of type 'HA_CREATE_INFO *' (aka 'st_ha_create_information *') with an rvalue of type 'ulonglong' (aka 'unsigned long long') (ulonglong)0, (uint)0); ^~~~~~~~~~~~ /home/kevg/work/mariadb/sql/partition_info.h:281:72: note: passing argument to parameter 'info' here bool set_up_defaults_for_partitioning(handler *file, HA_CREATE_INFO *info, ^ --- sql/sql_partition.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 01dcc7cc2ac..8e58c34162f 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -283,7 +283,7 @@ bool partition_default_handling(TABLE *table, partition_info *part_info, } } part_info->set_up_defaults_for_partitioning(table->file, - (ulonglong)0, (uint)0); + NULL, (uint)0); DBUG_RETURN(FALSE); } -- cgit v1.2.1 From 701c7e777ff707085337c01f0a49d0daa8635c06 Mon Sep 17 00:00:00 2001 From: Karim Geiger Date: Tue, 23 Jan 2018 11:56:52 +0100 Subject: Fix error message typo --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3d2de3126ff..c78f2ffd94f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3461,7 +3461,7 @@ static int init_common_variables() /* TODO: remove this when my_time_t is 64 bit compatible */ if (!IS_TIME_T_VALID_FOR_TIMESTAMP(server_start_time)) { - sql_print_error("This MySQL server doesn't support dates later then 2038"); + sql_print_error("This MySQL server doesn't support dates later than 2038"); return 1; } -- cgit v1.2.1 From 94da1cb4a67ecb2e2590748381eebac072308ce6 Mon Sep 17 00:00:00 2001 From: Sachin Setiya Date: Tue, 23 Jan 2018 15:47:54 +0530 Subject: MDEV-14586 Assertion `0' failed in retrieve_auto_increment ... Problem:- If we create table using myisam/aria then this crashes the server. CREATE TABLE t1(a bit(1), b int auto_increment , index(a,b)); insert into t1 values(1,1); Or this query CREATE TABLE t1 (b BIT(1), pk INTEGER AUTO_INCREMENT PRIMARY KEY); ALTER TABLE t1 ADD INDEX(b,pk); INSERT INTO t1 VALUES (1,b'1'); ALTER TABLE t1 DROP PRIMARY KEY; Reason:- The reason for this is 1st- find_ref_key() finds what key an auto_increment field belongs to by comparing key_part->offset and field->ptr. But BIT fields might have zero length in the record, so a key might have many key parts with the same offset. That is, comparing offsets cannot uniquely identify the correct key part. 2nd- Since next_number_key_offset is zero it myisam/aria will think that auto_increment is in first part of key. 3nd- myisam/aria will call retrieve_auto_key which will see first key_part field as a bit field and call assert(0) Solution:- Many key parts might have the same offset, but BIT fields do not support auto_increment. So, we can skip all key parts over BIT fields, and then comparing offsets will be unambiguous. --- sql/key.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/key.cc b/sql/key.cc index 110b13000ed..700bf6a05a6 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -62,7 +62,8 @@ int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field, i < (int) key_count ; i++, key_info++) { - if (key_info->key_part[0].offset == fieldpos) + if (key_info->key_part[0].offset == fieldpos && + key_info->key_part[0].field->type() != MYSQL_TYPE_BIT) { /* Found key. Calc keylength */ *key_length= *keypart= 0; return i; /* Use this key */ @@ -81,7 +82,8 @@ int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field, j < key_info->key_parts ; j++, key_part++) { - if (key_part->offset == fieldpos) + if (key_part->offset == fieldpos && + key_part->field->type() != MYSQL_TYPE_BIT) { *keypart= j; return i; /* Use this key */ -- cgit v1.2.1 From 11408a69adc6749c855a9867fc4db3e3d45236c3 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Sun, 21 Jan 2018 23:44:31 +0100 Subject: Fix Item tree changes/rollback debug print --- sql/sql_class.cc | 8 ++++---- sql/sql_class.h | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index b007729494e..c88c13b9524 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2234,6 +2234,9 @@ void THD::check_and_register_item_tree_change(Item **place, Item **new_value, MEM_ROOT *runtime_memroot) { Item_change_record *change; + DBUG_ENTER("THD::check_and_register_item_tree_change"); + DBUG_PRINT("enter", ("Register: %p (%p) <- %p (%p)", + *place, place, *new_value, new_value)); I_List_iterator it(change_list); while ((change= it++)) { @@ -2243,6 +2246,7 @@ void THD::check_and_register_item_tree_change(Item **place, Item **new_value, if (change) nocheck_register_item_tree_change(place, change->old_value, runtime_memroot); + DBUG_VOID_RETURN; } @@ -2250,17 +2254,13 @@ void THD::rollback_item_tree_changes() { I_List_iterator it(change_list); Item_change_record *change; - DBUG_ENTER("rollback_item_tree_changes"); while ((change= it++)) { - DBUG_PRINT("info", ("revert %p -> %p", - change->old_value, (*change->place))); *change->place= change->old_value; } /* We can forget about changes memory: it's allocated in runtime memroot */ change_list.empty(); - DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index e8f50f13ebc..bff7492ffec 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2725,10 +2725,14 @@ public: void change_item_tree(Item **place, Item *new_value) { + DBUG_ENTER("THD::change_item_tree"); + DBUG_PRINT("enter", ("Register: %p (%p) <- %p", + *place, place, new_value)); /* TODO: check for OOM condition here */ if (!stmt_arena->is_conventional()) nocheck_register_item_tree_change(place, *place, mem_root); *place= new_value; + DBUG_VOID_RETURN; } /** Make change in item tree after checking whether it needs registering -- cgit v1.2.1 From ba8d0fa700a73893979793785ed53f7bbd950df8 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Mon, 15 Jan 2018 14:50:35 +0100 Subject: MDEV-14786: Server crashes in Item_cond::transform on 2nd execution of SP querying from a view MDEV-14957: JOIN::prepare gets unusable "conds" as argument Do not touch merged derived (it is irreversible) Fix first argument of in_optimizer for calls possible before fix_fields() --- sql/item.cc | 2 +- sql/item.h | 6 ++++++ sql/item_cmpfunc.cc | 34 ++++++++++++++++++++++++++++++++++ sql/item_cmpfunc.h | 2 ++ sql/sql_derived.cc | 20 ++++++++++++++++++++ sql/sql_select.cc | 3 +++ 6 files changed, 66 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 576dce78299..08a00615c0c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -10010,7 +10010,7 @@ const char *dbug_print_item(Item *item) if (!item) return "(Item*)NULL"; item->print(&str ,QT_ORDINARY); - if (str.c_ptr() == buf) + if (str.c_ptr_safe() == buf) return buf; else return "Couldn't fit into buffer"; diff --git a/sql/item.h b/sql/item.h index 4daca60f68e..830f8bf14a4 100644 --- a/sql/item.h +++ b/sql/item.h @@ -50,6 +50,12 @@ bool trace_unsupported_by_check_vcol_func_processor(const char *where) return trace_unsupported_func(where, "check_vcol_func_processor"); } +#ifdef DBUG_OFF +static inline const char *dbug_print_item(Item *item) { return NULL; } +#else +extern const char *dbug_print_item(Item *item); +#endif + class Protocol; struct TABLE_LIST; void item_init(void); /* Init item functions */ diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 62e76922c0e..a77443f40ef 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1420,6 +1420,7 @@ bool Item_in_optimizer::is_top_level_item() void Item_in_optimizer::fix_after_pullout(st_select_lex *new_parent, Item **ref) { + DBUG_ASSERT(fixed); /* This will re-calculate attributes of our Item_in_subselect: */ Item_bool_func::fix_after_pullout(new_parent, ref); @@ -1443,6 +1444,33 @@ bool Item_in_optimizer::eval_not_null_tables(uchar *opt_arg) } +void Item_in_optimizer::print(String *str, enum_query_type query_type) +{ + restore_first_argumet(); + Item_func::print(str, query_type); +} + + +/** + "Restore" first argument before fix_fields() call (after it is harmless). + + @Note: Main pointer to left part of IN/ALL/ANY subselect is subselect's + lest_expr (see Item_in_optimizer::fix_left) so changes made during + fix_fields will be rolled back there which can make + Item_in_optimizer::args[0] unusable on second execution before fix_left() + call. This call fix the pointer. +*/ + +void Item_in_optimizer::restore_first_argumet() +{ + if (args[1]->type() == Item::SUBSELECT_ITEM && + ((Item_subselect *)args[1])->is_in_predicate()) + { + args[0]= ((Item_in_subselect *)args[1])->left_expr; + } +} + + bool Item_in_optimizer::fix_left(THD *thd, Item **ref) { DBUG_ENTER("Item_in_optimizer::fix_left"); @@ -1588,6 +1616,8 @@ Item *Item_in_optimizer::expr_cache_insert_transformer(uchar *thd_arg) { THD *thd= (THD*) thd_arg; DBUG_ENTER("Item_in_optimizer::expr_cache_insert_transformer"); + DBUG_ASSERT(fixed); + if (args[1]->type() != Item::SUBSELECT_ITEM) DBUG_RETURN(this); // MAX/MIN transformed => do nothing @@ -1611,6 +1641,7 @@ Item *Item_in_optimizer::expr_cache_insert_transformer(uchar *thd_arg) void Item_in_optimizer::get_cache_parameters(List ¶meters) { + DBUG_ASSERT(fixed); /* Add left expression to the list of the parameters of the subquery */ if (args[0]->cols() == 1) parameters.add_unique(args[0], &cmp_items); @@ -1842,6 +1873,7 @@ Item *Item_in_optimizer::transform(Item_transformer transformer, uchar *argument { Item *new_item; + DBUG_ASSERT(fixed); DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare()); DBUG_ASSERT(arg_count == 2); @@ -1893,6 +1925,7 @@ Item *Item_in_optimizer::transform(Item_transformer transformer, uchar *argument bool Item_in_optimizer::is_expensive_processor(uchar *arg) { + DBUG_ASSERT(fixed); return args[0]->is_expensive_processor(arg) || args[1]->is_expensive_processor(arg); } @@ -1900,6 +1933,7 @@ bool Item_in_optimizer::is_expensive_processor(uchar *arg) bool Item_in_optimizer::is_expensive() { + DBUG_ASSERT(fixed); return args[0]->is_expensive() || args[1]->is_expensive(); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 7b7ca9223fd..c0e97be20c4 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -268,6 +268,8 @@ public: bool is_top_level_item(); bool eval_not_null_tables(uchar *opt_arg); void fix_after_pullout(st_select_lex *new_parent, Item **ref); + virtual void print(String *str, enum_query_type query_type); + void restore_first_argumet(); }; class Comp_creator diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 2a6d82c161a..2e947ecba16 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -366,7 +366,11 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) derived->get_unit())); if (derived->merged) + { + + DBUG_PRINT("info", ("Irreversibly merged: exit")); DBUG_RETURN(FALSE); + } if (dt_select->uncacheable & UNCACHEABLE_RAND) { @@ -667,6 +671,17 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) unit->derived= derived; + /* + Above cascade call of prepare is important for PS protocol, but after it + is called we can check if we really need prepare for this derived + */ + if (derived->merged) + { + DBUG_PRINT("info", ("Irreversibly merged: exit")); + DBUG_RETURN(FALSE); + } + + derived->fill_me= FALSE; if (!(derived->derived_result= new select_union)) @@ -795,6 +810,11 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived) DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", (derived->alias ? derived->alias : ""), derived->get_unit())); + if (derived->merged) + { + DBUG_PRINT("info", ("Irreversibly merged: exit")); + DBUG_RETURN(FALSE); + } if (unit->optimized) DBUG_RETURN(FALSE); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5db503cd266..90bb536c0e2 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -638,6 +638,9 @@ JOIN::prepare(Item ***rref_pointer_array, join_list= &select_lex->top_join_list; union_part= unit_arg->is_union(); + // simple check that we got usable conds + dbug_print_item(conds); + if (select_lex->handle_derived(thd->lex, DT_PREPARE)) DBUG_RETURN(1); -- cgit v1.2.1 From b3c7cf81e3578fef828aa749de4c75258c3fbd76 Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 23 Jan 2018 19:21:44 +0200 Subject: Fix for MDEV-14141 Crash in print_keydup_error() May also fix: MDEV-14970 "MariaDB crashed with signal 11 and Aria table" I am not able to reproduce a crash, however there was no protection in print_keydup_error() if the storage engine reported the wrong key number. This patch adds such a protection and should stop any further crashes in this case. Other things: - Added extra protection in Aria to not set errkey to more than number of keys. (Don't think this is cause of this crash, but better safe than sorry) - Extend test_if_equal_repl_errors() to handle different cases of ER_DUP_ENTRY. This is just mainly precaution for the future. --- sql/handler.cc | 14 +++++++------- sql/log_event.cc | 7 ++++++- sql/sql_table.cc | 7 ++++--- 3 files changed, 17 insertions(+), 11 deletions(-) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index 174034a7eb5..07dc0cf04a9 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3338,9 +3338,11 @@ void print_keydup_error(TABLE *table, KEY *key, const char *msg, myf errflag) if (key == NULL) { - /* Key is unknown */ - str.copy("", 0, system_charset_info); - my_printf_error(ER_DUP_ENTRY, msg, errflag, str.c_ptr(), "*UNKNOWN*"); + /* + Key is unknown. Should only happen if storage engine reports wrong + duplicate key number. + */ + my_printf_error(ER_DUP_ENTRY, msg, errflag, "", "*UNKNOWN*"); } else { @@ -3432,11 +3434,9 @@ void handler::print_error(int error, myf errflag) if (table) { uint key_nr=get_dup_key(error); - if ((int) key_nr >= 0) + if ((int) key_nr >= 0 && key_nr < table->s->keys) { - print_keydup_error(table, - key_nr == MAX_KEY ? NULL : &table->key_info[key_nr], - errflag); + print_keydup_error(table, &table->key_info[key_nr], errflag); DBUG_VOID_RETURN; } } diff --git a/sql/log_event.cc b/sql/log_event.cc index b66ceac72bf..dcccdb2527f 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4075,8 +4075,13 @@ bool test_if_equal_repl_errors(int expected_error, int actual_error) return 1; switch (expected_error) { case ER_DUP_ENTRY: + case ER_DUP_ENTRY_WITH_KEY_NAME: + case ER_DUP_KEY: case ER_AUTOINC_READ_FAILED: - return (actual_error == ER_AUTOINC_READ_FAILED || + return (actual_error == ER_DUP_ENTRY || + actual_error == ER_DUP_ENTRY_WITH_KEY_NAME || + actual_error == ER_DUP_KEY || + actual_error == ER_AUTOINC_READ_FAILED || actual_error == HA_ERR_AUTOINC_ERANGE); case ER_UNKNOWN_TABLE: return actual_error == ER_IT_IS_A_VIEW; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7d37c559e20..2d346a64613 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9612,12 +9612,13 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, if ((int) key_nr >= 0) { const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME); - if (key_nr == 0 && + if (key_nr == 0 && to->s->keys > 0 && (to->key_info[0].key_part[0].field->flags & AUTO_INCREMENT_FLAG)) err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE); - print_keydup_error(to, key_nr == MAX_KEY ? NULL : - &to->key_info[key_nr], + print_keydup_error(to, + key_nr >= to->s->keys ? NULL : + &to->key_info[key_nr], err_msg, MYF(0)); } else -- cgit v1.2.1 From d0acfa458ef10ef46afee7ca81bfad3064026d38 Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 23 Jan 2018 23:48:57 +0200 Subject: MDEV-14245 tokudb_alter_table.drop_add_pk_part_104 fails "tokudb_alter_table.drop_add_pk_part_104 leaves a temporary file behind" Fixed by copying 3 lines from 10.1 to 10.0 that cleaned up the temporary file for partitioning tables. --- sql/sql_table.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2d346a64613..46705827e41 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -8840,7 +8840,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, TODO don't create the frm in the first place */ - deletefrm(alter_ctx.get_tmp_path()); + const char *path= alter_ctx.get_tmp_path(); + table->file->ha_create_partitioning_metadata(path, NULL, CHF_DELETE_FLAG); + deletefrm(path); my_free(const_cast(frm.str)); goto end_inplace; } -- cgit v1.2.1 From e431d90065d277e62fa4f81a1654790f58a84146 Mon Sep 17 00:00:00 2001 From: Ian Gilfillan Date: Wed, 24 Jan 2018 09:57:18 +0200 Subject: Update sponsors --- sql/contributors.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/contributors.h b/sql/contributors.h index 88a4a088acf..7369dcd141d 100644 --- a/sql/contributors.h +++ b/sql/contributors.h @@ -38,8 +38,9 @@ struct show_table_contributors_st { struct show_table_contributors_st show_table_contributors[]= { /* MariaDB foundation sponsors, in contribution, size , time order */ {"Booking.com", "https://www.booking.com", "Founding member, Platinum Sponsor of the MariaDB Foundation"}, - {"Alibaba Cloud", "https://intl.aliyun.com", "Platinum Sponsor of the MariaDB Foundation"}, + {"Alibaba Cloud", "https://www.alibabacloud.com/", "Platinum Sponsor of the MariaDB Foundation"}, {"Tencent Cloud", "https://cloud.tencent.com", "Platinum Sponsor of the MariaDB Foundation"}, + {"Microsoft", "https://microsoft.com/", "Platinum Sponsor of the MariaDB Foundation"}, {"MariaDB Corporation", "https://mariadb.com", "Founding member, Gold Sponsor of the MariaDB Foundation"}, {"Visma", "https://visma.com", "Gold Sponsor of the MariaDB Foundation"}, {"DBS", "https://dbs.com", "Gold Sponsor of the MariaDB Foundation"}, -- cgit v1.2.1 From 76577e1e2602f3c30859a176808c433a263e1b0a Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 24 Jan 2018 10:58:27 +0100 Subject: typo fix --- sql/item_cmpfunc.cc | 4 ++-- sql/item_cmpfunc.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index a77443f40ef..39f497e3828 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1446,7 +1446,7 @@ bool Item_in_optimizer::eval_not_null_tables(uchar *opt_arg) void Item_in_optimizer::print(String *str, enum_query_type query_type) { - restore_first_argumet(); + restore_first_argument(); Item_func::print(str, query_type); } @@ -1461,7 +1461,7 @@ void Item_in_optimizer::print(String *str, enum_query_type query_type) call. This call fix the pointer. */ -void Item_in_optimizer::restore_first_argumet() +void Item_in_optimizer::restore_first_argument() { if (args[1]->type() == Item::SUBSELECT_ITEM && ((Item_subselect *)args[1])->is_in_predicate()) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index c0e97be20c4..a045a08e4fd 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -269,7 +269,7 @@ public: bool eval_not_null_tables(uchar *opt_arg); void fix_after_pullout(st_select_lex *new_parent, Item **ref); virtual void print(String *str, enum_query_type query_type); - void restore_first_argumet(); + void restore_first_argument(); }; class Comp_creator -- cgit v1.2.1 From ee8755e3c51a1da8fcf108ad0257a7e62fc94347 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 24 Jan 2018 14:42:52 +0100 Subject: MDEV-15012: ASAN: numerous test failures in PS First roll back changes, then free Items which can lead to memory freeing. --- sql/sql_prepare.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index faaeaf51573..a3bf9d6c93c 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -3230,9 +3230,9 @@ void Prepared_statement::cleanup_stmt() DBUG_ENTER("Prepared_statement::cleanup_stmt"); DBUG_PRINT("enter",("stmt: 0x%lx", (long) this)); + thd->rollback_item_tree_changes(); cleanup_items(free_list); thd->cleanup_after_query(); - thd->rollback_item_tree_changes(); DBUG_VOID_RETURN; } -- cgit v1.2.1 From a0702dbcda0c4495345d6dda6738cc77d823e325 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 23 Jan 2018 11:24:53 +0100 Subject: MDEV-11539 test_if_reopen: Assertion `strcmp(share->unique_file_name,filename) || share->last_version' failed upon select from I_S remove HA_EXTRA_PREPARE_FOR_RENAME - neither OPTIMIZE nor REPAIR need it (was introduced in b58e79566c5 when replacing remove_table_from_cache() with wait_while_table_is_used() even though remove_table_from_cache() did not have it). --- sql/sql_admin.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index a3e13fe0e5a..3aac41d6e41 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -638,8 +638,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, */ if (lock_type == TL_WRITE && !table->table->s->tmp_table) { - if (wait_while_table_is_used(thd, table->table, - HA_EXTRA_PREPARE_FOR_RENAME)) + if (wait_while_table_is_used(thd, table->table, HA_EXTRA_NOT_USED)) goto err; DEBUG_SYNC(thd, "after_admin_flush"); /* Flush entries in the query cache involving this table. */ -- cgit v1.2.1 From dae4fb0acb373e653f826f0ec7bdaf2485ef0b93 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 30 Jan 2018 11:07:35 +0400 Subject: MDEV-15118 ExtractValue(xml,something_complex) does not work Item_xml_str_func::fix_fields() used a local "String tmp" as a buffer for args[1]->val_str(). "tmp" was freed at the end of fix_fields(), while Items created during my_xpath_parse() still pointed to its fragments. Adding a new member Item_xml_str_func::m_xpath_query and store the result of args[1]->val_str() into it. --- sql/item_xmlfunc.cc | 10 ++++++++-- sql/item_xmlfunc.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index c7fd923b0ae..c12f5fd3e87 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -2634,7 +2634,7 @@ void Item_xml_str_func::fix_length_and_dec() bool Item_xml_str_func::fix_fields(THD *thd, Item **ref) { - String *xp, tmp; + String *xp; MY_XPATH xpath; int rc; @@ -2662,7 +2662,13 @@ bool Item_xml_str_func::fix_fields(THD *thd, Item **ref) return true; } - if (!(xp= args[1]->val_str(&tmp))) + /* + Get the XPath query text from args[1] and cache it in m_xpath_query. + Its fragments will be referenced by items created during my_xpath_parse(), + e.g. by Item_nodeset_func_axisbyname::node_name. + */ + if (!(xp= args[1]->val_str(&m_xpath_query)) || + (xp != &m_xpath_query && m_xpath_query.copy(*xp))) return false; // Will return NULL my_xpath_init(&xpath); xpath.cs= collation.collation; diff --git a/sql/item_xmlfunc.h b/sql/item_xmlfunc.h index 637f505e12e..e0356d367bd 100644 --- a/sql/item_xmlfunc.h +++ b/sql/item_xmlfunc.h @@ -67,6 +67,7 @@ protected: return parse(res, cache); } }; + String m_xpath_query; // XPath query text Item *nodeset_func; XML xml; bool get_xml(XML *xml, bool cache= false) -- cgit v1.2.1 From c4a908cb56d3ed81879573631d1f180d4962ed4e Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 30 Jan 2018 11:35:27 +0400 Subject: MDEV-13790 UNHEX() of a somewhat complicated CONCAT() returns NULL --- sql/item_strfunc.cc | 180 ++++++++++++++++++---------------------------------- sql/item_strfunc.h | 1 + 2 files changed, 64 insertions(+), 117 deletions(-) (limited to 'sql') diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index c0d60d7ef8b..378f23f3109 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -630,138 +630,84 @@ String *Item_func_decode_histogram::val_str(String *str) /////////////////////////////////////////////////////////////////////////////// +/* + Realloc the result buffer. + NOTE: We should be prudent in the initial allocation unit -- the + size of the arguments is a function of data distribution, which + can be any. Instead of overcommitting at the first row, we grow + the allocated amount by the factor of 2. This ensures that no + more than 25% of memory will be overcommitted on average. + + @param IN/OUT str - the result string + @param IN length - new total space required in "str" + @retval false - on success + @retval true - on error +*/ + +bool Item_func_concat::realloc_result(String *str, uint length) const +{ + if (str->alloced_length() >= length) + return false; // Alloced space is big enough, nothing to do. + + if (str->alloced_length() == 0) + return str->alloc(length); + + /* + Item_func_concat::val_str() makes sure the result length does not grow + higher than max_allowed_packet. So "length" is limited to 1G here. + We can't say anything about the current value of str->alloced_length(), + as str was initially set by args[0]->val_str(str). + So multiplication by 2 can overflow, if args[0] for some reasons + did not limit the result to max_alloced_packet. But it's not harmful, + "str" will be realloced exactly to "length" bytes in case of overflow. + */ + uint new_length= MY_MAX(str->alloced_length() * 2, length); + return str->realloc(new_length); +} + + /** Concatenate args with the following premises: If only one arg (which is ok), return value of arg; - Don't reallocate val_str() if not absolute necessary. */ String *Item_func_concat::val_str(String *str) { DBUG_ASSERT(fixed == 1); - String *res,*res2,*use_as_buff; - uint i; - bool is_const= 0; + THD *thd= current_thd; + String *res; null_value=0; - if (!(res=args[0]->val_str(str))) + if (!(res= args[0]->val_str(str))) goto null; - use_as_buff= &tmp_value; - /* Item_subselect in --ps-protocol mode will state it as a non-const */ - is_const= args[0]->const_item() || !args[0]->used_tables(); - for (i=1 ; i < arg_count ; i++) - { - if (res->length() == 0) - { - if (!(res=args[i]->val_str(str))) - goto null; - /* - CONCAT accumulates its result in the result of its the first - non-empty argument. Because of this we need is_const to be - evaluated only for it. - */ - is_const= args[i]->const_item() || !args[i]->used_tables(); - } - else - { - if (!(res2=args[i]->val_str(use_as_buff))) - goto null; - if (res2->length() == 0) - continue; - if (res->length()+res2->length() > - current_thd->variables.max_allowed_packet) - { - push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, - ER_WARN_ALLOWED_PACKET_OVERFLOWED, - ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(), - current_thd->variables.max_allowed_packet); - goto null; - } - if (!is_const && res->alloced_length() >= res->length()+res2->length()) - { // Use old buffer - res->append(*res2); - } - else if (str->alloced_length() >= res->length()+res2->length()) - { - if (str->ptr() == res2->ptr()) - str->replace(0,0,*res); - else - { - str->copy(*res); - str->append(*res2); - } - res= str; - use_as_buff= &tmp_value; - } - else if (res == &tmp_value) - { - if (res->append(*res2)) // Must be a blob - goto null; - } - else if (res2 == &tmp_value) - { // This can happend only 1 time - if (tmp_value.replace(0,0,*res)) - goto null; - res= &tmp_value; - use_as_buff=str; // Put next arg here - } - else if (tmp_value.is_alloced() && res2->ptr() >= tmp_value.ptr() && - res2->ptr() <= tmp_value.ptr() + tmp_value.alloced_length()) - { - /* - This happens really seldom: - In this case res2 is sub string of tmp_value. We will - now work in place in tmp_value to set it to res | res2 - */ - /* Chop the last characters in tmp_value that isn't in res2 */ - tmp_value.length((uint32) (res2->ptr() - tmp_value.ptr()) + - res2->length()); - /* Place res2 at start of tmp_value, remove chars before res2 */ - if (tmp_value.replace(0,(uint32) (res2->ptr() - tmp_value.ptr()), - *res)) - goto null; - res= &tmp_value; - use_as_buff=str; // Put next arg here - } - else - { // Two big const strings - /* - NOTE: We should be prudent in the initial allocation unit -- the - size of the arguments is a function of data distribution, which - can be any. Instead of overcommitting at the first row, we grow - the allocated amount by the factor of 2. This ensures that no - more than 25% of memory will be overcommitted on average. - */ - - uint concat_len= res->length() + res2->length(); - - if (tmp_value.alloced_length() < concat_len) - { - if (tmp_value.alloced_length() == 0) - { - if (tmp_value.alloc(concat_len)) - goto null; - } - else - { - uint new_len = MY_MAX(tmp_value.alloced_length() * 2, concat_len); - if (tmp_value.realloc(new_len)) - goto null; - } - } + if (res != str) + str->copy(res->ptr(), res->length(), res->charset()); - if (tmp_value.copy(*res) || tmp_value.append(*res2)) - goto null; - - res= &tmp_value; - use_as_buff=str; - } - is_const= 0; + for (uint i= 1 ; i < arg_count ; i++) + { + uint concat_len; + if (!(res= args[i]->val_str(&tmp_value))) + goto null; + if (res->length() == 0) + continue; + if ((concat_len= str->length() + res->length()) > + thd->variables.max_allowed_packet) + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_WARN_ALLOWED_PACKET_OVERFLOWED, + ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(), + thd->variables.max_allowed_packet); + goto null; } + DBUG_ASSERT(!res->uses_buffer_owned_by(str)); + DBUG_ASSERT(!str->uses_buffer_owned_by(res)); + if (realloc_result(str, concat_len) || str->append(*res)) + goto null; } - res->set_charset(collation.collation); - return res; + + str->set_charset(collation.collation); + return str; null: null_value=1; diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index aa3486d4e73..12c348aa9fa 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -156,6 +156,7 @@ public: class Item_func_concat :public Item_str_func { String tmp_value; + bool realloc_result(String *str, uint length) const; public: Item_func_concat(List &list) :Item_str_func(list) {} Item_func_concat(Item *a,Item *b) :Item_str_func(a,b) {} -- cgit v1.2.1 From 6b4a4a85a7f42ba8d47bde2a879066a54b3ca798 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 30 Jan 2018 11:28:21 +0400 Subject: MDEV-14696 Server crashes in in prep_alter_part_table on 2nd execution of PS. The thd->lex->part_info should be kept intact during PS execution. Or the second execution gets that modified part_info. Let's modify ths->work_part_info instead. --- sql/sql_partition.cc | 7 ++++++- sql/sql_table.cc | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index dd1f60ec078..1c270521a12 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4713,7 +4713,12 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, DBUG_RETURN(TRUE); } - thd->work_part_info= thd->lex->part_info; + /* + One of these is done in handle_if_exists_option(): + thd->work_part_info= thd->lex->part_info; + or + thd->work_part_info= NULL; + */ if (thd->work_part_info && !(thd->work_part_info= thd->work_part_info->get_clone())) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index bb745f41d26..be5906ec8e6 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5997,6 +5997,7 @@ remove_key_no_warn: #ifdef WITH_PARTITION_STORAGE_ENGINE partition_info *tab_part_info= table->part_info; + thd->work_part_info= thd->lex->part_info; if (tab_part_info && thd->lex->check_exists) { /* ALTER TABLE ADD PARTITION IF NOT EXISTS */ @@ -6015,7 +6016,7 @@ remove_key_no_warn: ER_SAME_NAME_PARTITION, ER(ER_SAME_NAME_PARTITION), pe->partition_name); alter_info->flags&= ~Alter_info::ALTER_ADD_PARTITION; - thd->lex->part_info= NULL; + thd->work_part_info= NULL; break; } } -- cgit v1.2.1 From ded07724eebb6c3afe882884fbad32e8dc907b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Mon, 29 Jan 2018 19:46:59 +0200 Subject: MDEV-15014 Assertion `m_cache_lock_status == LOCKED_NO_WAIT || m_cache_status == DISABLE_REQUEST' failed in Query_cache::free_cache on startup The assert guards against not-locked or not-requested query cache disabling. If during startup we disable query cache, we failed to request disabling. --- sql/sql_cache.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 3fc1edfcb56..6effc376a2f 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -2477,6 +2477,7 @@ void Query_cache::init() */ if (global_system_variables.query_cache_type == 0) { + m_cache_status= DISABLE_REQUEST; free_cache(); m_cache_status= DISABLED; } -- cgit v1.2.1 From 5edd129fbf14eb56e793f84963b3b9e5770c4604 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Tue, 30 Jan 2018 21:05:27 +0200 Subject: Fix ASAN failure in main.lock (and others) Whenever one copies an IO_CACHE struct, one must remember to call setup_io_cache, if not, the IO_CACHE's current_pos and end_pos self-references will point to the previous struct's memory, which could go out of scope. Commit 90038693903044bbbf7946ac128c3757ad33d7ba fixes this problem in a more general fashion by removing the self-references altogether, but for 5.5 we'll keep the old behaviour. --- sql/sql_update.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/sql_update.cc b/sql/sql_update.cc index ede38468513..e42f6a4ff76 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -628,6 +628,8 @@ int mysql_update(THD *thd, if (reinit_io_cache(&tempfile,READ_CACHE,0L,0,0)) error=1; /* purecov: inspected */ select->file=tempfile; // Read row ptrs from this file + // select->file was copied, update self-references. + setup_io_cache(&select->file); if (error >= 0) goto err; } -- cgit v1.2.1 From d6638586c6363fd7b914ea4d2d5e6276659e0e2a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 31 Jan 2018 20:22:31 +0100 Subject: don't crash debug builds on "packets out of order" only do it in EXTRA_DEBUG builds --- sql/net_serv.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 90a5da6a927..225b6d9542e 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -58,9 +58,11 @@ #ifdef EXTRA_DEBUG #define EXTRA_DEBUG_fprintf fprintf #define EXTRA_DEBUG_fflush fflush +#define EXTRA_DEBUG_ASSERT DBUG_ASSERT #else static void inline EXTRA_DEBUG_fprintf(...) {} static int inline EXTRA_DEBUG_fflush(...) { return 0; } +#define EXTRA_DEBUG_ASSERT(X) do {} while(0) #endif #ifdef MYSQL_SERVER #define MYSQL_SERVER_my_error my_error @@ -1071,7 +1073,7 @@ packets_out_of_order: ("Packets out of order (Found: %d, expected %u)", (int) net->buff[net->where_b + 3], net->pkt_nr)); - DBUG_ASSERT(0); + EXTRA_DEBUG_ASSERT(0); /* We don't make noise server side, since the client is expected to break the protocol for e.g. --send LOAD DATA .. LOCAL where -- cgit v1.2.1 From 80d3eee072025f34984e474ea160651eac9e11e5 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Fri, 26 Jan 2018 16:59:53 +0100 Subject: MDEV-14857: problem with 10.2.11 server crashing when executing stored procedure Counter for select numbering made stored with the statement (before was global) So now it does have always accurate value which does not depend on interruption of statement prepare by errors like lack of table in a view definition. --- sql/sp.cc | 1 - sql/sp_head.cc | 35 +++++++---------------------------- sql/sp_head.h | 3 --- sql/sql_class.cc | 2 +- sql/sql_class.h | 16 +++++++++++++++- sql/sql_explain.h | 6 ++++++ sql/sql_lex.cc | 2 ++ sql/sql_lex.h | 10 ++++++++-- sql/sql_parse.cc | 9 +++++++-- sql/sql_prepare.cc | 18 +----------------- sql/sql_select.cc | 16 ++++++++++++++++ sql/sql_trigger.cc | 7 +++++-- sql/sql_view.cc | 7 +------ 13 files changed, 69 insertions(+), 63 deletions(-) (limited to 'sql') diff --git a/sql/sp.cc b/sql/sp.cc index 5a64c28865e..2e268e483e7 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -760,7 +760,6 @@ static sp_head *sp_compile(THD *thd, String *defstr, ulonglong sql_mode, else { sp= thd->lex->sphead; - sp->set_select_number(thd->select_number); } thd->pop_internal_handler(); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index eceebd1d13f..8bf78d97670 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -597,7 +597,7 @@ sp_head::sp_head() m_flags(0), m_sp_cache_version(0), m_creation_ctx(0), - unsafe_flags(0), m_select_number(1), + unsafe_flags(0), m_recursion_level(0), m_next_cached_sp(0), m_cont_level(0) @@ -840,7 +840,7 @@ sp_head::~sp_head() thd->lex->sphead= NULL; lex_end(thd->lex); delete thd->lex; - thd->lex= lex; + thd->lex= thd->stmt_lex= lex; } my_hash_free(&m_sptabs); @@ -1121,7 +1121,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) backup_arena; query_id_t old_query_id; TABLE *old_derived_tables; - LEX *old_lex; + LEX *old_lex, *old_stmt_lex; Item_change_list old_change_list; String old_packet; uint old_server_status; @@ -1136,19 +1136,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success) if (check_stack_overrun(thd, 7 * STACK_MIN_SIZE, (uchar*)&old_packet)) DBUG_RETURN(TRUE); - /* - Normally the counter is not reset between parsing and first execution, - but it is possible in case of error to have parsing on one CALL and - first execution (where VIEW will be parsed and added). So we store the - counter after parsing and restore it before execution just to avoid - repeating SELECT numbers. - - Other problem is that it can be more SELECTs parsed in case of fixing - error causes previous interruption of the SP. So it is save not just - assign old value but add it. - */ - thd->select_number+= m_select_number; - /* init per-instruction memroot */ init_sql_alloc(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0)); @@ -1237,6 +1224,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) do it in each instruction */ old_lex= thd->lex; + old_stmt_lex= thd->stmt_lex; /* We should also save Item tree change list to avoid rollback something too early in the calling query. @@ -1384,6 +1372,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) DBUG_ASSERT(thd->change_list.is_empty()); old_change_list.move_elements_to(&thd->change_list); thd->lex= old_lex; + thd->stmt_lex= old_stmt_lex; thd->set_query_id(old_query_id); DBUG_ASSERT(!thd->derived_tables); thd->derived_tables= old_derived_tables; @@ -1482,16 +1471,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success) m_recursion_level + 1)); m_first_instance->m_first_free_instance= this; - /* - This execution of the SP was aborted with an error (e.g. "Table not - found"). However it might still have consumed some numbers from the - thd->select_number counter. The next sp->exec() call must not use the - consumed numbers, so we remember the first free number (We know that - nobody will use it as this execution has stopped with an error). - */ - if (err_status) - set_select_number(thd->select_number); - DBUG_RETURN(err_status); } @@ -2228,7 +2207,7 @@ sp_head::reset_lex(THD *thd) if (sublex == 0) DBUG_RETURN(TRUE); - thd->lex= sublex; + thd->lex= thd->stmt_lex= sublex; (void)m_lex.push_front(oldlex); /* Reset most stuff. */ @@ -2974,7 +2953,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, We should not save old value since it is saved/restored in sp_head::execute() when we are entering/leaving routine. */ - thd->lex= m_lex; + thd->lex= thd->stmt_lex= m_lex; thd->set_query_id(next_query_id()); diff --git a/sql/sp_head.h b/sql/sp_head.h index 5d3697daa16..604190079cb 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -232,7 +232,6 @@ private: */ uint32 unsafe_flags; - uint m_select_number; public: inline Stored_program_creation_ctx *get_creation_ctx() { @@ -522,8 +521,6 @@ public: sp_pcontext *get_parse_context() { return m_pcont; } - void set_select_number(uint num) { m_select_number= num; } - private: MEM_ROOT *m_thd_root; ///< Temp. store for thd's mem_root diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a226b920673..8359ad3ac97 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3654,7 +3654,7 @@ void Statement::set_statement(Statement *stmt) { id= stmt->id; mark_used_columns= stmt->mark_used_columns; - lex= stmt->lex; + stmt_lex= lex= stmt->lex; query_string= stmt->query_string; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 4556487bdfe..76e55d5d3de 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1027,6 +1027,21 @@ public: LEX_STRING name; /* name for named prepared statements */ LEX *lex; // parse tree descriptor + /* + LEX which represents current statement (conventional, SP or PS) + + For example during view parsing THD::lex will point to the views LEX and + THD::stmt_lex will point to LEX of the statement where the view will be + included + + Currently it is used to have always correct select numbering inside + statement (LEX::current_select_number) without storing and restoring a + global counter which was THD::select_number. + + TODO: make some unified statement representation (now SP has different) + to store such data like LEX::current_select_number. + */ + LEX *stmt_lex; /* Points to the query associated with this statement. It's const, but we need to declare it char * because all table handlers are written @@ -2690,7 +2705,6 @@ public: uint tmp_table, global_disable_checkpoint; uint server_status,open_options; enum enum_thread_type system_thread; - uint select_number; //number of select (used for EXPLAIN) /* Current or next transaction isolation level. When a connection is established, the value is taken from diff --git a/sql/sql_explain.h b/sql/sql_explain.h index 4d0ba38d810..caacf6b3a2f 100644 --- a/sql/sql_explain.h +++ b/sql/sql_explain.h @@ -208,6 +208,9 @@ public: Explain_select(MEM_ROOT *root, bool is_analyze) : Explain_basic_join(root), +#ifndef DBUG_OFF + select_lex(NULL), +#endif message(NULL), having(NULL), having_value(Item::COND_UNDEF), using_temporary(false), using_filesort(false), @@ -222,6 +225,9 @@ public: void replace_table(uint idx, Explain_table_access *new_tab); public: +#ifndef DBUG_OFF + SELECT_LEX *select_lex; +#endif const char *select_type; /* diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 63ab6b5d046..5b8327d6f59 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -657,6 +657,7 @@ void lex_start(THD *thd) { LEX *lex= thd->lex; DBUG_ENTER("lex_start"); + DBUG_PRINT("info", ("Lex %p stmt_lex: %p", thd->lex, thd->stmt_lex)); lex->thd= lex->unit.thd= thd; @@ -668,6 +669,7 @@ void lex_start(THD *thd) /* 'parent_lex' is used in init_query() so it must be before it. */ lex->select_lex.parent_lex= lex; lex->select_lex.init_query(); + lex->current_select_number= 1; lex->value_list.empty(); lex->update_list.empty(); lex->set_var_list.empty(); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index b57fba08b47..292f3d6d90f 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -727,7 +727,13 @@ public: Item *prep_having;/* saved HAVING clause for prepared statement processing */ /* Saved values of the WHERE and HAVING clauses*/ Item::cond_result cond_value, having_value; - /* point on lex in which it was created, used in view subquery detection */ + /* + Point to the LEX in which it was created, used in view subquery detection. + + TODO: make also st_select_lex::parent_stmt_lex (see THD::stmt_lex) + and use st_select_lex::parent_lex & st_select_lex::parent_stmt_lex + instead of global (from THD) references where it is possible. + */ LEX *parent_lex; enum olap_type olap; /* FROM clause - points to the beginning of the TABLE_LIST::next_local list. */ @@ -2452,7 +2458,7 @@ struct LEX: public Query_tables_list /** SELECT of CREATE VIEW statement */ LEX_STRING create_view_select; - uint number_of_selects; // valid only for view + uint current_select_number; // valid for statment LEX (not view) /** Start of 'ON table', in trigger statements. */ const char* raw_trg_on_table_name_begin; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6084c59a257..4dd8d9e124e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6903,7 +6903,12 @@ void THD::reset_for_next_command(bool do_clear_error) clear_error(1); thd->free_list= 0; - thd->select_number= 1; + /* + We also assign thd->stmt_lex in lex_start(), but during bootstrap this + code is executed first. + */ + thd->stmt_lex= &main_lex; thd->stmt_lex->current_select_number= 1; + DBUG_PRINT("info", ("Lex %p stmt_lex: %p", thd->lex, thd->stmt_lex)); /* Those two lines below are theoretically unneeded as THD::cleanup_after_query() should take care of this already. @@ -7021,7 +7026,7 @@ mysql_new_select(LEX *lex, bool move_down) if (!(select_lex= new (thd->mem_root) SELECT_LEX())) DBUG_RETURN(1); - select_lex->select_number= ++thd->select_number; + select_lex->select_number= ++thd->stmt_lex->current_select_number; select_lex->parent_lex= lex; /* Used in init_query. */ select_lex->init_query(); select_lex->init_select(); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index e5b85c3be45..64212d15548 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -164,20 +164,6 @@ public: uint param_count; uint last_errno; uint flags; - /* - The value of thd->select_number at the end of the PREPARE phase. - - The issue is: each statement execution opens VIEWs, which may cause - select_lex objects to be created, and select_number values to be assigned. - - On the other hand, PREPARE assigns select_number values for triggers and - subqueries. - - In order for select_number values from EXECUTE not to conflict with - select_number values from PREPARE, we keep the number and set it at each - execution. - */ - uint select_number_after_prepare; char last_error[MYSQL_ERRMSG_SIZE]; #ifndef EMBEDDED_LIBRARY bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end, @@ -3649,6 +3635,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) if (! (lex= new (mem_root) st_lex_local)) DBUG_RETURN(TRUE); + stmt_lex= lex; if (set_db(thd->db, thd->db_length)) DBUG_RETURN(TRUE); @@ -3754,8 +3741,6 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) trans_rollback_implicit(thd); thd->mdl_context.release_transactional_locks(); } - - select_number_after_prepare= thd->select_number; /* Preserve CHANGE MASTER attributes */ lex_end_stage1(lex); @@ -3891,7 +3876,6 @@ Prepared_statement::execute_loop(String *expanded_query, */ DBUG_ASSERT(thd->free_list == NULL); - thd->select_number= select_number_after_prepare; /* Check if we got an error when sending long data */ if (state == Query_arena::STMT_ERROR) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b9fe8f3162a..7a6a028ee9c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2462,6 +2462,17 @@ void JOIN::save_explain_data(Explain_query *output, bool can_overwrite, bool need_tmp_table, bool need_order, bool distinct) { + /* + If there is SELECT in this statemet with the same number it must be the + same SELECT + */ + DBUG_ASSERT(select_lex->select_number == UINT_MAX || + select_lex->select_number == INT_MAX || + !output || + !output->get_select(select_lex->select_number) || + output->get_select(select_lex->select_number)->select_lex == + select_lex); + if (select_lex->select_number != UINT_MAX && select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ && have_query_plan != JOIN::QEP_NOT_PRESENT_YET && @@ -24601,6 +24612,11 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table, { explain= new (output->mem_root) Explain_select(output->mem_root, thd->lex->analyze_stmt); + if (!explain) + DBUG_RETURN(1); // EoM +#ifndef DBUG_OFF + explain->select_lex= select_lex; +#endif join->select_lex->set_explain_type(true); explain->select_id= join->select_lex->select_number; diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 0b4978b2862..70e9b36c56e 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1373,12 +1373,13 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, List_iterator_fast it_client_cs_name(triggers->client_cs_names); List_iterator_fast it_connection_cl_name(triggers->connection_cl_names); List_iterator_fast it_db_cl_name(triggers->db_cl_names); - LEX *old_lex= thd->lex, lex; + LEX *old_lex= thd->lex, *old_stmt_lex= thd->stmt_lex; + LEX lex; sp_rcontext *save_spcont= thd->spcont; ulonglong save_sql_mode= thd->variables.sql_mode; LEX_STRING *on_table_name; - thd->lex= &lex; + thd->lex= thd->stmt_lex= &lex; save_db.str= thd->db; save_db.length= thd->db_length; @@ -1577,6 +1578,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, } thd->reset_db(save_db.str, save_db.length); thd->lex= old_lex; + thd->stmt_lex= old_stmt_lex; thd->spcont= save_spcont; thd->variables.sql_mode= save_sql_mode; @@ -1589,6 +1591,7 @@ err_with_lex_cleanup: // QQ: anything else ? lex_end(&lex); thd->lex= old_lex; + thd->stmt_lex= old_stmt_lex; thd->spcont= save_spcont; thd->variables.sql_mode= save_sql_mode; thd->reset_db(save_db.str, save_db.length); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 0f08883639a..1bdc76a66ea 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1187,8 +1187,6 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, */ mysql_derived_reinit(thd, NULL, table); - thd->select_number+= table->view->number_of_selects; - DEBUG_SYNC(thd, "after_cached_view_opened"); DBUG_RETURN(0); } @@ -1343,7 +1341,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, lex_start(thd); view_select= &lex->select_lex; - view_select->select_number= ++thd->select_number; + view_select->select_number= ++thd->stmt_lex->current_select_number; ulonglong saved_mode= thd->variables.sql_mode; /* switch off modes which can prevent normal parsing of VIEW @@ -1377,9 +1375,6 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, parse_status= parse_sql(thd, & parser_state, table->view_creation_ctx); - lex->number_of_selects= - (thd->select_number - view_select->select_number) + 1; - /* Restore environment. */ if ((old_lex->sql_command == SQLCOM_SHOW_FIELDS) || -- cgit v1.2.1 From 96cb428b350ba48ee17ad9968d08f5318e48258c Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Mon, 29 Jan 2018 09:44:17 +0100 Subject: MDEV-14862: Server crashes in Bitmap<64u>::merge / add_key_field Do not unwrap view references to keep table info. (Row-IN subselect does not unwrap items so it does not need fix) --- sql/item_subselect.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 8e8748be87a..4b45dc16609 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -2070,7 +2070,10 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join, } else { - Item *item= (Item*) select_lex->item_list.head()->real_item(); + Item *item= (Item*) select_lex->item_list.head(); + if (item->type() != REF_ITEM || + ((Item_ref*)item)->ref_type() != Item_ref::VIEW_REF) + item= item->real_item(); if (select_lex->table_list.elements) { -- cgit v1.2.1 From f694df6ac534e9e8396f9c9a7cae3768efc88311 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Fri, 2 Feb 2018 17:21:27 +0100 Subject: Fix of NULLIF print statement. --- sql/item_cmpfunc.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index ddf20f307a0..4e2e5bd4cac 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2826,7 +2826,9 @@ void Item_func_nullif::print(String *str, enum_query_type query_type) Therefore, after equal field propagation args[0] and args[2] can point to different items. */ - if ((query_type & QT_ITEM_ORIGINAL_FUNC_NULLIF) || args[0] == args[2]) + if ((query_type & QT_ITEM_ORIGINAL_FUNC_NULLIF) || + (arg_count == 2) || + (args[0] == args[2])) { /* If QT_ITEM_ORIGINAL_FUNC_NULLIF is requested, @@ -2844,10 +2846,14 @@ void Item_func_nullif::print(String *str, enum_query_type query_type) - one "a" for comparison - another "a" for the returned value! */ - DBUG_ASSERT(args[0] == args[2] || current_thd->lex->context_analysis_only); + DBUG_ASSERT(arg_count == 2 || + args[0] == args[2] || current_thd->lex->context_analysis_only); str->append(func_name()); str->append('('); - args[2]->print(str, query_type); + if (arg_count == 2) + args[0]->print(str, query_type); + else + args[2]->print(str, query_type); str->append(','); args[1]->print(str, query_type); str->append(')'); -- cgit v1.2.1