diff options
author | Jan Lindström <jan.lindstrom@mariadb.com> | 2017-08-09 08:56:11 +0300 |
---|---|---|
committer | Jan Lindström <jan.lindstrom@mariadb.com> | 2017-08-09 08:56:11 +0300 |
commit | 56b03e308fb4c0feee166ddf6a707d855affa3c3 (patch) | |
tree | fc4e16093800cf4cbf1cc54fceb0b7280c4212ba /sql | |
parent | 4f40f87c48a9ee252f797b5d760a6b6f07cc3815 (diff) | |
parent | a346a5613ee7c0b17b0b4ce377659c996ef6bb75 (diff) | |
download | mariadb-git-56b03e308fb4c0feee166ddf6a707d855affa3c3.tar.gz |
Merge tag 'mariadb-10.0.32' into 10.0-galera
Diffstat (limited to 'sql')
51 files changed, 823 insertions, 498 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 8606fd6890d..0f771d26bb5 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -43,15 +43,22 @@ SET_SOURCE_FILES_PROPERTIES(${GEN_SOURCES} # Gen_lex_token # Make sure sql_yacc.h is generated before compiling gen_lex_token + +IF(NOT CMAKE_GENERATOR MATCHES "Visual Studio") + SET(DEPENDS_gen_lex_token DEPENDS gen_lex_token) + SET(DEPENDS_gen_lex_hash DEPENDS gen_lex_hash) +ENDIF() + + IF(NOT CMAKE_CROSSCOMPILING) - ADD_EXECUTABLE(gen_lex_token gen_lex_token.cc) - ADD_DEPENDENCIES(gen_lex_token GenServerSource) + ADD_EXECUTABLE(gen_lex_token gen_lex_token.cc + ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.h) ENDIF() ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lex_token.h COMMAND gen_lex_token > lex_token.h - DEPENDS gen_lex_token + ${DEPENDS_gen_lex_token} ) ADD_DEFINITIONS(-DMYSQL_SERVER -DHAVE_EVENT_SCHEDULER) @@ -318,7 +325,7 @@ ENDIF() ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lex_hash.h COMMAND gen_lex_hash > lex_hash.h - DEPENDS gen_lex_hash + ${DEPENDS_gen_lex_hash} ) MYSQL_ADD_EXECUTABLE(mysql_tzinfo_to_sql tztime.cc COMPONENT Server) diff --git a/sql/contributors.h b/sql/contributors.h index 3a771e2b493..88a4a088acf 100644 --- a/sql/contributors.h +++ b/sql/contributors.h @@ -39,9 +39,11 @@ 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"}, + {"Tencent Cloud", "https://cloud.tencent.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"}, + {"IBM", "https://www.ibm.com", "Gold Sponsor of the MariaDB Foundation"}, {"Nexedi", "https://www.nexedi.com", "Silver Sponsor of the MariaDB Foundation"}, {"Acronis", "http://www.acronis.com", "Silver Sponsor of the MariaDB Foundation"}, {"Auttomattic", "https://automattic.com", "Bronze Sponsor of the MariaDB Foundation"}, diff --git a/sql/field.cc b/sql/field.cc index 7d7fad2d84d..7a44bcadd3c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6403,9 +6403,6 @@ uint Field::is_equal(Create_field *new_field) uint Field_str::is_equal(Create_field *new_field) { - if (field_flags_are_binary() != new_field->field_flags_are_binary()) - return 0; - return ((new_field->sql_type == real_type()) && new_field->charset == field_charset && new_field->length == max_display_length()); @@ -7810,9 +7807,6 @@ uint Field_blob::max_packed_col_length(uint max_length) uint Field_blob::is_equal(Create_field *new_field) { - if (field_flags_are_binary() != new_field->field_flags_are_binary()) - return 0; - return ((new_field->sql_type == get_blob_type_from_length(max_data_length())) && new_field->charset == field_charset && new_field->pack_length == pack_length()); @@ -7933,6 +7927,18 @@ Field::geometry_type Field_geom::geometry_type_merge(geometry_type a, return Field::GEOM_GEOMETRY; } + +uint Field_geom::is_equal(Create_field *new_field) +{ + return new_field->sql_type == MYSQL_TYPE_GEOMETRY && + /* + - Allow ALTER..INPLACE to supertype (GEOMETRY), + e.g. POINT to GEOMETRY or POLYGON to GEOMETRY. + - Allow ALTER..INPLACE to the same geometry type: POINT -> POINT + */ + (new_field->geom_type == geom_type || + new_field->geom_type == GEOM_GEOMETRY); +} #endif /*HAVE_SPATIAL*/ /**************************************************************************** @@ -8336,8 +8342,7 @@ uint Field_enum::is_equal(Create_field *new_field) The fields are compatible if they have the same flags, type, charset and have the same underlying length. */ - if (new_field->field_flags_are_binary() != field_flags_are_binary() || - new_field->sql_type != real_type() || + if (new_field->sql_type != real_type() || new_field->charset != field_charset || new_field->pack_length != pack_length()) return IS_EQUAL_NO; diff --git a/sql/field.h b/sql/field.h index 2770b8be213..e7bd5532ae6 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1080,10 +1080,6 @@ protected: const uchar *unpack_int64(uchar* to, const uchar *from, const uchar *from_end) { return unpack_int(to, from, from_end, 8); } - bool field_flags_are_binary() - { - return (flags & (BINCMP_FLAG | BINARY_FLAG)) != 0; - } double pos_in_interval_val_real(Field *min, Field *max); double pos_in_interval_val_str(Field *min, Field *max, uint data_offset); }; @@ -2620,6 +2616,7 @@ public: enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; } bool match_collation_to_optimize_range() const { return false; } void sql_type(String &str) const; + uint is_equal(Create_field *new_field); int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr); int store(longlong nr, bool unsigned_val); @@ -2967,11 +2964,6 @@ public: uint uint_geom_type, Virtual_column_info *vcol_info, engine_option_value *option_list, bool check_exists); - bool field_flags_are_binary() - { - return (flags & (BINCMP_FLAG | BINARY_FLAG)) != 0; - } - ha_storage_media field_storage_type() const { return (ha_storage_media) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index e854045661b..4441e975f93 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -680,7 +680,7 @@ int ha_partition::create(const char *name, TABLE *table_arg, HA_CREATE_INFO *create_info) { int error; - char name_buff[FN_REFLEN], name_lc_buff[FN_REFLEN]; + char name_buff[FN_REFLEN + 1], name_lc_buff[FN_REFLEN]; char *name_buffer_ptr; const char *path; uint i; @@ -722,8 +722,9 @@ int ha_partition::create(const char *name, TABLE *table_arg, for (j= 0; j < m_part_info->num_subparts; j++) { part_elem= sub_it++; - create_partition_name(name_buff, path, name_buffer_ptr, - NORMAL_PART_NAME, FALSE); + if ((error= create_partition_name(name_buff, sizeof(name_buff), path, + name_buffer_ptr, NORMAL_PART_NAME, FALSE))) + goto create_error; if ((error= set_up_table_before_create(table_arg, name_buff, create_info, part_elem)) || ((error= (*file)->ha_create(name_buff, table_arg, create_info)))) @@ -735,8 +736,9 @@ int ha_partition::create(const char *name, TABLE *table_arg, } else { - create_partition_name(name_buff, path, name_buffer_ptr, - NORMAL_PART_NAME, FALSE); + if ((error= create_partition_name(name_buff, sizeof(name_buff), path, + name_buffer_ptr, NORMAL_PART_NAME, FALSE))) + goto create_error; if ((error= set_up_table_before_create(table_arg, name_buff, create_info, part_elem)) || ((error= (*file)->ha_create(name_buff, table_arg, create_info)))) @@ -752,9 +754,9 @@ create_error: name_buffer_ptr= m_name_buffer_ptr; for (abort_file= file, file= m_file; file < abort_file; file++) { - create_partition_name(name_buff, path, name_buffer_ptr, NORMAL_PART_NAME, - FALSE); - (void) (*file)->ha_delete_table((const char*) name_buff); + if (!create_partition_name(name_buff, sizeof(name_buff), path, + name_buffer_ptr, NORMAL_PART_NAME, FALSE)) + (void) (*file)->ha_delete_table((const char*) name_buff); name_buffer_ptr= strend(name_buffer_ptr) + 1; } handler::delete_table(name); @@ -781,7 +783,7 @@ create_error: int ha_partition::drop_partitions(const char *path) { List_iterator<partition_element> part_it(m_part_info->partitions); - char part_name_buff[FN_REFLEN]; + char part_name_buff[FN_REFLEN + 1]; uint num_parts= m_part_info->partitions.elements; uint num_subparts= m_part_info->num_subparts; uint i= 0; @@ -814,9 +816,11 @@ int ha_partition::drop_partitions(const char *path) { partition_element *sub_elem= sub_it++; part= i * num_subparts + j; - create_subpartition_name(part_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, name_variant); + if ((ret_error= create_subpartition_name(part_name_buff, + sizeof(part_name_buff), path, + part_elem->partition_name, + sub_elem->partition_name, name_variant))) + error= ret_error; file= m_file[part]; DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff)); if ((ret_error= file->ha_delete_table(part_name_buff))) @@ -827,15 +831,19 @@ int ha_partition::drop_partitions(const char *path) } else { - create_partition_name(part_name_buff, path, - part_elem->partition_name, name_variant, - TRUE); - file= m_file[i]; - DBUG_PRINT("info", ("Drop partition %s", part_name_buff)); - if ((ret_error= file->ha_delete_table(part_name_buff))) + if ((ret_error= create_partition_name(part_name_buff, + sizeof(part_name_buff), path, + part_elem->partition_name, name_variant, TRUE))) error= ret_error; - if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) - error= 1; + else + { + file= m_file[i]; + DBUG_PRINT("info", ("Drop partition %s", part_name_buff)); + if ((ret_error= file->ha_delete_table(part_name_buff))) + error= ret_error; + if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) + error= 1; + } } if (part_elem->part_state == PART_IS_CHANGED) part_elem->part_state= PART_NORMAL; @@ -871,8 +879,8 @@ int ha_partition::rename_partitions(const char *path) { List_iterator<partition_element> part_it(m_part_info->partitions); List_iterator<partition_element> temp_it(m_part_info->temp_partitions); - char part_name_buff[FN_REFLEN]; - char norm_name_buff[FN_REFLEN]; + char part_name_buff[FN_REFLEN + 1]; + char norm_name_buff[FN_REFLEN + 1]; uint num_parts= m_part_info->partitions.elements; uint part_count= 0; uint num_subparts= m_part_info->num_subparts; @@ -914,10 +922,11 @@ int ha_partition::rename_partitions(const char *path) { sub_elem= sub_it++; file= m_reorged_file[part_count++]; - create_subpartition_name(norm_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, - NORMAL_PART_NAME); + if ((ret_error= create_subpartition_name(norm_name_buff, + sizeof(norm_name_buff), path, + part_elem->partition_name, + sub_elem->partition_name, NORMAL_PART_NAME))) + error= ret_error; DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); if ((ret_error= file->ha_delete_table(norm_name_buff))) error= ret_error; @@ -930,16 +939,20 @@ int ha_partition::rename_partitions(const char *path) else { file= m_reorged_file[part_count++]; - create_partition_name(norm_name_buff, path, - part_elem->partition_name, NORMAL_PART_NAME, - TRUE); - DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); - if ((ret_error= file->ha_delete_table(norm_name_buff))) + if ((ret_error= create_partition_name(norm_name_buff, + sizeof(norm_name_buff), path, + part_elem->partition_name, NORMAL_PART_NAME, TRUE))) error= ret_error; - else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) - error= 1; else - part_elem->log_entry= NULL; /* Indicate success */ + { + DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); + if ((ret_error= file->ha_delete_table(norm_name_buff))) + error= ret_error; + else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) + error= 1; + else + part_elem->log_entry= NULL; /* Indicate success */ + } } } while (++i < temp_partitions); (void) sync_ddl_log(); @@ -982,10 +995,11 @@ int ha_partition::rename_partitions(const char *path) { sub_elem= sub_it++; part= i * num_subparts + j; - create_subpartition_name(norm_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, - NORMAL_PART_NAME); + if ((ret_error= create_subpartition_name(norm_name_buff, + sizeof(norm_name_buff), path, + part_elem->partition_name, + sub_elem->partition_name, NORMAL_PART_NAME))) + error= ret_error; if (part_elem->part_state == PART_IS_CHANGED) { file= m_reorged_file[part_count++]; @@ -997,10 +1011,11 @@ int ha_partition::rename_partitions(const char *path) (void) sync_ddl_log(); } file= m_new_file[part]; - create_subpartition_name(part_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, - TEMP_PART_NAME); + if ((ret_error= create_subpartition_name(part_name_buff, + sizeof(part_name_buff), path, + part_elem->partition_name, + sub_elem->partition_name, TEMP_PART_NAME))) + error= ret_error; DBUG_PRINT("info", ("Rename subpartition from %s to %s", part_name_buff, norm_name_buff)); if ((ret_error= file->ha_rename_table(part_name_buff, @@ -1014,32 +1029,36 @@ int ha_partition::rename_partitions(const char *path) } else { - create_partition_name(norm_name_buff, path, - part_elem->partition_name, NORMAL_PART_NAME, - TRUE); - if (part_elem->part_state == PART_IS_CHANGED) + if ((ret_error= create_partition_name(norm_name_buff, + sizeof(norm_name_buff), path, + part_elem->partition_name, NORMAL_PART_NAME, TRUE)) || + (ret_error= create_partition_name(part_name_buff, + sizeof(part_name_buff), path, + part_elem->partition_name, TEMP_PART_NAME, TRUE))) + error= ret_error; + else { - file= m_reorged_file[part_count++]; - DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); - if ((ret_error= file->ha_delete_table(norm_name_buff))) + if (part_elem->part_state == PART_IS_CHANGED) + { + file= m_reorged_file[part_count++]; + DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); + if ((ret_error= file->ha_delete_table(norm_name_buff))) + error= ret_error; + else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) + error= 1; + (void) sync_ddl_log(); + } + file= m_new_file[i]; + DBUG_PRINT("info", ("Rename partition from %s to %s", + part_name_buff, norm_name_buff)); + if ((ret_error= file->ha_rename_table(part_name_buff, + norm_name_buff))) error= ret_error; else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) error= 1; - (void) sync_ddl_log(); + else + part_elem->log_entry= NULL; } - file= m_new_file[i]; - create_partition_name(part_name_buff, path, - part_elem->partition_name, TEMP_PART_NAME, - TRUE); - DBUG_PRINT("info", ("Rename partition from %s to %s", - part_name_buff, norm_name_buff)); - if ((ret_error= file->ha_rename_table(part_name_buff, - norm_name_buff))) - error= ret_error; - else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) - error= 1; - else - part_elem->log_entry= NULL; } } } while (++i < num_parts); @@ -1655,7 +1674,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, { List_iterator<partition_element> part_it(m_part_info->partitions); List_iterator <partition_element> t_it(m_part_info->temp_partitions); - char part_name_buff[FN_REFLEN]; + char part_name_buff[FN_REFLEN + 1]; uint num_parts= m_part_info->partitions.elements; uint num_subparts= m_part_info->num_subparts; uint i= 0; @@ -1883,10 +1902,14 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, do { partition_element *sub_elem= sub_it++; - create_subpartition_name(part_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, - name_variant); + if ((error= create_subpartition_name(part_name_buff, + sizeof(part_name_buff), path, + part_elem->partition_name, sub_elem->partition_name, + name_variant))) + { + cleanup_new_partition(part_count); + DBUG_RETURN(error); + } part= i * num_subparts + j; DBUG_PRINT("info", ("Add subpartition %s", part_name_buff)); if ((error= prepare_new_partition(table, create_info, @@ -1904,9 +1927,14 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, } else { - create_partition_name(part_name_buff, path, - part_elem->partition_name, name_variant, - TRUE); + if ((error= create_partition_name(part_name_buff, + sizeof(part_name_buff), path, part_elem->partition_name, + name_variant, TRUE))) + { + cleanup_new_partition(part_count); + DBUG_RETURN(error); + } + DBUG_PRINT("info", ("Add partition %s", part_name_buff)); if ((error= prepare_new_partition(table, create_info, new_file_array[i], @@ -2277,8 +2305,8 @@ uint ha_partition::del_ren_table(const char *from, const char *to) { int save_error= 0; int error; - char from_buff[FN_REFLEN], to_buff[FN_REFLEN], from_lc_buff[FN_REFLEN], - to_lc_buff[FN_REFLEN]; + char from_buff[FN_REFLEN + 1], to_buff[FN_REFLEN + 1], + from_lc_buff[FN_REFLEN], to_lc_buff[FN_REFLEN]; char *name_buffer_ptr; const char *from_path; const char *to_path= NULL; @@ -2314,13 +2342,15 @@ uint ha_partition::del_ren_table(const char *from, const char *to) i= 0; do { - create_partition_name(from_buff, from_path, name_buffer_ptr, - NORMAL_PART_NAME, FALSE); + if ((error= create_partition_name(from_buff, sizeof(from_buff), from_path, + name_buffer_ptr, NORMAL_PART_NAME, FALSE))) + goto rename_error; if (to != NULL) { // Rename branch - create_partition_name(to_buff, to_path, name_buffer_ptr, - NORMAL_PART_NAME, FALSE); + if ((error= create_partition_name(to_buff, sizeof(to_buff), to_path, + name_buffer_ptr, NORMAL_PART_NAME, FALSE))) + goto rename_error; error= (*file)->ha_rename_table(from_buff, to_buff); if (error) goto rename_error; @@ -2349,12 +2379,14 @@ rename_error: for (abort_file= file, file= m_file; file < abort_file; file++) { /* Revert the rename, back from 'to' to the original 'from' */ - create_partition_name(from_buff, from_path, name_buffer_ptr, - NORMAL_PART_NAME, FALSE); - create_partition_name(to_buff, to_path, name_buffer_ptr, - NORMAL_PART_NAME, FALSE); - /* Ignore error here */ - (void) (*file)->ha_rename_table(to_buff, from_buff); + if (!create_partition_name(from_buff, sizeof(from_buff), from_path, + name_buffer_ptr, NORMAL_PART_NAME, FALSE) && + !create_partition_name(to_buff, sizeof(to_buff), to_path, + name_buffer_ptr, NORMAL_PART_NAME, FALSE)) + { + /* Ignore error here */ + (void) (*file)->ha_rename_table(to_buff, from_buff); + } name_buffer_ptr= strend(name_buffer_ptr) + 1; } DBUG_RETURN(error); @@ -3421,7 +3453,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) char *name_buffer_ptr; int error= HA_ERR_INITIALIZATION; handler **file; - char name_buff[FN_REFLEN]; + char name_buff[FN_REFLEN + 1]; ulonglong check_table_flags; DBUG_ENTER("ha_partition::open"); @@ -3475,8 +3507,9 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) file= m_is_clone_of->m_file; for (i= 0; i < m_tot_parts; i++) { - create_partition_name(name_buff, name, name_buffer_ptr, NORMAL_PART_NAME, - FALSE); + if ((error= create_partition_name(name_buff, sizeof(name_buff), name, + name_buffer_ptr, NORMAL_PART_NAME, FALSE))) + goto err_handler; /* ::clone() will also set ha_share from the original. */ if (!(m_file[i]= file[i]->clone(name_buff, m_clone_mem_root))) { @@ -3492,8 +3525,9 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) file= m_file; do { - create_partition_name(name_buff, name, name_buffer_ptr, NORMAL_PART_NAME, - FALSE); + if ((error= create_partition_name(name_buff, sizeof(name_buff), name, + name_buffer_ptr, NORMAL_PART_NAME, FALSE))) + goto err_handler; table->s->connect_string = m_connect_string[(uint)(file-m_file)]; if ((error= (*file)->ha_open(table, name_buff, mode, test_if_locked | HA_OPEN_NO_PSI_CALL))) diff --git a/sql/handler.cc b/sql/handler.cc index 91dde9a8d27..19f648219ac 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3720,6 +3720,8 @@ void handler::print_error(int error, myf errflag) */ bool handler::get_error_message(int error, String* buf) { + DBUG_EXECUTE_IF("external_lock_failure", + buf->set_ascii(STRING_WITH_LEN("KABOOM!"));); return FALSE; } @@ -6044,6 +6046,8 @@ int handler::ha_external_lock(THD *thd, int lock_type) MYSQL_TABLE_LOCK_WAIT(m_psi, PSI_TABLE_EXTERNAL_LOCK, lock_type, { error= external_lock(thd, lock_type); }) + DBUG_EXECUTE_IF("external_lock_failure", error= HA_ERR_GENERIC;); + if (error == 0 || lock_type == F_UNLCK) { m_lock_type= lock_type; diff --git a/sql/item.cc b/sql/item.cc index 4ce8396f71e..6bd982f8854 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. - Copyright (c) 2010, 2017, MariaDB + Copyright (c) 2010, 2017, MariaDB Corporation 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 @@ -847,6 +847,7 @@ Item_ident::Item_ident(Name_resolution_context *context_arg, cached_table(0), depended_from(0), can_be_depended(TRUE) { name = (char*) field_name_arg; + name_length= name ? strlen(name) : 0; } @@ -859,6 +860,7 @@ Item_ident::Item_ident(TABLE_LIST *view_arg, const char *field_name_arg) cached_table(NULL), depended_from(NULL), can_be_depended(TRUE) { name = (char*) field_name_arg; + name_length= name ? strlen(name) : 0; } @@ -1263,6 +1265,7 @@ Item *Item::const_charset_converter(CHARSET_INFO *tocs, DBUG_ASSERT(fixed); StringBuffer<64>tmp; String *s= val_str(&tmp); + if (!s) return new Item_null((char *) func_name, tocs); @@ -4564,7 +4567,7 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) int cur_match_degree= 0; /* SELECT list element with explicit alias */ - if ((*(cur_group->item))->name && + if ((*(cur_group->item))->name && !table_name && !(*(cur_group->item))->is_autogenerated_name && !my_strcasecmp(system_charset_info, (*(cur_group->item))->name, field_name)) @@ -4987,6 +4990,12 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) ((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ? (Item_ident*) (*reference) : 0)); + if (thd->lex->in_sum_func && + thd->lex->in_sum_func->nest_level >= select->nest_level) + { + set_if_bigger(thd->lex->in_sum_func->max_arg_level, + select->nest_level); + } /* A reference to a view field had been found and we substituted it instead of this Item (find_field_in_tables diff --git a/sql/item.h b/sql/item.h index 4d33a0eb6c1..f363950b9bc 100644 --- a/sql/item.h +++ b/sql/item.h @@ -830,25 +830,20 @@ public: store return value of this method. NOTE - Buffer passed via argument should only be used if the item itself - doesn't have an own String buffer. In case when the item maintains - it's own string buffer, it's preferable to return it instead to - minimize number of mallocs/memcpys. - The caller of this method can modify returned string, but only in case - when it was allocated on heap, (is_alloced() is true). This allows - the caller to efficiently use a buffer allocated by a child without - having to allocate a buffer of it's own. The buffer, given to - val_str() as argument, belongs to the caller and is later used by the - caller at it's own choosing. - A few implications from the above: - - unless you return a string object which only points to your buffer - but doesn't manages it you should be ready that it will be - modified. - - even for not allocated strings (is_alloced() == false) the caller - can change charset (see Item_func_{typecast/binary}. XXX: is this - a bug? - - still you should try to minimize data copying and return internal - object whenever possible. + The caller can modify the returned String, if it's not marked + "const" (with the String::mark_as_const() method). That means that + if the item returns its own internal buffer (e.g. tmp_value), it + *must* be marked "const" [1]. So normally it's preferrable to + return the result value in the String, that was passed as an + argument. But, for example, SUBSTR() returns a String that simply + points into the buffer of SUBSTR()'s args[0]->val_str(). Such a + String is always "const", so it's ok to use tmp_value for that and + avoid reallocating/copying of the argument String. + + [1] consider SELECT CONCAT(f, ":", f) FROM (SELECT func() AS f); + here the return value of f() is used twice in the top-level + select, and if they share the same tmp_value buffer, modifying the + first one will implicitly modify the second too. RETURN In case of NULL value return 0 (NULL pointer) and set null_value flag @@ -1476,7 +1471,7 @@ public: virtual Item *expr_cache_insert_transformer(uchar *thd_arg) { return this; } virtual bool expr_cache_is_needed(THD *) { return FALSE; } virtual Item *safe_charset_converter(CHARSET_INFO *tocs); - bool needs_charset_converter(uint32 length, CHARSET_INFO *tocs) + bool needs_charset_converter(uint32 length, CHARSET_INFO *tocs) const { /* This will return "true" if conversion happens: diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 038a0ebabc2..0134f628c80 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -5110,7 +5110,7 @@ void Regexp_processor_pcre::set_recursion_limit(THD *thd) DBUG_ASSERT(thd == current_thd); stack_used= available_stack_size(thd->thread_stack, &stack_used); m_pcre_extra.match_limit_recursion= - (my_thread_stack_size - stack_used)/my_pcre_frame_size; + (my_thread_stack_size - STACK_MIN_SIZE - stack_used)/my_pcre_frame_size; } @@ -5372,6 +5372,12 @@ void Regexp_processor_pcre::fix_owner(Item_func *owner, } +bool Item_func_regex::fix_fields(THD *thd, Item **ref) +{ + re.set_recursion_limit(thd); + return Item_bool_func::fix_fields(thd, ref); +} + void Item_func_regex::fix_length_and_dec() { @@ -5398,6 +5404,13 @@ longlong Item_func_regex::val_int() } +bool Item_func_regexp_instr::fix_fields(THD *thd, Item **ref) +{ + re.set_recursion_limit(thd); + return Item_int_func::fix_fields(thd, ref); +} + + void Item_func_regexp_instr::fix_length_and_dec() { diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 17ad1bd8c7d..ba0af32d76f 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1652,6 +1652,7 @@ public: DBUG_VOID_RETURN; } longlong val_int(); + bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); const char *func_name() const { return "regexp"; } @@ -1679,6 +1680,7 @@ public: DBUG_VOID_RETURN; } longlong val_int(); + bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); const char *func_name() const { return "regexp_instr"; } }; diff --git a/sql/item_func.cc b/sql/item_func.cc index 9c5ef502693..7e4ddb7427c 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -848,8 +848,9 @@ void Item_func_num1::fix_length_and_dec() { DBUG_ENTER("Item_func_num1::fix_length_and_dec"); DBUG_PRINT("info", ("name %s", func_name())); - switch (cached_result_type= args[0]->cast_to_int_type()) { + switch (args[0]->cast_to_int_type()) { case INT_RESULT: + cached_result_type= INT_RESULT; max_length= args[0]->max_length; unsigned_flag= args[0]->unsigned_flag; break; @@ -860,8 +861,8 @@ void Item_func_num1::fix_length_and_dec() max_length= float_length(decimals); break; case TIME_RESULT: - cached_result_type= DECIMAL_RESULT; case DECIMAL_RESULT: + cached_result_type= DECIMAL_RESULT; decimals= args[0]->decimal_scale(); // Do not preserve NOT_FIXED_DEC max_length= args[0]->max_length; break; diff --git a/sql/item_func.h b/sql/item_func.h index 0141619dced..5db92b6f3fe 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1174,7 +1174,11 @@ public: longlong val_int(); const char *func_name() const { return "coercibility"; } void fix_length_and_dec() { max_length=10; maybe_null= 0; } - table_map not_null_tables() const { return 0; } + bool eval_not_null_tables(uchar *opt_arg) + { + not_null_tables_cache= 0; + return 0; + } }; class Item_func_locate :public Item_int_func @@ -1445,7 +1449,11 @@ public: } void cleanup(); Item_result result_type () const { return udf.result_type(); } - table_map not_null_tables() const { return 0; } + bool eval_not_null_tables(uchar *opt_arg) + { + not_null_tables_cache= 0; + return 0; + } bool is_expensive() { return 1; } virtual void print(String *str, enum_query_type query_type); }; @@ -1922,7 +1930,11 @@ public: bool is_expensive_processor(uchar *arg) { return TRUE; } enum Functype functype() const { return FT_FUNC; } const char *func_name() const { return "match"; } - table_map not_null_tables() const { return 0; } + bool eval_not_null_tables(uchar *opt_arg) + { + not_null_tables_cache= 0; + return 0; + } bool fix_fields(THD *thd, Item **ref); bool eq(const Item *, bool binary_cmp) const; /* The following should be safe, even if we compare doubles */ @@ -2159,6 +2171,11 @@ public: { return TRUE; } + bool eval_not_null_tables(uchar *opt_arg) + { + not_null_tables_cache= 0; + return 0; + } }; @@ -2206,7 +2223,11 @@ public: void fix_length_and_dec(); enum Item_result result_type () const { return last_value->result_type(); } const char *func_name() const { return "last_value"; } - table_map not_null_tables() const { return 0; } + bool eval_not_null_tables(uchar *opt_arg) + { + not_null_tables_cache= 0; + return 0; + } enum_field_types field_type() const { return last_value->field_type(); } bool const_item() const { return 0; } void evaluate_sideeffects(); diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 568a28e6465..a9e39ab717a 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1268,7 +1268,7 @@ String *Item_func_buffer::val_str(String *str_value) { DBUG_ENTER("Item_func_buffer::val_str"); DBUG_ASSERT(fixed == 1); - String *obj= args[0]->val_str(&tmp_value); + String *obj= args[0]->val_str(str_value); double dist= args[1]->val_real(); Geometry_buffer buffer; Geometry *g; diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 62d2198e221..d32edff599c 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -171,7 +171,6 @@ public: class Item_func_spatial_collection: public Item_geometry_func { - String tmp_value; enum Geometry::wkbType coll_type; enum Geometry::wkbType item_type; public: @@ -325,7 +324,6 @@ protected: Gcalc_result_receiver res_receiver; Gcalc_operation_reducer operation; - String tmp_value; public: Item_func_buffer(Item *obj, Item *distance): diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 7cd712cc5e1..c3043adac47 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -73,8 +73,14 @@ size_t username_char_length= 80; Conversion happens only in case of "tricky" Item character set (e.g. UCS2). Normally conversion does not happen, and val_str_ascii() is immediately returned instead. + + No matter if conversion is needed or not needed, + the result is always returned in "str" (see MDEV-10306 why). + + @param [OUT] str - Store the result here + @param [IN] ascii_buffer - Use this temporary buffer to call val_str_ascii() */ -String *Item_func::val_str_from_val_str_ascii(String *str, String *str2) +String *Item_func::val_str_from_val_str_ascii(String *str, String *ascii_buffer) { DBUG_ASSERT(fixed == 1); @@ -86,19 +92,19 @@ String *Item_func::val_str_from_val_str_ascii(String *str, String *str2) return res; } - DBUG_ASSERT(str != str2); + DBUG_ASSERT(str != ascii_buffer); uint errors; - String *res= val_str_ascii(str); + String *res= val_str_ascii(ascii_buffer); if (!res) return 0; - if ((null_value= str2->copy(res->ptr(), res->length(), - &my_charset_latin1, collation.collation, - &errors))) + if ((null_value= str->copy(res->ptr(), res->length(), + &my_charset_latin1, collation.collation, + &errors))) return 0; - return str2; + return str; } @@ -368,12 +374,12 @@ void Item_func_sha2::fix_length_and_dec() /* Implementation of AES encryption routines */ -String *Item_func_aes_encrypt::val_str(String *str) +String *Item_func_aes_encrypt::val_str(String *str2) { DBUG_ASSERT(fixed == 1); char key_buff[80]; String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info); - String *sptr= args[0]->val_str(str); // String to encrypt + String *sptr= args[0]->val_str(&str_value); // String to encrypt String *key= args[1]->val_str(&tmp_key_value); // key int aes_length; if (sptr && key) // we need both arguments to be not NULL @@ -381,15 +387,15 @@ String *Item_func_aes_encrypt::val_str(String *str) null_value=0; aes_length=my_aes_get_size(sptr->length()); // Calculate result length - if (!str_value.alloc(aes_length)) // Ensure that memory is free + if (!str2->alloc(aes_length)) // Ensure that memory is free { // finally encrypt directly to allocated buffer. - if (my_aes_encrypt(sptr->ptr(),sptr->length(), (char*) str_value.ptr(), + if (my_aes_encrypt(sptr->ptr(),sptr->length(), (char*) str2->ptr(), key->ptr(), key->length()) == aes_length) { // We got the expected result length - str_value.length((uint) aes_length); - return &str_value; + str2->length((uint) aes_length); + return str2; } } } @@ -412,22 +418,22 @@ String *Item_func_aes_decrypt::val_str(String *str) String *sptr, *key; DBUG_ENTER("Item_func_aes_decrypt::val_str"); - sptr= args[0]->val_str(str); // String to decrypt + sptr= args[0]->val_str(&str_value); // String to decrypt key= args[1]->val_str(&tmp_key_value); // Key if (sptr && key) // Need to have both arguments not NULL { null_value=0; - if (!str_value.alloc(sptr->length())) // Ensure that memory is free + if (!str->alloc(sptr->length())) // Ensure that memory is free { // finally decrypt directly to allocated buffer. int length; length=my_aes_decrypt(sptr->ptr(), sptr->length(), - (char*) str_value.ptr(), + (char*) str->ptr(), key->ptr(), key->length()); if (length >= 0) // if we got correct data data { - str_value.length((uint) length); - DBUG_RETURN(&str_value); + str->length((uint) length); + DBUG_RETURN(str); } } } @@ -464,7 +470,7 @@ void Item_func_to_base64::fix_length_and_dec() String *Item_func_to_base64::val_str_ascii(String *str) { - String *res= args[0]->val_str(str); + String *res= args[0]->val_str(&tmp_value); bool too_long= false; int length; if (!res || @@ -472,7 +478,7 @@ String *Item_func_to_base64::val_str_ascii(String *str) (too_long= ((uint) (length= base64_needed_encoded_length((int) res->length())) > current_thd->variables.max_allowed_packet)) || - tmp_value.alloc((uint) length)) + str->alloc((uint) length)) { null_value= 1; // NULL input, too long input, or OOM. if (too_long) @@ -484,11 +490,11 @@ String *Item_func_to_base64::val_str_ascii(String *str) } return 0; } - base64_encode(res->ptr(), (int) res->length(), (char*) tmp_value.ptr()); + base64_encode(res->ptr(), (int) res->length(), (char*) str->ptr()); DBUG_ASSERT(length > 0); - tmp_value.length((uint) length - 1); // Without trailing '\0' + str->length((uint) length - 1); // Without trailing '\0' null_value= 0; - return &tmp_value; + return str; } @@ -509,7 +515,7 @@ void Item_func_from_base64::fix_length_and_dec() String *Item_func_from_base64::val_str(String *str) { - String *res= args[0]->val_str_ascii(str); + String *res= args[0]->val_str_ascii(&tmp_value); int length; const char *end_ptr; @@ -527,11 +533,11 @@ String *Item_func_from_base64::val_str(String *str) goto err; } - if (tmp_value.alloc((uint) length)) + if (str->alloc((uint) length)) goto err; if ((length= base64_decode(res->ptr(), (int) res->length(), - (char *) tmp_value.ptr(), &end_ptr, 0)) < 0 || + (char *) str->ptr(), &end_ptr, 0)) < 0 || end_ptr < res->ptr() + res->length()) { push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, @@ -540,9 +546,9 @@ String *Item_func_from_base64::val_str(String *str) goto err; } - tmp_value.length((uint) length); + str->length((uint) length); null_value= 0; - return &tmp_value; + return str; err: null_value= 1; // NULL input, too long input, OOM, or badly formed input return 0; @@ -797,7 +803,7 @@ String *Item_func_des_encrypt::val_str(String *str) struct st_des_keyschedule keyschedule; const char *append_str="********"; uint key_number, res_length, tail; - String *res= args[0]->val_str(str); + String *res= args[0]->val_str(&tmp_value); if ((null_value= args[0]->null_value)) return 0; // ENCRYPT(NULL) == NULL @@ -821,7 +827,7 @@ String *Item_func_des_encrypt::val_str(String *str) } else { - String *keystr=args[1]->val_str(&tmp_value); + String *keystr= args[1]->val_str(str); if (!keystr) goto error; key_number=127; // User key string @@ -853,23 +859,23 @@ String *Item_func_des_encrypt::val_str(String *str) tmp_arg.length(0); tmp_arg.append(res->ptr(), res->length()); code= ER_OUT_OF_RESOURCES; - if (tmp_arg.append(append_str, tail) || tmp_value.alloc(res_length+1)) + if (tmp_arg.append(append_str, tail) || str->alloc(res_length+1)) goto error; tmp_arg[res_length-1]=tail; // save extra length - tmp_value.realloc(res_length+1); - tmp_value.length(res_length+1); - tmp_value.set_charset(&my_charset_bin); - tmp_value[0]=(char) (128 | key_number); + str->realloc(res_length+1); + str->length(res_length+1); + str->set_charset(&my_charset_bin); + (*str)[0]=(char) (128 | key_number); // Real encryption bzero((char*) &ivec,sizeof(ivec)); DES_ede3_cbc_encrypt((const uchar*) (tmp_arg.ptr()), - (uchar*) (tmp_value.ptr()+1), + (uchar*) (str->ptr()+1), res_length, &keyschedule.ks1, &keyschedule.ks2, &keyschedule.ks3, &ivec, TRUE); - return &tmp_value; + return str; error: push_warning_printf(current_thd,Sql_condition::WARN_LEVEL_WARN, @@ -893,7 +899,7 @@ String *Item_func_des_decrypt::val_str(String *str) DES_cblock ivec; struct st_des_keyblock keyblock; struct st_des_keyschedule keyschedule; - String *res= args[0]->val_str(str); + String *res= args[0]->val_str(&tmp_value); uint length,tail; if ((null_value= args[0]->null_value)) @@ -917,7 +923,7 @@ String *Item_func_des_decrypt::val_str(String *str) else { // We make good 24-byte (168 bit) key from given plaintext key with MD5 - String *keystr=args[1]->val_str(&tmp_value); + String *keystr= args[1]->val_str(str); if (!keystr) goto error; @@ -932,23 +938,23 @@ String *Item_func_des_decrypt::val_str(String *str) DES_set_key_unchecked(&keyblock.key3,&keyschedule.ks3); } code= ER_OUT_OF_RESOURCES; - if (tmp_value.alloc(length-1)) + if (str->alloc(length-1)) goto error; bzero((char*) &ivec,sizeof(ivec)); DES_ede3_cbc_encrypt((const uchar*) res->ptr()+1, - (uchar*) (tmp_value.ptr()), + (uchar*) (str->ptr()), length-1, &keyschedule.ks1, &keyschedule.ks2, &keyschedule.ks3, &ivec, FALSE); /* Restore old length of key */ - if ((tail=(uint) (uchar) tmp_value[length-2]) > 8) + if ((tail=(uint) (uchar) (*str)[length-2]) > 8) goto wrong_key; // Wrong key - tmp_value.length(length-1-tail); - tmp_value.set_charset(&my_charset_bin); - return &tmp_value; + str->length(length-1-tail); + str->set_charset(&my_charset_bin); + return str; error: push_warning_printf(current_thd,Sql_condition::WARN_LEVEL_WARN, @@ -1136,25 +1142,26 @@ void Item_func_concat_ws::fix_length_and_dec() String *Item_func_reverse::val_str(String *str) { DBUG_ASSERT(fixed == 1); - String *res = args[0]->val_str(str); - char *ptr, *end, *tmp; + String *res= args[0]->val_str(&tmp_value); + const char *ptr, *end; + char *tmp; if ((null_value=args[0]->null_value)) return 0; /* An empty string is a special case as the string pointer may be null */ if (!res->length()) return make_empty_result(); - if (tmp_value.alloced_length() < res->length() && - tmp_value.realloc(res->length())) + if (str->alloced_length() < res->length() && + str->realloc(res->length())) { null_value= 1; return 0; } - tmp_value.length(res->length()); - tmp_value.set_charset(res->charset()); - ptr= (char *) res->ptr(); - end= ptr + res->length(); - tmp= (char *) tmp_value.ptr() + tmp_value.length(); + str->length(res->length()); + str->set_charset(res->charset()); + ptr= res->ptr(); + end= res->end(); + tmp= (char *) str->end(); #ifdef USE_MB if (use_mb(res->charset())) { @@ -1164,7 +1171,7 @@ String *Item_func_reverse::val_str(String *str) if ((l= my_ismbchar(res->charset(),ptr,end))) { tmp-= l; - DBUG_ASSERT(tmp >= tmp_value.ptr()); + DBUG_ASSERT(tmp >= str->ptr()); memcpy(tmp,ptr,l); ptr+= l; } @@ -1178,7 +1185,7 @@ String *Item_func_reverse::val_str(String *str) while (ptr < end) *--tmp= *ptr++; } - return &tmp_value; + return str; } @@ -1336,6 +1343,13 @@ void Item_func_replace::fix_length_and_dec() /*********************************************************************/ +bool Item_func_regexp_replace::fix_fields(THD *thd, Item **ref) +{ + re.set_recursion_limit(thd); + return Item_str_func::fix_fields(thd, ref); +} + + void Item_func_regexp_replace::fix_length_and_dec() { if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 3)) @@ -1471,6 +1485,13 @@ err: } +bool Item_func_regexp_substr::fix_fields(THD *thd, Item **ref) +{ + re.set_recursion_limit(thd); + return Item_str_func::fix_fields(thd, ref); +} + + void Item_func_regexp_substr::fix_length_and_dec() { if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 2)) @@ -2344,6 +2365,7 @@ String *Item_func_database::val_str(String *str) } else str->copy(thd->db, thd->db_length, system_charset_info); + null_value= 0; return str; } @@ -2378,6 +2400,28 @@ bool Item_func_user::init(const char *user, const char *host) } +Item *Item_func_sysconst::safe_charset_converter(CHARSET_INFO *tocs) +{ + /* + During view or prepared statement creation, the item should not + make use of const_charset_converter as it would imply substitution + with constant items which is not correct. Functions can have different + values during view creation and view execution based on context. + + Return the identical item during view creation and prepare. + */ + if (!Item_func_sysconst::const_item()) + return this; + return const_charset_converter(tocs, true, fully_qualified_func_name()); +} + +bool Item_func_sysconst::const_item() const +{ + if (current_thd->lex->is_ps_or_view_context_analysis()) + return false; + return true; +} + bool Item_func_user::fix_fields(THD *thd, Item **ref) { return (Item_func_sysconst::fix_fields(thd, ref) || @@ -2403,21 +2447,19 @@ bool Item_func_current_role::fix_fields(THD *thd, Item **ref) Security_context *ctx= context->security_ctx ? context->security_ctx : thd->security_ctx; - if (ctx->priv_role[0]) { if (str_value.copy(ctx->priv_role, strlen(ctx->priv_role), system_charset_info)) return 1; - str_value.mark_as_const(); + null_value= maybe_null= 0; return 0; } null_value= maybe_null= 1; return 0; } - void Item_func_soundex::fix_length_and_dec() { uint32 char_length= args[0]->max_char_length(); @@ -2425,7 +2467,6 @@ void Item_func_soundex::fix_length_and_dec() DBUG_ASSERT(collation.collation != NULL); set_if_bigger(char_length, 4); fix_char_length(char_length); - tmp_value.set_charset(collation.collation); } @@ -2470,7 +2511,7 @@ static bool my_uni_isalpha(int wc) String *Item_func_soundex::val_str(String *str) { DBUG_ASSERT(fixed == 1); - String *res =args[0]->val_str(str); + String *res= args[0]->val_str(&tmp_value); char last_ch,ch; CHARSET_INFO *cs= collation.collation; my_wc_t wc; @@ -2480,10 +2521,11 @@ String *Item_func_soundex::val_str(String *str) if ((null_value= args[0]->null_value)) return 0; /* purecov: inspected */ - if (tmp_value.alloc(MY_MAX(res->length(), 4 * cs->mbminlen))) - return str; /* purecov: inspected */ - char *to= (char *) tmp_value.ptr(); - char *to_end= to + tmp_value.alloced_length(); + if (str->alloc(MY_MAX(res->length(), 4 * cs->mbminlen))) + return &tmp_value; /* purecov: inspected */ + str->set_charset(collation.collation); + char *to= (char *) str->ptr(); + char *to_end= to + str->alloced_length(); char *from= (char *) res->ptr(), *end= from + res->length(); for ( ; ; ) /* Skip pre-space */ @@ -2568,8 +2610,8 @@ String *Item_func_soundex::val_str(String *str) to+= nbytes; } - tmp_value.length((uint) (to-tmp_value.ptr())); - return &tmp_value; + str->length((uint) (to - str->ptr())); + return str; } @@ -3378,16 +3420,16 @@ String *Item_func_conv_charset::val_str(String *str) DBUG_ASSERT(fixed == 1); if (use_cached_value) return null_value ? 0 : &str_value; - String *arg= args[0]->val_str(str); + String *arg= args[0]->val_str(&tmp_value); uint dummy_errors; if (args[0]->null_value) { null_value=1; return 0; } - null_value= tmp_value.copy(arg->ptr(), arg->length(), arg->charset(), - conv_charset, &dummy_errors); - return null_value ? 0 : check_well_formed_result(&tmp_value); + null_value= str->copy(arg->ptr(), arg->length(), arg->charset(), + conv_charset, &dummy_errors); + return null_value ? 0 : check_well_formed_result(str); } void Item_func_conv_charset::fix_length_and_dec() @@ -3530,7 +3572,7 @@ String *Item_func_weight_string::val_str(String *str) DBUG_ASSERT(fixed == 1); if (args[0]->result_type() != STRING_RESULT || - !(res= args[0]->val_str(str))) + !(res= args[0]->val_str(&tmp_value))) goto nl; /* @@ -3577,19 +3619,19 @@ String *Item_func_weight_string::val_str(String *str) goto nl; } - if (tmp_value.alloc(tmp_length)) + if (str->alloc(tmp_length)) goto nl; frm_length= cs->coll->strnxfrm(cs, - (uchar *) tmp_value.ptr(), tmp_length, + (uchar *) str->ptr(), tmp_length, nweights ? nweights : tmp_length, (const uchar *) res->ptr(), res->length(), flags); DBUG_ASSERT(frm_length <= tmp_length); - tmp_value.length(frm_length); + str->length(frm_length); null_value= 0; - return &tmp_value; + return str; nl: null_value= 1; @@ -3630,18 +3672,18 @@ String *Item_func_hex::val_str_ascii(String *str) } /* Convert given string to a hex string, character by character */ - res= args[0]->val_str(str); - if (!res || tmp_value.alloc(res->length()*2+1)) + res= args[0]->val_str(&tmp_value); + if (!res || str->alloc(res->length()*2+1)) { null_value=1; return 0; } null_value=0; - tmp_value.length(res->length()*2); - tmp_value.set_charset(&my_charset_latin1); + str->length(res->length()*2); + str->set_charset(&my_charset_latin1); - octet2hex((char*) tmp_value.ptr(), res->ptr(), res->length()); - return &tmp_value; + octet2hex((char*) str->ptr(), res->ptr(), res->length()); + return str; } /** Convert given hex string to a binary string. */ @@ -3654,8 +3696,8 @@ String *Item_func_unhex::val_str(String *str) uint length; DBUG_ASSERT(fixed == 1); - res= args[0]->val_str(str); - if (!res || tmp_value.alloc(length= (1+res->length())/2)) + res= args[0]->val_str(&tmp_value); + if (!res || str->alloc(length= (1+res->length())/2)) { null_value=1; return 0; @@ -3663,8 +3705,8 @@ String *Item_func_unhex::val_str(String *str) from= res->ptr(); null_value= 0; - tmp_value.length(length); - to= (char*) tmp_value.ptr(); + str->length(length); + to= (char*) str->ptr(); if (res->length() % 2) { int hex_char; @@ -3682,7 +3724,7 @@ String *Item_func_unhex::val_str(String *str) if ((null_value= (hex_char == -1))) return 0; } - return &tmp_value; + return str; } @@ -3928,7 +3970,7 @@ String *Item_func_quote::val_str(String *str) ulong max_allowed_packet= current_thd->variables.max_allowed_packet; char *from, *to, *end, *start; - String *arg= args[0]->val_str(str); + String *arg= args[0]->val_str(&tmp_value); uint arg_length, new_length; if (!arg) // Null argument { @@ -3955,7 +3997,7 @@ String *Item_func_quote::val_str(String *str) set_if_smaller(new_length, max_allowed_packet); } - if (tmp_value.alloc(new_length)) + if (str->alloc(new_length)) goto null; if (collation.collation->mbmaxlen > 1) @@ -3963,7 +4005,7 @@ String *Item_func_quote::val_str(String *str) CHARSET_INFO *cs= collation.collation; int mblen; uchar *to_end; - to= (char*) tmp_value.ptr(); + to= (char*) str->ptr(); to_end= (uchar*) to + new_length; /* Put leading quote */ @@ -4000,14 +4042,14 @@ String *Item_func_quote::val_str(String *str) if ((mblen= cs->cset->wc_mb(cs, '\'', (uchar *) to, to_end)) <= 0) goto toolong; to+= mblen; - new_length= to - tmp_value.ptr(); + new_length= to - str->ptr(); goto ret; } /* We replace characters from the end to the beginning */ - to= (char*) tmp_value.ptr() + new_length - 1; + to= (char*) str->ptr() + new_length - 1; *to--= '\''; for (start= (char*) arg->ptr(),end= start + arg_length; end-- != start; to--) { @@ -4037,10 +4079,10 @@ String *Item_func_quote::val_str(String *str) *to= '\''; ret: - tmp_value.length(new_length); - tmp_value.set_charset(collation.collation); + str->length(new_length); + str->set_charset(collation.collation); null_value= 0; - return &tmp_value; + return str; toolong: push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, @@ -4113,7 +4155,7 @@ String *Item_func_compress::val_str(String *str) char *tmp, *last_char; DBUG_ASSERT(fixed == 1); - if (!(res= args[0]->val_str(str))) + if (!(res= args[0]->val_str(&tmp_value))) { null_value= 1; return 0; @@ -4134,13 +4176,13 @@ String *Item_func_compress::val_str(String *str) // Check new_size overflow: new_size <= res->length() if (((uint32) (new_size+5) <= res->length()) || - buffer.realloc((uint32) new_size + 4 + 1)) + str->realloc((uint32) new_size + 4 + 1)) { null_value= 1; return 0; } - body= ((Byte*)buffer.ptr()) + 4; + body= ((Byte*)str->ptr()) + 4; // As far as we have checked res->is_empty() we can use ptr() if ((err= my_compress_buffer(body, &new_size, (const uchar *)res->ptr(), @@ -4152,7 +4194,7 @@ String *Item_func_compress::val_str(String *str) return 0; } - tmp= (char*)buffer.ptr(); // int4store is a macro; avoid side effects + tmp= (char*) str->ptr(); // int4store is a macro; avoid side effects int4store(tmp, res->length() & 0x3FFFFFFF); /* This is to ensure that things works for CHAR fields, which trim ' ': */ @@ -4163,15 +4205,15 @@ String *Item_func_compress::val_str(String *str) new_size++; } - buffer.length((uint32)new_size + 4); - return &buffer; + str->length((uint32)new_size + 4); + return str; } String *Item_func_uncompress::val_str(String *str) { DBUG_ASSERT(fixed == 1); - String *res= args[0]->val_str(str); + String *res= args[0]->val_str(&tmp_value); ulong new_size; int err; uint code; @@ -4202,14 +4244,14 @@ String *Item_func_uncompress::val_str(String *str) max_allowed_packet)); goto err; } - if (buffer.realloc((uint32)new_size)) + if (str->realloc((uint32)new_size)) goto err; - if ((err= uncompress((Byte*)buffer.ptr(), &new_size, + if ((err= uncompress((Byte*)str->ptr(), &new_size, ((const Bytef*)res->ptr())+4,res->length()-4)) == Z_OK) { - buffer.length((uint32) new_size); - return &buffer; + str->length((uint32) new_size); + return str; } code= ((err == Z_BUF_ERROR) ? ER_ZLIB_Z_BUF_ERROR : diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 2886cb68f9b..1b133d1d885 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -87,7 +87,6 @@ public: class Item_func_md5 :public Item_str_ascii_func { - String tmp_value; public: Item_func_md5(Item *a) :Item_str_ascii_func(a) {} String *val_str_ascii(String *); @@ -167,7 +166,6 @@ public: class Item_func_decode_histogram :public Item_str_func { - String tmp_value; public: Item_func_decode_histogram(Item *a, Item *b) :Item_str_func(a, b) {} @@ -233,6 +231,7 @@ public: DBUG_VOID_RETURN; } String *val_str(String *str); + bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); const char *func_name() const { return "regexp_replace"; } }; @@ -253,6 +252,7 @@ public: DBUG_VOID_RETURN; } String *val_str(String *str); + bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); const char *func_name() const { return "regexp_substr"; } }; @@ -542,10 +542,7 @@ class Item_func_sysconst :public Item_str_func public: Item_func_sysconst() { collation.set(system_charset_info,DERIVATION_SYSCONST); } - Item *safe_charset_converter(CHARSET_INFO *tocs) - { - return const_charset_converter(tocs, true, fully_qualified_func_name()); - } + Item *safe_charset_converter(CHARSET_INFO *tocs); /* Used to create correct Item name in new converted item in safe_charset_converter, return string representation of this function @@ -557,6 +554,7 @@ public: return trace_unsupported_by_check_vcol_func_processor( fully_qualified_func_name()); } + bool const_item() const; }; @@ -635,7 +633,7 @@ public: String *val_str(String *) { DBUG_ASSERT(fixed == 1); - return (null_value ? 0 : &str_value); + return null_value ? NULL : &str_value; } }; @@ -677,7 +675,6 @@ public: class Item_func_format :public Item_str_ascii_func { - String tmp_str; MY_LOCALE *locale; public: Item_func_format(Item *org, Item *dec): Item_str_ascii_func(org, dec) {} @@ -731,7 +728,6 @@ public: class Item_func_binlog_gtid_pos :public Item_str_func { - String tmp_value; public: Item_func_binlog_gtid_pos(Item *arg1,Item *arg2) :Item_str_func(arg1,arg2) {} String *val_str(String *); @@ -1108,7 +1104,7 @@ public: class Item_func_compress: public Item_str_func { - String buffer; + String tmp_value; public: Item_func_compress(Item *a):Item_str_func(a){} void fix_length_and_dec(){max_length= (args[0]->max_length*120)/100+12;} @@ -1118,7 +1114,7 @@ public: class Item_func_uncompress: public Item_str_func { - String buffer; + String tmp_value; public: Item_func_uncompress(Item *a): Item_str_func(a){} void fix_length_and_dec(){ maybe_null= 1; max_length= MAX_BLOB_WIDTH; } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 70b730a5a33..198657636f6 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -329,7 +329,8 @@ bool Item_subselect::enumerate_field_refs_processor(uchar *arg) while ((upper= it++)) { - if (upper->item->walk(&Item::enumerate_field_refs_processor, FALSE, arg)) + if (upper->item && + upper->item->walk(&Item::enumerate_field_refs_processor, FALSE, arg)) return TRUE; } return FALSE; @@ -3327,7 +3328,8 @@ bool Item_in_subselect::init_cond_guards() { DBUG_ASSERT(thd); uint cols_num= left_expr->cols(); - if (!abort_on_null && left_expr->maybe_null && !pushed_cond_guards) + if (!abort_on_null && !pushed_cond_guards && + (left_expr->maybe_null || cols_num > 1)) { if (!(pushed_cond_guards= (bool*)thd->alloc(sizeof(bool) * cols_num))) return TRUE; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index fa1c3d0da90..d9bfeed418a 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -3105,7 +3105,7 @@ get_date_time_result_type(const char *format, uint length) const char *val= format; const char *end= format + length; - for (; val != end && val != end; val++) + for (; val != end; val++) { if (*val == '%' && val+1 != end) { diff --git a/sql/lock.cc b/sql/lock.cc index f7b9980ef05..965f7dcab99 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -96,7 +96,6 @@ extern HASH open_cache; static int lock_external(THD *thd, TABLE **table,uint count); static int unlock_external(THD *thd, TABLE **table,uint count); -static void print_lock_error(int error, TABLE *); /* Map the return value of thr_lock to an error from errmsg.txt */ static int thr_lock_errno_to_mysql[]= @@ -374,7 +373,7 @@ static int lock_external(THD *thd, TABLE **tables, uint count) if ((error=(*tables)->file->ha_external_lock(thd,lock_type))) { - print_lock_error(error, *tables); + (*tables)->file->print_error(error, MYF(0)); while (--i) { tables--; @@ -691,8 +690,8 @@ static int unlock_external(THD *thd, TABLE **table,uint count) (*table)->current_lock = F_UNLCK; if ((error=(*table)->file->ha_external_lock(thd, F_UNLCK))) { - error_code=error; - print_lock_error(error_code, *table); + error_code= error; + (*table)->file->print_error(error, MYF(0)); } } table++; @@ -914,36 +913,6 @@ bool lock_object_name(THD *thd, MDL_key::enum_mdl_namespace mdl_type, } -static void print_lock_error(int error, TABLE *table) -{ - int textno; - DBUG_ENTER("print_lock_error"); - - switch (error) { - case HA_ERR_LOCK_WAIT_TIMEOUT: - textno=ER_LOCK_WAIT_TIMEOUT; - break; - case HA_ERR_READ_ONLY_TRANSACTION: - textno=ER_READ_ONLY_TRANSACTION; - break; - case HA_ERR_LOCK_DEADLOCK: - textno=ER_LOCK_DEADLOCK; - break; - case HA_ERR_WRONG_COMMAND: - my_error(ER_ILLEGAL_HA, MYF(0), table->file->table_type(), - table->s->db.str, table->s->table_name.str); - DBUG_VOID_RETURN; - default: - textno=ER_CANT_LOCK; - break; - } - - my_error(textno, MYF(0), error); - - DBUG_VOID_RETURN; -} - - /**************************************************************************** Handling of global read locks diff --git a/sql/log.cc b/sql/log.cc index 596a0a449d2..c1c6a4758d7 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -9612,8 +9612,8 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name, sizeof(xev->xid)); if (!x || my_hash_insert(&xids, x)) goto err2; - break; } + break; } case BINLOG_CHECKPOINT_EVENT: if (first_round && do_xa) diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc index e856400466d..1b79f815a0f 100644 --- a/sql/multi_range_read.cc +++ b/sql/multi_range_read.cc @@ -1231,28 +1231,18 @@ bool DsMrr_impl::setup_buffer_sharing(uint key_size_in_keybuf, ptrdiff_t bytes_for_keys= (full_buf_end - full_buf) - bytes_for_rowids; - if (bytes_for_keys < key_buff_elem_size + 1) - { - ptrdiff_t add= key_buff_elem_size + 1 - bytes_for_keys; - bytes_for_keys= key_buff_elem_size + 1; - bytes_for_rowids -= add; - } - - if (bytes_for_rowids < (ptrdiff_t)rowid_buf_elem_size + 1) - { - ptrdiff_t add= (ptrdiff_t)(rowid_buf_elem_size + 1 - bytes_for_rowids); - bytes_for_rowids= (ptrdiff_t)rowid_buf_elem_size + 1; - bytes_for_keys -= add; - } + if (bytes_for_keys < key_buff_elem_size + 1 || + bytes_for_rowids < (ptrdiff_t)rowid_buf_elem_size + 1) + return TRUE; /* Failed to provide minimum space for one of the buffers */ rowid_buffer_end= full_buf + bytes_for_rowids; rowid_buffer.set_buffer_space(full_buf, rowid_buffer_end); key_buffer= &backward_key_buf; key_buffer->set_buffer_space(rowid_buffer_end, full_buf_end); - if (!key_buffer->have_space_for(key_buff_elem_size) || - !rowid_buffer.have_space_for((size_t)rowid_buf_elem_size)) - return TRUE; /* Failed to provide minimum space for one of the buffers */ + /* The above code guarantees that the buffers are big enough */ + DBUG_ASSERT(key_buffer->have_space_for(key_buff_elem_size) && + rowid_buffer.have_space_for((size_t)rowid_buf_elem_size)); return FALSE; } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index baf3d0f6758..45e6b3666bf 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3619,7 +3619,6 @@ sizeof(load_default_groups)/sizeof(load_default_groups[0]); #endif -#ifndef EMBEDDED_LIBRARY /** This function is used to check for stack overrun for pathological cases of regular expressions and 'like' expressions. @@ -3648,8 +3647,6 @@ check_enough_stack_size(int recurse_level) return 0; return check_enough_stack_size_slow(); } -#endif - /* @@ -3671,11 +3668,12 @@ static void init_pcre() { pcre_malloc= pcre_stack_malloc= my_str_malloc_mysqld; pcre_free= pcre_stack_free= my_str_free_mysqld; -#ifndef EMBEDDED_LIBRARY pcre_stack_guard= check_enough_stack_size_slow; /* See http://pcre.org/original/doc/html/pcrestack.html */ - my_pcre_frame_size= -pcre_exec(NULL, NULL, NULL, -999, -999, 0, NULL, 0) + 16; -#endif + my_pcre_frame_size= -pcre_exec(NULL, NULL, NULL, -999, -999, 0, NULL, 0); + // pcre can underestimate its stack usage. Use a safe value, as in the manual + set_if_bigger(my_pcre_frame_size, 500); + my_pcre_frame_size += 16; // Again, safety margin, see the manual } diff --git a/sql/net_serv.cc b/sql/net_serv.cc index f52549bfd0b..90a5da6a927 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. - Copyright (c) 2012, 2016, MariaDB + Copyright (c) 2012, 2017, MariaDB Corporation 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 diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 481d8445fa8..3563058282b 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -7949,8 +7949,10 @@ static SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param, DBUG_ENTER("get_full_func_mm_tree"); #ifdef HAVE_SPATIAL + Field::geometry_type sav_geom_type; if (field_item->field->type() == MYSQL_TYPE_GEOMETRY) { + sav_geom_type= ((Field_geom*) field_item->field)->geom_type; /* We have to be able to store all sorts of spatial features here */ ((Field_geom*) field_item->field)->geom_type= Field::GEOM_GEOMETRY; } @@ -7982,6 +7984,13 @@ static SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param, } } } + +#ifdef HAVE_SPATIAL + if (field_item->field->type() == MYSQL_TYPE_GEOMETRY) + { + ((Field_geom*) field_item->field)->geom_type= sav_geom_type; + } +#endif /*HAVE_SPATIAL*/ DBUG_RETURN(ftree); } diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 03204a627ed..cc63efa7d8c 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -3433,6 +3433,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join) table_map remaining_tables= 0; table_map handled_tabs= 0; join->sjm_lookup_tables= 0; + join->sjm_scan_tables= 0; for (tablenr= table_count - 1 ; tablenr != join->const_tables - 1; tablenr--) { POSITION *pos= join->best_positions + tablenr; @@ -3491,6 +3492,9 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join) for (i= tablenr; i != (first + sjm->tables - 1); i--) rem_tables |= join->best_positions[i].table->table->map; + for (i= first; i < first+ sjm->tables; i++) + join->sjm_scan_tables |= join->best_positions[i].table->table->map; + POSITION dummy; join->cur_sj_inner_tables= 0; for (i= first + sjm->tables; i <= tablenr; i++) diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 1eee5df2bc5..915477a45ed 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -892,6 +892,7 @@ char* partition_info::find_duplicate_field() */ partition_element *partition_info::get_part_elem(const char *partition_name, char *file_name, + size_t file_name_size, uint32 *part_id) { List_iterator<partition_element> part_it(partitions); @@ -913,10 +914,10 @@ partition_element *partition_info::get_part_elem(const char *partition_name, sub_part_elem->partition_name, partition_name)) { if (file_name) - create_subpartition_name(file_name, "", - part_elem->partition_name, - partition_name, - NORMAL_PART_NAME); + if (create_subpartition_name(file_name, file_name_size, "", + part_elem->partition_name, + partition_name, NORMAL_PART_NAME)) + DBUG_RETURN(NULL); *part_id= j + (i * num_subparts); DBUG_RETURN(sub_part_elem); } @@ -931,8 +932,9 @@ partition_element *partition_info::get_part_elem(const char *partition_name, part_elem->partition_name, partition_name)) { if (file_name) - create_partition_name(file_name, "", partition_name, - NORMAL_PART_NAME, TRUE); + if (create_partition_name(file_name, file_name_size, "", + partition_name, NORMAL_PART_NAME, TRUE)) + DBUG_RETURN(NULL); *part_id= i; DBUG_RETURN(part_elem); } diff --git a/sql/partition_info.h b/sql/partition_info.h index 8ad7b1fd1fd..a80295edde0 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -340,9 +340,8 @@ public: bool init_column_part(); bool add_column_list_value(THD *thd, Item *item); void set_show_version_string(String *packet); - partition_element *get_part_elem(const char *partition_name, - char *file_name, - uint32 *part_id); + partition_element *get_part_elem(const char *partition_name, char *file_name, + size_t file_name_size, uint32 *part_id); void report_part_expr_error(bool use_subpart_expr); bool set_used_partition(List<Item> &fields, List<Item> &values, diff --git a/sql/records.cc b/sql/records.cc index 940fd97d123..f7d038f8650 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -1,5 +1,6 @@ /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. + Copyright (c) 2009, 2017, MariaDB Corporation 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 diff --git a/sql/rpl_handler.cc b/sql/rpl_handler.cc index 917a9d11b5a..d97e0e07f52 100644 --- a/sql/rpl_handler.cc +++ b/sql/rpl_handler.cc @@ -261,7 +261,7 @@ int Binlog_storage_delegate::after_flush(THD *thd, thd->semisync_info= log_info; } - strcpy(log_info->log_file, log_file+dirname_length(log_file)); + strmake_buf(log_info->log_file, log_file+dirname_length(log_file)); log_info->log_pos = log_pos; FOREACH_OBSERVER(ret, after_flush, false, diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index d63bf8fc29c..c23190cda2b 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2006, 2012, Oracle and/or its affiliates. - Copyright (c) 2010, 2011, Monty Program Ab +/* Copyright (c) 2006, 2017, Oracle and/or its affiliates. + Copyright (c) 2010, 2017, MariaDB Corporation 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 @@ -715,7 +715,6 @@ void end_master_info(Master_info* mi) if (!mi->inited) DBUG_VOID_RETURN; - end_relay_log_info(&mi->rli); if (mi->fd >= 0) { end_io_cache(&mi->file); @@ -754,6 +753,7 @@ void free_key_master_info(Master_info *mi) /* We use 2 here instead of 1 just to make it easier when debugging */ mi->killed= 2; end_master_info(mi); + end_relay_log_info(&mi->rli); mi->unlock_slave_threads(); delete mi; diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 928fbd3d7c1..eac4149cb06 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2006, 2013, Oracle and/or its affiliates. - Copyright (c) 2010, 2013, Monty Program Ab +/* Copyright (c) 2006, 2017, Oracle and/or its affiliates. + Copyright (c) 2011, 2017, MariaDB Corporation 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 @@ -54,8 +54,8 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery) sync_counter(0), is_relay_log_recovery(is_slave_recovery), save_temporary_tables(0), mi(0), inuse_relaylog_list(0), last_inuse_relaylog(0), - cur_log_old_open_count(0), group_relay_log_pos(0), - event_relay_log_pos(0), + cur_log_old_open_count(0), error_on_rli_init_info(false), + group_relay_log_pos(0), event_relay_log_pos(0), #if HAVE_valgrind is_fake(FALSE), #endif @@ -119,7 +119,7 @@ int init_relay_log_info(Relay_log_info* rli, const char* info_fname) { char fname[FN_REFLEN+128]; - int info_fd; + int info_fd= -1; const char* msg = 0; int error = 0; DBUG_ENTER("init_relay_log_info"); @@ -129,6 +129,8 @@ int init_relay_log_info(Relay_log_info* rli, DBUG_RETURN(0); fn_format(fname, info_fname, mysql_data_home, "", 4+32); mysql_mutex_lock(&rli->data_lock); + if (rli->error_on_rli_init_info) + goto err; info_fd = rli->info_fd; rli->cur_log_fd = -1; rli->slave_skip_counter=0; @@ -254,8 +256,8 @@ a file name for --relay-log-index option", opt_relaylog_index_name); if ((info_fd= mysql_file_open(key_file_relay_log_info, fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0) { - sql_print_error("Failed to create a new relay log info file (\ -file '%s', errno %d)", fname, my_errno); + sql_print_error("Failed to create a new relay log info file (" + "file '%s', errno %d)", fname, my_errno); msg= current_thd->get_stmt_da()->message(); goto err; } @@ -436,16 +438,21 @@ Failed to open the existing relay log info file '%s' (errno %d)", goto err; } rli->inited= 1; + rli->error_on_rli_init_info= false; mysql_mutex_unlock(&rli->data_lock); DBUG_RETURN(0); err: - sql_print_error("%s", msg); + rli->error_on_rli_init_info= true; + if (msg) + sql_print_error("%s", msg); end_io_cache(&rli->info_file); if (info_fd >= 0) mysql_file_close(info_fd, MYF(0)); rli->info_fd= -1; + mysql_mutex_lock(rli->relay_log.get_log_lock()); rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT); + mysql_mutex_unlock(rli->relay_log.get_log_lock()); mysql_mutex_unlock(&rli->data_lock); DBUG_RETURN(1); } @@ -1101,6 +1108,8 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset, const char** errmsg) { int error=0; + const char *ln; + char name_buf[FN_REFLEN]; DBUG_ENTER("purge_relay_logs"); /* @@ -1127,12 +1136,37 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset, if (!rli->inited) { DBUG_PRINT("info", ("rli->inited == 0")); - DBUG_RETURN(0); - } - - DBUG_ASSERT(rli->slave_running == 0); - DBUG_ASSERT(rli->mi->slave_running == 0); + if (rli->error_on_rli_init_info) + { + ln= rli->relay_log.generate_name(opt_relay_logname, "-relay-bin", + 1, name_buf); + if (rli->relay_log.open_index_file(opt_relaylog_index_name, ln, TRUE)) + { + sql_print_error("Unable to purge relay log files. Failed to open relay " + "log index file:%s.", rli->relay_log.get_index_fname()); + DBUG_RETURN(1); + } + mysql_mutex_lock(rli->relay_log.get_log_lock()); + if (rli->relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND, + (rli->max_relay_log_size ? rli->max_relay_log_size : + max_binlog_size), 1, TRUE)) + { + sql_print_error("Unable to purge relay log files. Failed to open relay " + "log file:%s.", rli->relay_log.get_log_fname()); + mysql_mutex_unlock(rli->relay_log.get_log_lock()); + DBUG_RETURN(1); + } + mysql_mutex_unlock(rli->relay_log.get_log_lock()); + } + else + DBUG_RETURN(0); + } + else + { + DBUG_ASSERT(rli->slave_running == 0); + DBUG_ASSERT(rli->mi->slave_running == 0); + } mysql_mutex_lock(&rli->data_lock); /* @@ -1179,6 +1213,12 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset, rli->group_relay_log_name[0]= rli->event_relay_log_name[0]= 0; } + if (!rli->inited && rli->error_on_rli_init_info) + { + mysql_mutex_lock(rli->relay_log.get_log_lock()); + rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT); + mysql_mutex_unlock(rli->relay_log.get_log_lock()); + } err: #ifndef DBUG_OFF char buf[22]; diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 7fc41786957..e3f8e10a705 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -1,4 +1,5 @@ -/* Copyright (c) 2005, 2012, Oracle and/or its affiliates. +/* Copyright (c) 2005, 2017, Oracle and/or its affiliates. + Copyright (c) 2009, 2017, MariaDB Corporation 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 @@ -176,7 +177,14 @@ public: a different log under our feet */ uint32 cur_log_old_open_count; - + + /* + If on init_info() call error_on_rli_init_info is true that means + that previous call to init_info() terminated with an error, RESET + SLAVE must be executed and the problem fixed manually. + */ + bool error_on_rli_init_info; + /* Let's call a group (of events) : - a transaction diff --git a/sql/slave.cc b/sql/slave.cc index b1cda1129bd..f785e4f345c 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. - Copyright (c) 2009, 2017, MariaDB +/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. + Copyright (c) 2009, 2017, MariaDB Corporation 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 @@ -388,6 +388,7 @@ int init_slave() { delete active_mi; active_mi= 0; + sql_print_error("Failed to allocate memory for the Master Info structure"); goto err; } @@ -449,7 +450,6 @@ end: DBUG_RETURN(error); err: - sql_print_error("Failed to allocate memory for the Master Info structure"); error= 1; goto end; } @@ -2369,6 +2369,7 @@ static void write_ignored_events_info_to_relay_log(THD *thd, Master_info *mi) } if (rli->ign_gtids.count()) { + DBUG_ASSERT(!rli->is_in_group()); // Ensure no active transaction glev= new Gtid_list_log_event(&rli->ign_gtids, Gtid_list_log_event::FLAG_IGN_GTIDS); rli->ign_gtids.reset(); @@ -5405,7 +5406,9 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) bool gtid_skip_enqueue= false; bool got_gtid_event= false; rpl_gtid event_gtid; - +#ifndef DBUG_OFF + static uint dbug_rows_event_count= 0; +#endif /* FD_q must have been prepared for the first R_a event inside get_master_version_and_clock() @@ -5472,6 +5475,26 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) (uchar)buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT /* a way to escape */) DBUG_RETURN(queue_old_event(mi,buf,event_len)); +#ifdef ENABLED_DEBUG_SYNC + /* + A (+d,dbug.rows_events_to_delay_relay_logging)-test is supposed to + create a few Write_log_events and after receiving the 1st of them + the IO thread signals to launch the SQL thread, and sets itself to + wait for a release signal. + */ + DBUG_EXECUTE_IF("dbug.rows_events_to_delay_relay_logging", + if ((buf[EVENT_TYPE_OFFSET] == WRITE_ROWS_EVENT_V1 || + buf[EVENT_TYPE_OFFSET] == WRITE_ROWS_EVENT) && + ++dbug_rows_event_count == 2) + { + const char act[]= + "now SIGNAL start_sql_thread " + "WAIT_FOR go_on_relay_logging"; + DBUG_ASSERT(debug_sync_service); + DBUG_ASSERT(!debug_sync_set_action(current_thd, + STRING_WITH_LEN(act))); + };); +#endif mysql_mutex_lock(&mi->data_lock); switch ((uchar)buf[EVENT_TYPE_OFFSET]) { @@ -6089,6 +6112,7 @@ void end_relay_log_info(Relay_log_info* rli) mysql_mutex_t *log_lock; DBUG_ENTER("end_relay_log_info"); + rli->error_on_rli_init_info= false; if (!rli->inited) DBUG_VOID_RETURN; if (rli->info_fd >= 0) @@ -6676,9 +6700,12 @@ static Log_event* next_event(rpl_group_info *rgi, ulonglong *event_size) DBUG_RETURN(ev); } - if (rli->ign_gtids.count()) + if (rli->ign_gtids.count() && !rli->is_in_group()) { - /* We generate and return a Gtid_list, to update gtid_slave_pos. */ + /* + We generate and return a Gtid_list, to update gtid_slave_pos, + unless being in the middle of a group. + */ DBUG_PRINT("info",("seeing ignored end gtids")); ev= new Gtid_list_log_event(&rli->ign_gtids, Gtid_list_log_event::FLAG_IGN_GTIDS); diff --git a/sql/spatial.cc b/sql/spatial.cc index bfe302f332e..b03a8b6da07 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -1150,8 +1150,8 @@ int Gis_polygon::centroid_xy(double *x, double *y) const uint32 n_points, org_n_points; double prev_x, prev_y; double cur_area= 0; - double cur_cx= 0; - double cur_cy= 0; + double cur_cx= 0, cur_cy= 0; + double sum_cx= 0, sum_cy= 0; if (no_data(data, 4)) return 1; @@ -1165,17 +1165,32 @@ int Gis_polygon::centroid_xy(double *x, double *y) const while (--n_points) // One point is already read { double tmp_x, tmp_y; + double loc_area; get_point(&tmp_x, &tmp_y, data); data+= POINT_DATA_SIZE; - cur_area+= (prev_x + tmp_x) * (prev_y - tmp_y); + loc_area= prev_x * tmp_y - tmp_x * prev_y; + cur_area+= loc_area; cur_cx+= tmp_x; cur_cy+= tmp_y; + sum_cx+= (prev_x + tmp_x) * loc_area; + sum_cy+= (prev_y + tmp_y) * loc_area; + prev_x= tmp_x; prev_y= tmp_y; } - cur_area= fabs(cur_area) / 2; - cur_cx= cur_cx / (org_n_points - 1); - cur_cy= cur_cy / (org_n_points - 1); + + if (fabs(cur_area) > 1e-10) + { + cur_cx= sum_cx / cur_area / 3.0; + cur_cy= sum_cy / cur_area / 3.0; + } + else + { + cur_cx= cur_cx / (org_n_points - 1); + cur_cy= cur_cy / (org_n_points - 1); + } + + cur_area= fabs(cur_area); if (!first_loop) { diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7a87ec3bd87..f0543becc0c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -729,12 +729,6 @@ extern "C" @param buffer pointer to preferred result buffer @param length length of buffer @param max_query_len how many chars of query to copy (0 for all) - - @req LOCK_thread_count - - @note LOCK_thread_count mutex is not necessary when the function is invoked on - the currently running thread (current_thd) or if the caller in some other - way guarantees that access to thd->query is serialized. @return Pointer to string */ @@ -748,6 +742,9 @@ char *thd_get_error_context_description(THD *thd, char *buffer, const Security_context *sctx= &thd->main_security_ctx; char header[256]; int len; + + mysql_mutex_lock(&LOCK_thread_count); + /* The pointers thd->query and thd->proc_info might change since they are being modified concurrently. This is acceptable for proc_info since its @@ -803,6 +800,7 @@ char *thd_get_error_context_description(THD *thd, char *buffer, } mysql_mutex_unlock(&thd->LOCK_thd_data); } + mysql_mutex_unlock(&LOCK_thread_count); if (str.c_ptr_safe() == buffer) return buffer; @@ -1596,6 +1594,8 @@ void THD::init(void) server_status= SERVER_STATUS_AUTOCOMMIT; if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES; + if (variables.sql_mode & MODE_ANSI_QUOTES) + server_status|= SERVER_STATUS_ANSI_QUOTES; transaction.all.modified_non_trans_table= transaction.stmt.modified_non_trans_table= FALSE; @@ -4158,7 +4158,7 @@ void Security_context::destroy() if (external_user) { my_free(external_user); - user= NULL; + external_user= NULL; } my_free(ip); @@ -4368,6 +4368,10 @@ extern "C" enum thd_kill_levels thd_kill_level(const MYSQL_THD thd) however not more often than global.progress_report_time. If global.progress_report_time is 0, then don't send progress reports, but check every second if the value has changed + + We clear any errors that we get from sending the progress packet to + the client as we don't want to set an error without the caller knowing + about it. */ static void thd_send_progress(THD *thd) @@ -4384,8 +4388,12 @@ static void thd_send_progress(THD *thd) thd->progress.next_report_time= (report_time + seconds_to_next * 1000000000ULL); if (global_system_variables.progress_report_time && - thd->variables.progress_report_time) + thd->variables.progress_report_time && !thd->is_error()) + { net_send_progress_packet(thd); + if (thd->is_error()) + thd->clear_error(); + } } } diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index af5b016df9d..2ca97a32071 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -537,6 +537,8 @@ bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived) DBUG_ASSERT(derived->table); } } + else + derived->table= derived->merge_underlying_list->table; DBUG_RETURN(FALSE); } diff --git a/sql/sql_load.cc b/sql/sql_load.cc index c391cfba00c..fe72d40b802 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. - Copyright (c) 2010, 2016, MariaDB + Copyright (c) 2010, 2017, MariaDB Corporation 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 diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f39566cec34..9f0b6e25a5c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1168,20 +1168,16 @@ static my_bool deny_updates_if_read_only_option(THD *thd, if (lex->sql_command == SQLCOM_UPDATE_MULTI) DBUG_RETURN(FALSE); - const my_bool create_temp_tables= - (lex->sql_command == SQLCOM_CREATE_TABLE) && - lex->create_info.tmp_table(); - - const my_bool drop_temp_tables= - (lex->sql_command == SQLCOM_DROP_TABLE) && - lex->drop_temporary; - - const my_bool update_real_tables= - some_non_temp_table_to_be_updated(thd, all_tables) && - !(create_temp_tables || drop_temp_tables); - + /* + a table-to-be-created is not in the temp table list yet, + so CREATE TABLE needs a special treatment + */ + const bool update_real_tables= + lex->sql_command == SQLCOM_CREATE_TABLE + ? !(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) + : some_non_temp_table_to_be_updated(thd, all_tables); - const my_bool create_or_drop_databases= + const bool create_or_drop_databases= (lex->sql_command == SQLCOM_CREATE_DB) || (lex->sql_command == SQLCOM_DROP_DB); @@ -1719,9 +1715,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd, kill_zombie_dump_threads(slave_server_id); thd->variables.server_id = slave_server_id; - general_log_print(thd, command, "Log: '%s' Pos: %ld", packet+10, - (long) pos); - mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags); + const char *name= packet + 10; + size_t nlen= strlen(name); + + general_log_print(thd, command, "Log: '%s' Pos: %lu", name, pos); + if (nlen < FN_REFLEN) + mysql_binlog_send(thd, thd->strmake(name, nlen), (my_off_t)pos, flags); unregister_slave(thd,1,1); /* fake COM_QUIT -- if we get here, the thread needs to terminate */ error = TRUE; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index be7824aae9e..960b90a3cc7 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1870,6 +1870,22 @@ static int add_subpartition_by(File fptr) return err + add_partition_by(fptr); } +static int add_name_string(File fptr, const char *name) +{ + int err; + String name_string("", 0, system_charset_info); + THD *thd= current_thd; + ulonglong save_sql_mode= thd->variables.sql_mode; + thd->variables.sql_mode&= ~MODE_ANSI_QUOTES; + ulonglong save_options= thd->variables.option_bits; + thd->variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE; + append_identifier(thd, &name_string, name, strlen(name)); + thd->variables.sql_mode= save_sql_mode; + thd->variables.option_bits= save_options; + err= add_string_object(fptr, &name_string); + return err; +} + static int add_part_field_list(File fptr, List<char> field_list) { uint i, num_fields; @@ -1881,15 +1897,7 @@ static int add_part_field_list(File fptr, List<char> field_list) err+= add_begin_parenthesis(fptr); while (i < num_fields) { - const char *field_str= part_it++; - String field_string("", 0, system_charset_info); - THD *thd= current_thd; - ulonglong save_options= thd->variables.option_bits; - thd->variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE; - append_identifier(thd, &field_string, field_str, - strlen(field_str)); - thd->variables.option_bits= save_options; - err+= add_string_object(fptr, &field_string); + err+= add_name_string(fptr, part_it++); if (i != (num_fields-1)) err+= add_comma(fptr); i++; @@ -1898,20 +1906,6 @@ static int add_part_field_list(File fptr, List<char> field_list) return err; } -static int add_name_string(File fptr, const char *name) -{ - int err; - String name_string("", 0, system_charset_info); - THD *thd= current_thd; - ulonglong save_options= thd->variables.option_bits; - thd->variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE; - append_identifier(thd, &name_string, name, - strlen(name)); - thd->variables.option_bits= save_options; - err= add_string_object(fptr, &name_string); - return err; -} - static int add_int(File fptr, longlong number) { char buff[32]; @@ -5994,8 +5988,8 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; DDL_LOG_MEMORY_ENTRY *log_entry; - char tmp_path[FN_REFLEN]; - char normal_path[FN_REFLEN]; + char tmp_path[FN_REFLEN + 1]; + char normal_path[FN_REFLEN + 1]; List_iterator<partition_element> part_it(part_info->partitions); uint temp_partitions= part_info->temp_partitions.elements; uint num_elements= part_info->partitions.elements; @@ -6019,14 +6013,15 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, ddl_log_entry.next_entry= *next_entry; ddl_log_entry.handler_name= ha_resolve_storage_engine_name(sub_elem->engine_type); - create_subpartition_name(tmp_path, path, - part_elem->partition_name, - sub_elem->partition_name, - TEMP_PART_NAME); - create_subpartition_name(normal_path, path, - part_elem->partition_name, - sub_elem->partition_name, - NORMAL_PART_NAME); + if (create_subpartition_name(tmp_path, sizeof(tmp_path), path, + part_elem->partition_name, + sub_elem->partition_name, + TEMP_PART_NAME) || + create_subpartition_name(normal_path, sizeof(normal_path), path, + part_elem->partition_name, + sub_elem->partition_name, + NORMAL_PART_NAME)) + DBUG_RETURN(TRUE); ddl_log_entry.name= normal_path; ddl_log_entry.from_name= tmp_path; if (part_elem->part_state == PART_IS_CHANGED) @@ -6047,12 +6042,13 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, ddl_log_entry.next_entry= *next_entry; ddl_log_entry.handler_name= ha_resolve_storage_engine_name(part_elem->engine_type); - create_partition_name(tmp_path, path, - part_elem->partition_name, - TEMP_PART_NAME, TRUE); - create_partition_name(normal_path, path, - part_elem->partition_name, - NORMAL_PART_NAME, TRUE); + if (create_partition_name(tmp_path, sizeof(tmp_path), path, + part_elem->partition_name, TEMP_PART_NAME, + TRUE) || + create_partition_name(normal_path, sizeof(normal_path), path, + part_elem->partition_name, NORMAL_PART_NAME, + TRUE)) + DBUG_RETURN(TRUE); ddl_log_entry.name= normal_path; ddl_log_entry.from_name= tmp_path; if (part_elem->part_state == PART_IS_CHANGED) @@ -6091,7 +6087,7 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; DDL_LOG_MEMORY_ENTRY *log_entry; - char tmp_path[FN_LEN]; + char tmp_path[FN_REFLEN + 1]; List_iterator<partition_element> part_it(part_info->partitions); List_iterator<partition_element> temp_it(part_info->temp_partitions); uint num_temp_partitions= part_info->temp_partitions.elements; @@ -6130,10 +6126,10 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, ddl_log_entry.next_entry= *next_entry; ddl_log_entry.handler_name= ha_resolve_storage_engine_name(sub_elem->engine_type); - create_subpartition_name(tmp_path, path, - part_elem->partition_name, - sub_elem->partition_name, - name_variant); + if (create_subpartition_name(tmp_path, sizeof(tmp_path), path, + part_elem->partition_name, + sub_elem->partition_name, name_variant)) + DBUG_RETURN(TRUE); ddl_log_entry.name= tmp_path; if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) { @@ -6149,9 +6145,10 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, ddl_log_entry.next_entry= *next_entry; ddl_log_entry.handler_name= ha_resolve_storage_engine_name(part_elem->engine_type); - create_partition_name(tmp_path, path, - part_elem->partition_name, - name_variant, TRUE); + if (create_partition_name(tmp_path, sizeof(tmp_path), path, + part_elem->partition_name, name_variant, + TRUE)) + DBUG_RETURN(TRUE); ddl_log_entry.name= tmp_path; if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) { @@ -8263,31 +8260,41 @@ static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *part_iter) return res; } +/* used in error messages below */ +static const char *longest_str(const char *s1, const char *s2, + const char *s3=0) +{ + if (strlen(s2) > strlen(s1)) s1= s2; + if (s3 && strlen(s3) > strlen(s1)) s1= s3; + return s1; +} + /* Create partition names SYNOPSIS create_partition_name() - out:out Created partition name string + out:out The buffer for the created partition name string + must be *at least* of FN_REFLEN+1 bytes in1 First part in2 Second part name_variant Normal, temporary or renamed partition name RETURN VALUE - NONE + 0 if ok, error if name too long DESCRIPTION This method is used to calculate the partition name, service routine to the del_ren_cre_table method. */ -void create_partition_name(char *out, const char *in1, - const char *in2, uint name_variant, - bool translate) +int create_partition_name(char *out, size_t outlen, const char *in1, + const char *in2, uint name_variant, bool translate) { char transl_part_name[FN_REFLEN]; - const char *transl_part; + const char *transl_part, *end; + DBUG_ASSERT(outlen >= FN_REFLEN + 1); // consistency! same limit everywhere if (translate) { @@ -8297,11 +8304,17 @@ void create_partition_name(char *out, const char *in1, else transl_part= in2; if (name_variant == NORMAL_PART_NAME) - strxmov(out, in1, "#P#", transl_part, NullS); + end= strxnmov(out, outlen-1, in1, "#P#", transl_part, NullS); else if (name_variant == TEMP_PART_NAME) - strxmov(out, in1, "#P#", transl_part, "#TMP#", NullS); + end= strxnmov(out, outlen-1, in1, "#P#", transl_part, "#TMP#", NullS); else if (name_variant == RENAMED_PART_NAME) - strxmov(out, in1, "#P#", transl_part, "#REN#", NullS); + end= strxnmov(out, outlen-1, in1, "#P#", transl_part, "#REN#", NullS); + if (end - out == static_cast<ptrdiff_t>(outlen-1)) + { + my_error(ER_PATH_LENGTH, MYF(0), longest_str(in1, transl_part)); + return HA_WRONG_CREATE_OPTION; + } + return 0; } @@ -8310,37 +8323,46 @@ void create_partition_name(char *out, const char *in1, SYNOPSIS create_subpartition_name() - out:out Created partition name string + out:out The buffer for the created partition name string + must be *at least* of FN_REFLEN+1 bytes in1 First part in2 Second part in3 Third part name_variant Normal, temporary or renamed partition name RETURN VALUE - NONE + 0 if ok, error if name too long DESCRIPTION This method is used to calculate the subpartition name, service routine to the del_ren_cre_table method. */ -void create_subpartition_name(char *out, const char *in1, - const char *in2, const char *in3, - uint name_variant) +int create_subpartition_name(char *out, size_t outlen, + const char *in1, const char *in2, + const char *in3, uint name_variant) { - char transl_part_name[FN_REFLEN], transl_subpart_name[FN_REFLEN]; + char transl_part_name[FN_REFLEN], transl_subpart_name[FN_REFLEN], *end; + DBUG_ASSERT(outlen >= FN_REFLEN + 1); // consistency! same limit everywhere tablename_to_filename(in2, transl_part_name, FN_REFLEN); tablename_to_filename(in3, transl_subpart_name, FN_REFLEN); if (name_variant == NORMAL_PART_NAME) - strxmov(out, in1, "#P#", transl_part_name, - "#SP#", transl_subpart_name, NullS); + end= strxnmov(out, outlen-1, in1, "#P#", transl_part_name, + "#SP#", transl_subpart_name, NullS); else if (name_variant == TEMP_PART_NAME) - strxmov(out, in1, "#P#", transl_part_name, - "#SP#", transl_subpart_name, "#TMP#", NullS); + end= strxnmov(out, outlen-1, in1, "#P#", transl_part_name, + "#SP#", transl_subpart_name, "#TMP#", NullS); else if (name_variant == RENAMED_PART_NAME) - strxmov(out, in1, "#P#", transl_part_name, - "#SP#", transl_subpart_name, "#REN#", NullS); + end= strxnmov(out, outlen-1, in1, "#P#", transl_part_name, + "#SP#", transl_subpart_name, "#REN#", NullS); + if (end - out == static_cast<ptrdiff_t>(outlen-1)) + { + my_error(ER_PATH_LENGTH, MYF(0), + longest_str(in1, transl_part_name, transl_subpart_name)); + return HA_WRONG_CREATE_OPTION; + } + return 0; } uint get_partition_field_store_length(Field *field) diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 5da132661c9..1b7735b5e96 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -274,12 +274,12 @@ bool partition_key_modified(TABLE *table, const MY_BITMAP *fields); #define partition_key_modified(X,Y) 0 #endif -void create_partition_name(char *out, const char *in1, - const char *in2, uint name_variant, - bool translate); -void create_subpartition_name(char *out, const char *in1, - const char *in2, const char *in3, - uint name_variant); +int __attribute__((warn_unused_result)) + create_partition_name(char *out, size_t outlen, const char *in1, const char + *in2, uint name_variant, bool translate); +int __attribute__((warn_unused_result)) + create_subpartition_name(char *out, size_t outlen, const char *in1, const + char *in2, const char *in3, uint name_variant); void set_field_ptr(Field **ptr, const uchar *new_buf, const uchar *old_buf); void set_key_field_ptr(KEY *key_info, const uchar *new_buf, diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc index f520281135a..2a76c8d6671 100644 --- a/sql/sql_partition_admin.cc +++ b/sql/sql_partition_admin.cc @@ -491,7 +491,7 @@ bool Sql_cmd_alter_table_exchange_partition:: partition_element *part_elem; char *partition_name; char temp_name[FN_REFLEN+1]; - char part_file_name[FN_REFLEN+1]; + char part_file_name[2*FN_REFLEN+1]; char swap_file_name[FN_REFLEN+1]; char temp_file_name[FN_REFLEN+1]; uint swap_part_id; @@ -586,9 +586,9 @@ bool Sql_cmd_alter_table_exchange_partition:: temp_name, "", FN_IS_TMP); if (!(part_elem= part_table->part_info->get_part_elem(partition_name, - part_file_name + - part_file_name_len, - &swap_part_id))) + part_file_name + part_file_name_len, + sizeof(part_file_name) - part_file_name_len, + &swap_part_id))) { // my_error(ER_UNKNOWN_PARTITION, MYF(0), partition_name, // part_table->alias); diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index eb8e0004380..df24f398e97 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -306,6 +306,12 @@ static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref plugin); static void intern_plugin_unlock(LEX *lex, plugin_ref plugin); static void reap_plugins(void); +bool plugin_is_forced(struct st_plugin_int *p) +{ + return p->load_option == PLUGIN_FORCE || + p->load_option == PLUGIN_FORCE_PLUS_PERMANENT; +} + static void report_error(int where_to, uint error, ...) { va_list args; @@ -1360,7 +1366,7 @@ static int plugin_initialize(MEM_ROOT *tmp_root, struct st_plugin_int *plugin, if (options_only || state == PLUGIN_IS_DISABLED) { - ret= 0; + ret= !options_only && plugin_is_forced(plugin); goto err; } @@ -1671,8 +1677,7 @@ int plugin_init(int *argc, char **argv, int flags) while ((plugin_ptr= *(--reap))) { mysql_mutex_unlock(&LOCK_plugin); - if (plugin_ptr->load_option == PLUGIN_FORCE || - plugin_ptr->load_option == PLUGIN_FORCE_PLUS_PERMANENT) + if (plugin_is_forced(plugin_ptr)) reaped_mandatory_plugin= TRUE; plugin_deinitialize(plugin_ptr, true); mysql_mutex_lock(&LOCK_plugin); @@ -3542,8 +3547,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, plugin_dash.length + 1); strxmov(plugin_name_with_prefix_ptr, plugin_dash.str, plugin_name_ptr, NullS); - if (tmp->load_option != PLUGIN_FORCE && - tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT) + if (!plugin_is_forced(tmp)) { /* support --skip-plugin-foo syntax */ options[0].name= plugin_name_ptr; @@ -3861,8 +3865,7 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, We adjust the default value to account for the hardcoded exceptions we have set for the federated and ndbcluster storage engines. */ - if (tmp->load_option != PLUGIN_FORCE && - tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT) + if (!plugin_is_forced(tmp)) opts[0].def_value= opts[1].def_value= plugin_load_option; error= handle_options(argc, &argv, opts, NULL); @@ -3878,8 +3881,7 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, Set plugin loading policy from option value. First element in the option list is always the <plugin name> option value. */ - if (tmp->load_option != PLUGIN_FORCE && - tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT) + if (!plugin_is_forced(tmp)) plugin_load_option= (enum_plugin_load_option) *(ulong*) opts[0].value; } diff --git a/sql/sql_priv.h b/sql/sql_priv.h index 09a22ba0444..2c9a22d4bd9 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -121,7 +121,7 @@ #define OPTION_AUTOCOMMIT (1ULL << 8) // THD, user #define OPTION_BIG_SELECTS (1ULL << 9) // THD, user #define OPTION_LOG_OFF (1ULL << 10) // THD, user -#define OPTION_QUOTE_SHOW_CREATE (1ULL << 11) // THD, user, unused +#define OPTION_QUOTE_SHOW_CREATE (1ULL << 11) // THD, user #define TMP_TABLE_ALL_COLUMNS (1ULL << 12) // SELECT, intern #define OPTION_WARNINGS (1ULL << 13) // THD, user #define OPTION_AUTO_IS_NULL (1ULL << 14) // THD, user, binlog diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index bd0d31213e6..f1bbe58a8b8 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2008, 2014, SkySQL Ab. +/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. + Copyright (c) 2008, 2017, MariaDB Corporation 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 @@ -2665,6 +2665,7 @@ impossible position"; loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK); break; } + /* fall through */ default: errmsg = "could not find next log"; my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; @@ -3150,6 +3151,7 @@ int reset_slave(THD *thd, Master_info* mi) // close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0 end_master_info(mi); + end_relay_log_info(&mi->rli); // and delete these two files create_logfile_name_with_suffix(master_info_file_tmp, sizeof(master_info_file_tmp), diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6a281a4583e..7be9bfb7838 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1305,6 +1305,7 @@ TODO: make view to decide if it is possible to write to WHERE directly or make S DBUG_PRINT("info",("Select tables optimized away")); zero_result_cause= "Select tables optimized away"; tables_list= 0; // All tables resolved + select_lex->min_max_opt_list.empty(); const_tables= top_join_tab_count= table_count; /* Extract all table-independent conditions and replace the WHERE @@ -2942,8 +2943,11 @@ void JOIN::exec_inner() if (sort_table_cond) { if (!curr_table->select) + { if (!(curr_table->select= new SQL_SELECT)) DBUG_VOID_RETURN; + curr_table->select->head= curr_table->table; + } if (!curr_table->select->cond) curr_table->select->cond= sort_table_cond; else @@ -8076,6 +8080,63 @@ bool JOIN_TAB::hash_join_is_possible() } +/** + @brief + Check whether a KEYUSE can be really used for access this join table + + @param join Join structure with the best join order + for which the check is performed + @param keyuse Evaluated KEYUSE structure + + @details + This function is supposed to be used after the best execution plan have been + already chosen and the JOIN_TAB array for the best join order been already set. + For a given KEYUSE to access this JOIN_TAB in the best execution plan the + function checks whether it really can be used. The function first performs + the check with access_from_tables_is_allowed(). If it succeeds it checks + whether the keyuse->val does not use some fields of a materialized semijoin + nest that cannot be used to build keys to access outer tables. + Such KEYUSEs exists for the query like this: + select * from ot + where ot.c in (select it1.c from it1, it2 where it1.c=f(it2.c)) + Here we have two KEYUSEs to access table ot: with val=it1.c and val=f(it2.c). + However if the subquery was materialized the second KEYUSE cannot be employed + to access ot. + + @retval true the given keyuse can be used for ref access of this JOIN_TAB + @retval false otherwise +*/ + +bool JOIN_TAB::keyuse_is_valid_for_access_in_chosen_plan(JOIN *join, + KEYUSE *keyuse) +{ + if (!access_from_tables_is_allowed(keyuse->used_tables, + join->sjm_lookup_tables)) + return false; + if (join->sjm_scan_tables & table->map) + return true; + table_map keyuse_sjm_scan_tables= keyuse->used_tables & + join->sjm_scan_tables; + if (!keyuse_sjm_scan_tables) + return true; + uint sjm_tab_nr= 0; + while (!(keyuse_sjm_scan_tables & table_map(1) << sjm_tab_nr)) + sjm_tab_nr++; + JOIN_TAB *sjm_tab= join->map2table[sjm_tab_nr]; + TABLE_LIST *emb_sj_nest= sjm_tab->emb_sj_nest; + if (!(emb_sj_nest->sj_mat_info && emb_sj_nest->sj_mat_info->is_used && + emb_sj_nest->sj_mat_info->is_sj_scan)) + return true; + st_select_lex *sjm_sel= emb_sj_nest->sj_subq_pred->unit->first_select(); + for (uint i= 0; i < sjm_sel->item_list.elements; i++) + { + if (sjm_sel->ref_pointer_array[i] == keyuse->val) + return true; + } + return false; +} + + static uint cache_record_length(JOIN *join,uint idx) { @@ -8623,6 +8684,7 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, do { if (!(~used_tables & keyuse->used_tables) && + join_tab->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse) && are_tables_local(join_tab, keyuse->used_tables)) { if (first_keyuse) @@ -8637,6 +8699,8 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, { if (curr->keypart == keyuse->keypart && !(~used_tables & curr->used_tables) && + join_tab->keyuse_is_valid_for_access_in_chosen_plan(join, + keyuse) && are_tables_local(join_tab, curr->used_tables)) break; } @@ -8671,6 +8735,7 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, do { if (!(~used_tables & keyuse->used_tables) && + join_tab->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse) && are_tables_local(join_tab, keyuse->used_tables)) { bool add_key_part= TRUE; @@ -8680,7 +8745,9 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, { if (curr->keypart == keyuse->keypart && !(~used_tables & curr->used_tables) && - are_tables_local(join_tab, curr->used_tables)) + join_tab->keyuse_is_valid_for_access_in_chosen_plan(join, + curr) && + are_tables_local(join_tab, curr->used_tables)) { keyuse->keypart= NO_KEYPART; add_key_part= FALSE; @@ -8782,8 +8849,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, do { if (!(~used_tables & keyuse->used_tables) && - j->access_from_tables_is_allowed(keyuse->used_tables, - join->sjm_lookup_tables)) + j->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse)) { if (are_tables_local(j, keyuse->val->used_tables())) { @@ -8853,8 +8919,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, for (i=0 ; i < keyparts ; keyuse++,i++) { while (((~used_tables) & keyuse->used_tables) || - !j->access_from_tables_is_allowed(keyuse->used_tables, - join->sjm_lookup_tables) || + !j->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse) || keyuse->keypart == NO_KEYPART || (keyuse->keypart != (is_hash_join_key_no(key) ? diff --git a/sql/sql_select.h b/sql/sql_select.h index d51bca785a5..4f1b7bd7e05 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -534,6 +534,8 @@ typedef struct st_join_table { !(used_sjm_lookup_tables & ~emb_sj_nest->sj_inner_tables)); } + bool keyuse_is_valid_for_access_in_chosen_plan(JOIN *join, KEYUSE *keyuse); + void remove_redundant_bnl_scan_conds(); } JOIN_TAB; @@ -1000,6 +1002,11 @@ public: to materialize and access by lookups */ table_map sjm_lookup_tables; + /** + Bitmap of semijoin tables that the chosen plan decided + to materialize to scan the results of materialization + */ + table_map sjm_scan_tables; /* Constant tables for which we have found a row (as opposed to those for which we didn't). @@ -1341,6 +1348,7 @@ public: pre_sort_join_tab= NULL; emb_sjm_nest= NULL; sjm_lookup_tables= 0; + sjm_scan_tables= 0; exec_saved_explain= false; /* diff --git a/sql/sql_show.cc b/sql/sql_show.cc index ce9815216bb..1918cbab720 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1169,8 +1169,13 @@ bool mysqld_show_create_db(THD *thd, LEX_STRING *dbname, if (test_all_bits(sctx->master_access, DB_ACLS)) db_access=DB_ACLS; else - db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname->str, 0) | - sctx->master_access); + { + db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname->str, 0) | + sctx->master_access; + if (sctx->priv_role[0]) + db_access|= acl_get("", "", sctx->priv_role, dbname->str, 0); + } + if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname->str)) { status_var_increment(thd->status_var.access_denied_errors); @@ -5170,8 +5175,10 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond) } #ifndef NO_EMBEDDED_ACCESS_CHECKS if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) || - acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0) || - !check_grant_db(thd, db_name->str)) + acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, false) || + (sctx->priv_role[0] ? + acl_get("", "", sctx->priv_role, db_name->str, false) : 0) || + !check_grant_db(thd, db_name->str)) #endif { load_db_opt_by_name(thd, db_name->str, &create); @@ -5359,7 +5366,10 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, HA_STATUS_TIME | HA_STATUS_VARIABLE_EXTRA | HA_STATUS_AUTO)) != 0) + { + file->print_error(info_error, MYF(0)); goto err; + } enum row_type row_type = file->get_row_type(); switch (row_type) { diff --git a/sql/sql_union.cc b/sql/sql_union.cc index cfa907b9ddc..16de451211f 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. - Copyright (c) 2010, 2014, SkySQL Ab. +/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. + Copyright (c) 2010, 2017, Corporation 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 @@ -360,6 +360,19 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, Item *item_tmp; while ((item_tmp= it++)) { + /* + If the outer query has a GROUP BY clause, an outer reference to this + query block may have been wrapped in a Item_outer_ref, which has not + been fixed yet. An Item_type_holder must be created based on a fixed + Item, so use the inner Item instead. + */ + DBUG_ASSERT(item_tmp->fixed || + (item_tmp->type() == Item::REF_ITEM && + ((Item_ref *)(item_tmp))->ref_type() == + Item_ref::OUTER_REF)); + if (!item_tmp->fixed) + item_tmp= item_tmp->real_item(); + /* Error's in 'new' will be detected after loop */ types.push_back(new Item_type_holder(thd_arg, item_tmp)); } @@ -1076,4 +1089,3 @@ void st_select_lex_unit::set_unique_exclude() } } } - diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 4ae5379289e..000a424faeb 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2920,6 +2920,10 @@ static bool fix_sql_mode(sys_var *self, THD *thd, enum_var_type type) thd->server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES; else thd->server_status&= ~SERVER_STATUS_NO_BACKSLASH_ESCAPES; + if (thd->variables.sql_mode & MODE_ANSI_QUOTES) + thd->server_status|= SERVER_STATUS_ANSI_QUOTES; + else + thd->server_status&= ~SERVER_STATUS_ANSI_QUOTES; } return false; } diff --git a/sql/threadpool_unix.cc b/sql/threadpool_unix.cc index 9e2ffc9aee0..7689816ca8b 100644 --- a/sql/threadpool_unix.cc +++ b/sql/threadpool_unix.cc @@ -982,24 +982,26 @@ static void thread_group_close(thread_group_t *thread_group) if (pipe(thread_group->shutdown_pipe)) { - DBUG_VOID_RETURN; + goto end; } /* Wake listener */ if (io_poll_associate_fd(thread_group->pollfd, thread_group->shutdown_pipe[0], NULL)) { - DBUG_VOID_RETURN; + goto end; + } + { + char c= 0; + if (write(thread_group->shutdown_pipe[1], &c, 1) < 0) + goto end; } - char c= 0; - if (write(thread_group->shutdown_pipe[1], &c, 1) < 0) - DBUG_VOID_RETURN; - /* Wake all workers. */ while(wake_thread(thread_group) == 0) { } +end: mysql_mutex_unlock(&thread_group->mutex); DBUG_VOID_RETURN; diff --git a/sql/uniques.cc b/sql/uniques.cc index c755293035b..31c00667440 100644 --- a/sql/uniques.cc +++ b/sql/uniques.cc @@ -483,7 +483,7 @@ void put_counter_into_merged_element(void *ptr, uint ofs, element_count cnt) <> 0 error */ -static bool merge_walk(uchar *merge_buffer, ulong merge_buffer_size, +static bool merge_walk(uchar *merge_buffer, size_t merge_buffer_size, uint key_length, BUFFPEK *begin, BUFFPEK *end, tree_walk_action walk_action, void *walk_action_arg, qsort_cmp2 compare, void *compare_arg, @@ -492,7 +492,7 @@ static bool merge_walk(uchar *merge_buffer, ulong merge_buffer_size, BUFFPEK_COMPARE_CONTEXT compare_context = { compare, compare_arg }; QUEUE queue; if (end <= begin || - merge_buffer_size < (ulong) (key_length * (end - begin + 1)) || + merge_buffer_size < (size_t) (key_length * (end - begin + 1)) || init_queue(&queue, (uint) (end - begin), offsetof(BUFFPEK, key), 0, buffpek_compare, &compare_context, 0, 0)) return 1; @@ -642,15 +642,19 @@ bool Unique::walk(TABLE *table, tree_walk_action action, void *walk_action_arg) return 1; if (flush_io_cache(&file) || reinit_io_cache(&file, READ_CACHE, 0L, 0, 0)) return 1; - size_t buff_sz= (max_in_memory_size / full_size + 1) * full_size; + /* + merge_buffer must fit at least MERGEBUFF2 keys, because + merge_index() can merge that many BUFFPEKs at once. + */ + size_t buff_sz= MY_MAX(MERGEBUFF2, max_in_memory_size/full_size+1) * full_size; if (!(merge_buffer = (uchar *)my_malloc(buff_sz, MYF(MY_THREAD_SPECIFIC|MY_WME)))) return 1; if (buff_sz < full_size * (file_ptrs.elements + 1UL)) res= merge(table, merge_buffer, buff_sz >= full_size * MERGEBUFF2) ; - + if (!res) - { - res= merge_walk(merge_buffer, (ulong) max_in_memory_size, full_size, + { + res= merge_walk(merge_buffer, buff_sz, full_size, (BUFFPEK *) file_ptrs.buffer, (BUFFPEK *) file_ptrs.buffer + file_ptrs.elements, action, walk_action_arg, |