diff options
author | Alexander Nozdrin <alik@sun.com> | 2010-02-05 15:05:37 +0300 |
---|---|---|
committer | Alexander Nozdrin <alik@sun.com> | 2010-02-05 15:05:37 +0300 |
commit | a45ea00b32a71ef5d123e102a7379f7d79a3dbbb (patch) | |
tree | 0bf2d7fce335a1c38da55def00c6bfc5304db2ee /sql | |
parent | ad935d47088485c59e6425347307b7b908790e3d (diff) | |
parent | 619037517f6827131f0f6367df57e28d1b695626 (diff) | |
download | mariadb-git-a45ea00b32a71ef5d123e102a7379f7d79a3dbbb.tar.gz |
Manual merge from mysql-next-mr.
Conflicts:
- sql/sys_vars.cc
Diffstat (limited to 'sql')
43 files changed, 665 insertions, 239 deletions
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index a6f249d286f..fd2c5a556a8 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -1045,6 +1045,7 @@ update_timing_fields_for_event(THD *thd, TABLE *table= NULL; Field **fields; int ret= 1; + bool save_binlog_row_based; DBUG_ENTER("Event_db_repository::update_timing_fields_for_event"); @@ -1052,8 +1053,8 @@ update_timing_fields_for_event(THD *thd, Turn off row binlogging of event timing updates. These are not used for RBR of events replicated to the slave. */ - if (thd->is_current_stmt_binlog_format_row()) - thd->clear_current_stmt_binlog_format_row(); + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); + thd->clear_current_stmt_binlog_format_row(); DBUG_ASSERT(thd->security_ctx->master_access & SUPER_ACL); @@ -1095,6 +1096,8 @@ update_timing_fields_for_event(THD *thd, end: if (table) close_thread_tables(thd); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(test(ret)); } diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 5d8455fa88b..733f2a7167f 100644..100755 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -237,8 +237,9 @@ event_scheduler_thread(void *arg) if (!res) scheduler->run(thd); + DBUG_LEAVE; // Against gcc warnings my_thread_end(); - DBUG_RETURN(0); // Against gcc warnings + return 0; } diff --git a/sql/events.cc b/sql/events.cc index ad98e257f79..73f3427607d 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -294,6 +294,7 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, bool if_not_exists) { int ret; + bool save_binlog_row_based; DBUG_ENTER("Events::create_event"); /* @@ -334,8 +335,8 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, Turn off row binlogging of this statement and use statement-based so that all supporting tables are updated for CREATE EVENT command. */ - if (thd->is_current_stmt_binlog_format_row()) - thd->clear_current_stmt_binlog_format_row(); + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); + thd->clear_current_stmt_binlog_format_row(); mysql_mutex_lock(&LOCK_event_metadata); @@ -375,6 +376,8 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, { sql_print_error("Event Error: An error occurred while creating query string, " "before writing it into binary log."); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(TRUE); } /* If the definer is not set or set to CURRENT_USER, the value of CURRENT_USER @@ -383,6 +386,8 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, } } mysql_mutex_unlock(&LOCK_event_metadata); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(ret); } @@ -412,6 +417,7 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, LEX_STRING *new_dbname, LEX_STRING *new_name) { int ret; + bool save_binlog_row_based; Event_queue_element *new_element; DBUG_ENTER("Events::update_event"); @@ -465,8 +471,8 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, Turn off row binlogging of this statement and use statement-based so that all supporting tables are updated for UPDATE EVENT command. */ - if (thd->is_current_stmt_binlog_format_row()) - thd->clear_current_stmt_binlog_format_row(); + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); + thd->clear_current_stmt_binlog_format_row(); mysql_mutex_lock(&LOCK_event_metadata); @@ -502,6 +508,8 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, } } mysql_mutex_unlock(&LOCK_event_metadata); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(ret); } @@ -535,6 +543,7 @@ bool Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists) { int ret; + bool save_binlog_row_based; DBUG_ENTER("Events::drop_event"); /* @@ -561,8 +570,8 @@ Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists) Turn off row binlogging of this statement and use statement-based so that all supporting tables are updated for DROP EVENT command. */ - if (thd->is_current_stmt_binlog_format_row()) - thd->clear_current_stmt_binlog_format_row(); + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); + thd->clear_current_stmt_binlog_format_row(); mysql_mutex_lock(&LOCK_event_metadata); /* On error conditions my_error() is called so no need to handle here */ @@ -575,6 +584,8 @@ Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists) ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } mysql_mutex_unlock(&LOCK_event_metadata); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(ret); } @@ -768,7 +779,7 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS) { DBUG_ASSERT(thd->lex->select_lex.db); - if (!is_infoschema_db(thd->lex->select_lex.db) && // There is no events in I_S + if (!is_infoschema_db(thd->lex->select_lex.db) && // There is no events in I_S check_access(thd, EVENT_ACL, thd->lex->select_lex.db, NULL, NULL, 0, 0)) DBUG_RETURN(1); diff --git a/sql/field.cc b/sql/field.cc index a07493a6964..51bb527fc85 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7835,8 +7835,7 @@ uint Field_blob::is_equal(Create_field *new_field) return ((new_field->sql_type == get_blob_type_from_length(max_data_length())) && new_field->charset == field_charset && - ((Field_blob *)new_field->field)->max_data_length() == - max_data_length()); + new_field->pack_length == pack_length()); } diff --git a/sql/field.h b/sql/field.h index e1f7b8c6a29..c30bbfae879 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1888,7 +1888,12 @@ public: uint32 max_display_length() { return field_length; } uint size_of() const { return sizeof(*this); } Item_result result_type () const { return INT_RESULT; } - int reset(void) { bzero(ptr, bytes_in_rec); return 0; } + int reset(void) { + bzero(ptr, bytes_in_rec); + if (bit_ptr && (bit_len > 0)) // reset odd bits among null bits + clr_rec_bits(bit_ptr, bit_ofs, bit_len); + return 0; + } int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr); int store(longlong nr, bool unsigned_val); diff --git a/sql/filesort.cc b/sql/filesort.cc index c6156b8243f..79887577f8f 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -145,6 +145,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, error= 1; bzero((char*) ¶m,sizeof(param)); param.sort_length= sortlength(thd, sortorder, s_length, &multi_byte_charset); + /* filesort cannot handle zero-length records. */ + DBUG_ASSERT(param.sort_length); param.ref_length= table->file->ref_length; param.addon_field= 0; param.addon_length= 0; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 4f3d58dc75e..2b8806b824c 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1272,17 +1272,28 @@ int ha_partition::prepare_new_partition(TABLE *tbl, partition_element *p_elem) { int error; - bool create_flag= FALSE; DBUG_ENTER("prepare_new_partition"); if ((error= set_up_table_before_create(tbl, part_name, create_info, 0, p_elem))) - goto error; + goto error_create; if ((error= file->ha_create(part_name, tbl, create_info))) - goto error; - create_flag= TRUE; + { + /* + Added for safety, InnoDB reports HA_ERR_FOUND_DUPP_KEY + if the table/partition already exists. + If we return that error code, then print_error would try to + get_dup_key on a non-existing partition. + So return a more reasonable error code. + */ + if (error == HA_ERR_FOUND_DUPP_KEY) + error= HA_ERR_TABLE_EXIST; + goto error_create; + } + DBUG_PRINT("info", ("partition %s created", part_name)); if ((error= file->ha_open(tbl, part_name, m_mode, m_open_test_lock))) - goto error; + goto error_open; + DBUG_PRINT("info", ("partition %s opened", part_name)); /* Note: if you plan to add another call that may return failure, better to do it before external_lock() as cleanup_new_partition() @@ -1290,12 +1301,15 @@ int ha_partition::prepare_new_partition(TABLE *tbl, Otherwise see description for cleanup_new_partition(). */ if ((error= file->ha_external_lock(ha_thd(), m_lock_type))) - goto error; + goto error_external_lock; + DBUG_PRINT("info", ("partition %s external locked", part_name)); DBUG_RETURN(0); -error: - if (create_flag) - (void) file->ha_delete_table(part_name); +error_external_lock: + (void) file->close(); +error_open: + (void) file->ha_delete_table(part_name); +error_create: DBUG_RETURN(error); } @@ -1329,19 +1343,23 @@ error: void ha_partition::cleanup_new_partition(uint part_count) { - handler **save_m_file= m_file; DBUG_ENTER("ha_partition::cleanup_new_partition"); - if (m_added_file && m_added_file[0]) + if (m_added_file) { - m_file= m_added_file; - m_added_file= NULL; + THD *thd= ha_thd(); + handler **file= m_added_file; + while ((part_count > 0) && (*file)) + { + (*file)->ha_external_lock(thd, F_UNLCK); + (*file)->close(); - external_lock(ha_thd(), F_UNLCK); - /* delete_table also needed, a bit more complex */ - close(); + /* Leave the (*file)->ha_delete_table(part_name) to the ddl-log */ - m_file= save_m_file; + file++; + part_count--; + } + m_added_file= NULL; } DBUG_VOID_RETURN; } @@ -1647,7 +1665,15 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, part_elem->part_state= PART_TO_BE_DROPPED; } m_new_file= new_file_array; - DBUG_RETURN(copy_partitions(copied, deleted)); + if ((error= copy_partitions(copied, deleted))) + { + /* + Close and unlock the new temporary partitions. + They will later be deleted through the ddl-log. + */ + cleanup_new_partition(part_count); + } + DBUG_RETURN(error); } @@ -1736,6 +1762,7 @@ int ha_partition::copy_partitions(ulonglong * const copied, } DBUG_RETURN(FALSE); error: + m_reorged_file[reorg_part]->ha_rnd_end(); DBUG_RETURN(result); } @@ -5898,6 +5925,23 @@ const key_map *ha_partition::keys_to_use_for_scanning() DBUG_RETURN(m_file[0]->keys_to_use_for_scanning()); } +#define MAX_PARTS_FOR_OPTIMIZER_CALLS 10 +/* + Prepare start variables for estimating optimizer costs. + + @param[out] num_used_parts Number of partitions after pruning. + @param[out] check_min_num Number of partitions to call. + @param[out] first first used partition. +*/ +void ha_partition::partitions_optimizer_call_preparations(uint *first, + uint *num_used_parts, + uint *check_min_num) +{ + *first= bitmap_get_first_set(&(m_part_info->used_partitions)); + *num_used_parts= bitmap_bits_set(&(m_part_info->used_partitions)); + *check_min_num= min(MAX_PARTS_FOR_OPTIMIZER_CALLS, *num_used_parts); +} + /* Return time for a scan of the table @@ -5911,43 +5955,67 @@ const key_map *ha_partition::keys_to_use_for_scanning() double ha_partition::scan_time() { - double scan_time= 0; - handler **file; + double scan_time= 0.0; + uint first, part_id, num_used_parts, check_min_num, partitions_called= 0; DBUG_ENTER("ha_partition::scan_time"); - for (file= m_file; *file; file++) - if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file))) - scan_time+= (*file)->scan_time(); + partitions_optimizer_call_preparations(&first, &num_used_parts, &check_min_num); + for (part_id= first; partitions_called < num_used_parts ; part_id++) + { + if (!bitmap_is_set(&(m_part_info->used_partitions), part_id)) + continue; + scan_time+= m_file[part_id]->scan_time(); + partitions_called++; + if (partitions_called >= check_min_num && scan_time != 0.0) + { + DBUG_RETURN(scan_time * + (double) num_used_parts / (double) partitions_called); + } + } DBUG_RETURN(scan_time); } /* - Get time to read + Estimate rows for records_in_range or estimate_rows_upper_bound. - SYNOPSIS - read_time() - index Index number used - ranges Number of ranges - rows Number of rows - - RETURN VALUE - time for read + @param is_records_in_range call records_in_range instead of + estimate_rows_upper_bound. + @param inx (only for records_in_range) index to use. + @param min_key (only for records_in_range) start of range. + @param max_key (only for records_in_range) end of range. - DESCRIPTION - This will be optimised later to include whether or not the index can - be used with partitioning. To achieve we need to add another parameter - that specifies how many of the index fields that are bound in the ranges. - Possibly added as a new call to handlers. + @return Number of rows or HA_POS_ERROR. */ - -double ha_partition::read_time(uint index, uint ranges, ha_rows rows) +ha_rows ha_partition::estimate_rows(bool is_records_in_range, uint inx, + key_range *min_key, key_range *max_key) { - DBUG_ENTER("ha_partition::read_time"); + ha_rows rows, estimated_rows= 0; + uint first, part_id, num_used_parts, check_min_num, partitions_called= 0; + DBUG_ENTER("ha_partition::records_in_range"); - DBUG_RETURN(m_file[0]->read_time(index, ranges, rows)); + partitions_optimizer_call_preparations(&first, &num_used_parts, &check_min_num); + for (part_id= first; partitions_called < num_used_parts ; part_id++) + { + if (!bitmap_is_set(&(m_part_info->used_partitions), part_id)) + continue; + if (is_records_in_range) + rows= m_file[part_id]->records_in_range(inx, min_key, max_key); + else + rows= m_file[part_id]->estimate_rows_upper_bound(); + if (rows == HA_POS_ERROR) + DBUG_RETURN(HA_POS_ERROR); + estimated_rows+= rows; + partitions_called++; + if (partitions_called >= check_min_num && estimated_rows) + { + DBUG_RETURN(estimated_rows * num_used_parts / partitions_called); + } + } + DBUG_RETURN(estimated_rows); } + /* Find number of records in a range @@ -5975,22 +6043,9 @@ double ha_partition::read_time(uint index, uint ranges, ha_rows rows) ha_rows ha_partition::records_in_range(uint inx, key_range *min_key, key_range *max_key) { - handler **file; - ha_rows in_range= 0; DBUG_ENTER("ha_partition::records_in_range"); - file= m_file; - do - { - if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file))) - { - ha_rows tmp_in_range= (*file)->records_in_range(inx, min_key, max_key); - if (tmp_in_range == HA_POS_ERROR) - DBUG_RETURN(tmp_in_range); - in_range+= tmp_in_range; - } - } while (*(++file)); - DBUG_RETURN(in_range); + DBUG_RETURN(estimate_rows(TRUE, inx, min_key, max_key)); } @@ -6006,22 +6061,36 @@ ha_rows ha_partition::records_in_range(uint inx, key_range *min_key, ha_rows ha_partition::estimate_rows_upper_bound() { - ha_rows rows, tot_rows= 0; - handler **file; DBUG_ENTER("ha_partition::estimate_rows_upper_bound"); - file= m_file; - do - { - if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file))) - { - rows= (*file)->estimate_rows_upper_bound(); - if (rows == HA_POS_ERROR) - DBUG_RETURN(HA_POS_ERROR); - tot_rows+= rows; - } - } while (*(++file)); - DBUG_RETURN(tot_rows); + DBUG_RETURN(estimate_rows(FALSE, 0, NULL, NULL)); +} + + +/* + Get time to read + + SYNOPSIS + read_time() + index Index number used + ranges Number of ranges + rows Number of rows + + RETURN VALUE + time for read + + DESCRIPTION + This will be optimised later to include whether or not the index can + be used with partitioning. To achieve we need to add another parameter + that specifies how many of the index fields that are bound in the ranges. + Possibly added as a new call to handlers. +*/ + +double ha_partition::read_time(uint index, uint ranges, ha_rows rows) +{ + DBUG_ENTER("ha_partition::read_time"); + + DBUG_RETURN(m_file[0]->read_time(index, ranges, rows)); } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index e2e6c674c5e..e6b7472786c 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -552,6 +552,18 @@ public: ------------------------------------------------------------------------- */ +private: + /* + Helper function to get the minimum number of partitions to use for + the optimizer hints/cost calls. + */ + void partitions_optimizer_call_preparations(uint *num_used_parts, + uint *check_min_num, + uint *first); + ha_rows estimate_rows(bool is_records_in_range, uint inx, + key_range *min_key, key_range *max_key); +public: + /* keys_to_use_for_scanning can probably be implemented as the intersection of all underlying handlers if mixed handlers are used. diff --git a/sql/item.cc b/sql/item.cc index 955340cc8ba..e785f0addde 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5312,7 +5312,7 @@ int Item::save_in_field(Field *field, bool no_conversions) field->set_notnull(); error=field->store(nr, unsigned_flag); } - return error; + return error ? error : (field->table->in_use->is_error() ? 2 : 0); } diff --git a/sql/item.h b/sql/item.h index 4dc65c52843..b7e6cc6c204 100644 --- a/sql/item.h +++ b/sql/item.h @@ -514,6 +514,13 @@ public: char * name; /* Name from select */ /* Original item name (if it was renamed)*/ char * orig_name; + /** + Intrusive list pointer for free list. If not null, points to the next + Item on some Query_arena's free list. For instance, stored procedures + have their own Query_arena's. + + @see Query_arena::free_list + */ Item *next; uint32 max_length; uint name_length; /* Length of name */ @@ -987,6 +994,23 @@ public: return FALSE; } + /** + Find a function of a given type + + @param arg the function type to search (enum Item_func::Functype) + @return + @retval TRUE the function type we're searching for is found + @retval FALSE the function type wasn't found + + @description + This function can be used (together with Item::walk()) to find functions + in an item tree fragment. + */ + virtual bool find_function_processor (uchar *arg) + { + return FALSE; + } + /* For SP local variable returns pointer to Item representing its current value and pointer to current Item otherwise. diff --git a/sql/item_create.cc b/sql/item_create.cc index 7d36481a23b..a393c886483 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -4218,6 +4218,16 @@ Create_func_rand::create_native(THD *thd, LEX_STRING name, if (item_list != NULL) arg_count= item_list->elements; + /* + When RAND() is binlogged, the seed is binlogged too. So the + sequence of random numbers is the same on a replication slave as + on the master. However, if several RAND() values are inserted + into a table, the order in which the rows are modified may differ + between master and slave, because the order is undefined. Hence, + the statement is unsafe to log in statement format. + */ + thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); + switch (arg_count) { case 0: { diff --git a/sql/item_func.cc b/sql/item_func.cc index a7b2609470f..75f8b2045b5 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -607,7 +607,7 @@ void Item_func::signal_divide_by_null() Item *Item_func::get_tmp_table_item(THD *thd) { - if (!with_sum_func && !const_item() && functype() != SUSERVAR_FUNC) + if (!with_sum_func && !const_item()) return new Item_field(result_field); return copy_or_same(thd); } diff --git a/sql/item_func.h b/sql/item_func.h index e3690232904..6bfdae8d56d 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -215,6 +215,11 @@ public: { return has_timestamp_args(); } + + virtual bool find_function_processor (uchar *arg) + { + return functype() == *(Functype *) arg; + } }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index d9ca1d17d82..c33e0f4c6fb 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -42,6 +42,20 @@ C_MODE_END String my_empty_string("",default_charset_info); +/* + Convert an array of bytes to a hexadecimal representation. + + Used to generate a hexadecimal representation of a message digest. +*/ +static void array_to_hex(char *to, const char *str, uint len) +{ + const char *str_end= str + len; + for (; str != str_end; ++str) + { + *to++= _dig_vec_lower[((uchar) *str) >> 4]; + *to++= _dig_vec_lower[((uchar) *str) & 0x0F]; + } +} bool Item_str_func::fix_fields(THD *thd, Item **ref) @@ -114,12 +128,7 @@ String *Item_func_md5::val_str(String *str) null_value=1; return 0; } - sprintf((char *) str->ptr(), - "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - digest[0], digest[1], digest[2], digest[3], - digest[4], digest[5], digest[6], digest[7], - digest[8], digest[9], digest[10], digest[11], - digest[12], digest[13], digest[14], digest[15]); + array_to_hex((char *) str->ptr(), (const char*) digest, 16); str->length((uint) 32); return str; } @@ -160,15 +169,7 @@ String *Item_func_sha::val_str(String *str) if (!( str->alloc(SHA1_HASH_SIZE*2) || (mysql_sha1_result(&context,digest)))) { - sprintf((char *) str->ptr(), - "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\ -%02x%02x%02x%02x%02x%02x%02x%02x", - digest[0], digest[1], digest[2], digest[3], - digest[4], digest[5], digest[6], digest[7], - digest[8], digest[9], digest[10], digest[11], - digest[12], digest[13], digest[14], digest[15], - digest[16], digest[17], digest[18], digest[19]); - + array_to_hex((char *) str->ptr(), (const char*) digest, SHA1_HASH_SIZE); str->length((uint) SHA1_HASH_SIZE*2); null_value=0; return str; @@ -677,8 +678,8 @@ String *Item_func_concat_ws::val_str(String *str) res->length() + sep_str->length() + res2->length()) { /* We have room in str; We can't get any errors here */ - if (str == res2) - { // This is quote uncommon! + if (str->ptr() == res2->ptr()) + { // This is quite uncommon! str->replace(0,0,*sep_str); str->replace(0,0,*res); } @@ -1764,19 +1765,19 @@ String *Item_func_encode::val_str(String *str) null_value= 0; res= copy_if_not_alloced(str, res, res->length()); - transform(res); + crypto_transform(res); sql_crypt.reinit(); return res; } -void Item_func_encode::transform(String *res) +void Item_func_encode::crypto_transform(String *res) { sql_crypt.encode((char*) res->ptr(),res->length()); res->set_charset(&my_charset_bin); } -void Item_func_decode::transform(String *res) +void Item_func_decode::crypto_transform(String *res) { sql_crypt.decode((char*) res->ptr(),res->length()); } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index ced164554e4..09a7da021c0 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -366,7 +366,7 @@ public: void fix_length_and_dec(); const char *func_name() const { return "encode"; } protected: - virtual void transform(String *); + virtual void crypto_transform(String *); private: /** Provide a seed for the PRNG sequence. */ bool seed(); @@ -379,7 +379,7 @@ public: Item_func_decode(Item *a, Item *seed): Item_func_encode(a, seed) {} const char *func_name() const { return "decode"; } protected: - void transform(String *); + void crypto_transform(String *); }; diff --git a/sql/log.cc b/sql/log.cc index fb8d8fbf8c1..5a583e9e134 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1753,7 +1753,7 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) */ if (cache_mngr->stmt_cache.has_incident()) { - mysql_bin_log.write_incident(thd, TRUE); + error= mysql_bin_log.write_incident(thd, TRUE); cache_mngr->reset_cache(&cache_mngr->stmt_cache); } else if (!cache_mngr->stmt_cache.empty()) @@ -2650,7 +2650,7 @@ const char *MYSQL_LOG::generate_name(const char *log_name, { char *p= fn_ext(log_name); uint length= (uint) (p - log_name); - strmake(buff, log_name, min(length, FN_REFLEN)); + strmake(buff, log_name, min(length, FN_REFLEN-1)); return (const char*)buff; } return log_name; @@ -3913,7 +3913,7 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time) if (stat_area.st_mtime < purge_time) strmake(to_log, log_info.log_file_name, - sizeof(log_info.log_file_name)); + sizeof(log_info.log_file_name) - 1); else break; } @@ -5375,11 +5375,11 @@ bool flush_error_log() if (opt_error_log) { char err_renamed[FN_REFLEN], *end; - end= strmake(err_renamed,log_error_file,FN_REFLEN-4); + end= strmake(err_renamed,log_error_file,FN_REFLEN-5); strmov(end, "-old"); mysql_mutex_lock(&LOCK_error_log); #ifdef __WIN__ - char err_temp[FN_REFLEN+4]; + char err_temp[FN_REFLEN+5]; /* On Windows is necessary a temporary file for to rename the current error file. diff --git a/sql/log_event.cc b/sql/log_event.cc index 3deeb9a0efe..be167451cb3 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2297,10 +2297,22 @@ bool Query_log_event::write(IO_CACHE* file) int8store(start, table_map_for_update); start+= 8; } + if (master_data_written != 0) + { + /* + Q_MASTER_DATA_WRITTEN_CODE only exists in relay logs where the master + has binlog_version<4 and the slave has binlog_version=4. See comment + for master_data_written in log_event.h for details. + */ + *start++= Q_MASTER_DATA_WRITTEN_CODE; + int4store(start, master_data_written); + start+= 4; + } + /* NOTE: When adding new status vars, please don't forget to update - the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update function - code_name in this file. + the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update the function + code_name() in this file. Here there could be code like if (command-line-option-which-says-"log_this_variable" && inited) @@ -2376,7 +2388,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, auto_increment_offset(thd_arg->variables.auto_increment_offset), lc_time_names_number(thd_arg->variables.lc_time_names->number), charset_database_number(0), - table_map_for_update((ulonglong)thd_arg->table_map_for_update) + table_map_for_update((ulonglong)thd_arg->table_map_for_update), + master_data_written(0) { time_t end_time; @@ -2605,6 +2618,7 @@ code_name(int code) case Q_LC_TIME_NAMES_CODE: return "Q_LC_TIME_NAMES_CODE"; case Q_CHARSET_DATABASE_CODE: return "Q_CHARSET_DATABASE_CODE"; case Q_TABLE_MAP_FOR_UPDATE_CODE: return "Q_TABLE_MAP_FOR_UPDATE_CODE"; + case Q_MASTER_DATA_WRITTEN_CODE: return "Q_MASTER_DATA_WRITTEN_CODE"; } sprintf(buf, "CODE#%d", code); return buf; @@ -2642,7 +2656,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, flags2_inited(0), sql_mode_inited(0), charset_inited(0), auto_increment_increment(1), auto_increment_offset(1), time_zone_len(0), lc_time_names_number(0), charset_database_number(0), - table_map_for_update(0) + table_map_for_update(0), master_data_written(0) { ulong data_len; uint32 tmp; @@ -2698,6 +2712,18 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, DBUG_PRINT("info", ("Query_log_event has status_vars_len: %u", (uint) status_vars_len)); tmp-= 2; + } + else + { + /* + server version < 5.0 / binlog_version < 4 master's event is + relay-logged with storing the original size of the event in + Q_MASTER_DATA_WRITTEN_CODE status variable. + The size is to be restored at reading Q_MASTER_DATA_WRITTEN_CODE-marked + event from the relay log. + */ + DBUG_ASSERT(description_event->binlog_version < 4); + master_data_written= data_written; } /* We have parsed everything we know in the post header for QUERY_EVENT, @@ -2789,6 +2815,11 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, table_map_for_update= uint8korr(pos); pos+= 8; break; + case Q_MASTER_DATA_WRITTEN_CODE: + CHECK_SPACE(pos, end, 4); + data_written= master_data_written= uint4korr(pos); + pos+= 4; + break; default: /* That's why you must write status vars in growing order of code */ DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\ @@ -3275,7 +3306,18 @@ START SLAVE; . Query: '%s'", expected_error, thd->query()); compare_errors: - /* + /* + In the slave thread, we may sometimes execute some DROP / * 40005 + TEMPORARY * / TABLE that come from parts of binlogs (likely if we + use RESET SLAVE or CHANGE MASTER TO), while the temporary table + has already been dropped. To ignore such irrelevant "table does + not exist errors", we silently clear the error if TEMPORARY was used. + */ + if (thd->lex->sql_command == SQLCOM_DROP_TABLE && thd->lex->drop_temporary && + thd->is_error() && thd->stmt_da->sql_errno() == ER_BAD_TABLE_ERROR && + !expected_error) + thd->stmt_da->reset_diagnostics_area(); + /* If we expected a non-zero error code, and we don't get the same error code, and it should be ignored or is related to a concurrency issue. */ @@ -8047,10 +8089,10 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, plus one or three bytes (see pack.c:net_store_length) for number of elements in the field metadata array. */ - if (m_field_metadata_size > 255) - m_data_size+= m_field_metadata_size + 3; - else + if (m_field_metadata_size < 251) m_data_size+= m_field_metadata_size + 1; + else + m_data_size+= m_field_metadata_size + 3; bzero(m_null_bits, num_null_bytes); for (unsigned int i= 0 ; i < m_table->s->fields ; ++i) diff --git a/sql/log_event.h b/sql/log_event.h index 9f14b30d2e2..5530444b0d4 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -264,7 +264,8 @@ struct sql_ex_info 1 + 1 + 255 /* type, length, time_zone */ + \ 1 + 2 /* type, lc_time_names_number */ + \ 1 + 2 /* type, charset_database_number */ + \ - 1 + 8 /* type, table_map_for_update */) + 1 + 8 /* type, table_map_for_update */ + \ + 1 + 4 /* type, master_data_written */) #define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \ LOG_EVENT_HEADER_LEN + /* write_header */ \ QUERY_HEADER_LEN + /* write_data */ \ @@ -331,6 +332,10 @@ struct sql_ex_info #define Q_TABLE_MAP_FOR_UPDATE_CODE 9 +#define Q_MASTER_DATA_WRITTEN_CODE 10 + +/* Intvar event post-header */ + /* Intvar event data */ #define I_TYPE_OFFSET 0 #define I_VAL_OFFSET 1 @@ -1681,6 +1686,16 @@ public: statement, for other query statements, this will be zero. */ ulonglong table_map_for_update; + /* + Holds the original length of a Query_log_event that comes from a + master of version < 5.0 (i.e., binlog_version < 4). When the IO + thread writes the relay log, it augments the Query_log_event with a + Q_MASTER_DATA_WRITTEN_CODE status_var that holds the original event + length. This field is initialized to non-zero in the SQL thread when + it reads this augmented event. SQL thread does not write + Q_MASTER_DATA_WRITTEN_CODE to the slave's server binlog. + */ + uint32 master_data_written; #ifndef MYSQL_CLIENT diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 6e35291b1c7..8daf8f5ecb3 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1440,8 +1440,18 @@ bool get_schema_tables_result(JOIN *join, enum enum_schema_table_state executed_place); enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table); -#define is_infoschema_db(X) \ - !my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str, (X)) +inline bool is_infoschema_db(const char *name, size_t len) +{ + return (INFORMATION_SCHEMA_NAME.length == len && + !my_strcasecmp(system_charset_info, + INFORMATION_SCHEMA_NAME.str, name)); +} + +inline bool is_infoschema_db(const char *name) +{ + return !my_strcasecmp(system_charset_info, + INFORMATION_SCHEMA_NAME.str, name); +} void initialize_information_schema_acl(); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 05442643e23..733c54fc2de 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2138,10 +2138,10 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache) /* It's safe to broadcast outside a lock (COND... is not deleted here) */ DBUG_PRINT("signal", ("Broadcasting COND_thread_count")); + DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); mysql_cond_broadcast(&COND_thread_count); - DBUG_LEAVE; // Must match DBUG_ENTER() pthread_exit(0); return 0; // Avoid compiler warnings } diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 7bf7b81aa3a..9e1413d726d 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -264,6 +264,22 @@ unpack_row(Relay_log_info const *rli, { DBUG_PRINT("debug", ("Was NULL; null mask: 0x%x; null bits: 0x%x", null_mask, null_bits)); + /** + Calling reset just in case one is unpacking on top a + record with data. + + This could probably go into set_null() but doing so, + (i) triggers assertion in other parts of the code at + the moment; (ii) it would make us reset the field, + always when setting null, which right now doesn't seem + needed anywhere else except here. + + TODO: maybe in the future we should consider moving + the reset to make it part of set_null. But then + the assertions triggered need to be + addressed/revisited. + */ + f->reset(); f->set_null(); } else diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index f7094e8734d..6591f9d5cb7 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -5132,11 +5132,11 @@ ER_SP_BADSTATEMENT 0A000 eng "%s is not allowed in stored procedures" ger "%s ist in gespeicherten Prozeduren nicht erlaubt" ER_UPDATE_LOG_DEPRECATED_IGNORED 42000 - eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been ignored" - ger "Das Update-Log ist veraltet und wurde durch das Binär-Log ersetzt. SET SQL_LOG_UPDATE wird ignoriert" + eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been ignored. This option will be removed in MySQL 5.6." + ger "Das Update-Log ist veraltet und wurde durch das Binär-Log ersetzt. SET SQL_LOG_UPDATE wird ignoriert. Diese Option wird in MySQL 5.6 entfernt." ER_UPDATE_LOG_DEPRECATED_TRANSLATED 42000 - eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN" - ger "Das Update-Log ist veraltet und wurde durch das Binär-Log ersetzt. SET SQL_LOG_UPDATE wurde in SET SQL_LOG_BIN übersetzt" + eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN. This option will be removed in MySQL 5.6." + ger "Das Update-Log ist veraltet und wurde durch das Binär-Log ersetzt. SET SQL_LOG_UPDATE wurde in SET SQL_LOG_BIN übersetzt. Diese Option wird in MySQL 5.6 entfernt." ER_QUERY_INTERRUPTED 70100 eng "Query execution was interrupted" ger "Ausführung der Abfrage wurde unterbrochen" diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 60be5723559..81800dd990a 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6274,7 +6274,8 @@ ER_UNKNOWN_LOCALE ER_SLAVE_IGNORE_SERVER_IDS eng "The requested server id %d clashes with the slave startup option --replicate-same-server-id" - +ER_QUERY_CACHE_DISABLED + eng "Query cache is disabled; restart the server with query_cache_type=1 to enable it" ER_SAME_NAME_PARTITION_FIELD eng "Duplicate partition field name '%-.192s'" ER_PARTITION_COLUMN_LIST_ERROR diff --git a/sql/sp.cc b/sql/sp.cc index 9d3527dc4e6..cbc0d003c9f 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -908,6 +908,8 @@ sp_create_routine(THD *thd, int type, sp_head *sp) bool store_failed= FALSE; + bool save_binlog_row_based; + DBUG_ENTER("sp_create_routine"); DBUG_PRINT("enter", ("type: %d name: %.*s",type, (int) sp->m_name.length, sp->m_name.str)); @@ -925,6 +927,7 @@ sp_create_routine(THD *thd, int type, sp_head *sp) row-based replication. The flag will be reset at the end of the statement. */ + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); thd->clear_current_stmt_binlog_format_row(); saved_count_cuted_fields= thd->count_cuted_fields; @@ -1132,6 +1135,8 @@ done: thd->variables.sql_mode= saved_mode; close_thread_tables(thd); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(ret); } @@ -1156,6 +1161,7 @@ sp_drop_routine(THD *thd, int type, sp_name *name) { TABLE *table; int ret; + bool save_binlog_row_based; DBUG_ENTER("sp_drop_routine"); DBUG_PRINT("enter", ("type: %d name: %.*s", type, (int) name->m_name.length, name->m_name.str)); @@ -1168,6 +1174,7 @@ sp_drop_routine(THD *thd, int type, sp_name *name) row-based replication. The flag will be reset at the end of the statement. */ + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); thd->clear_current_stmt_binlog_format_row(); if (!(table= open_proc_table_for_update(thd))) @@ -1186,6 +1193,8 @@ sp_drop_routine(THD *thd, int type, sp_name *name) } close_thread_tables(thd); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(ret); } @@ -1212,6 +1221,7 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) { TABLE *table; int ret; + bool save_binlog_row_based; DBUG_ENTER("sp_update_routine"); DBUG_PRINT("enter", ("type: %d name: %.*s", type, (int) name->m_name.length, name->m_name.str)); @@ -1223,6 +1233,7 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) row-based replication. The flag will be reset at the end of the statement. */ + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); thd->clear_current_stmt_binlog_format_row(); if (!(table= open_proc_table_for_update(thd))) @@ -1257,6 +1268,8 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) } close_thread_tables(thd); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(ret); } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 9996a237cb4..8d06003e2e4 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2799,8 +2799,15 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, m_lex->mark_as_requiring_prelocking(NULL); } thd->rollback_item_tree_changes(); - /* Update the state of the active arena. */ - thd->stmt_arena->state= Query_arena::EXECUTED; + /* + Update the state of the active arena if no errors on + open_tables stage. + */ + if (!res || !thd->is_error() || + (thd->stmt_da->sql_errno() != ER_CANT_REOPEN_TABLE && + thd->stmt_da->sql_errno() != ER_NO_SUCH_TABLE && + thd->stmt_da->sql_errno() != ER_UPDATE_TABLE_USED)) + thd->stmt_arena->state= Query_arena::EXECUTED; /* Merge here with the saved parent's values diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 9bb50d58dc5..012542a9467 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -292,7 +292,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) { TABLE *table; READ_RECORD read_record_info; - my_bool return_val= 1; + my_bool return_val= TRUE; bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; char tmp_name[NAME_LEN+1]; int password_length; @@ -605,7 +605,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) init_check_host(); initialized=1; - return_val=0; + return_val= FALSE; end: thd->variables.sql_mode= old_sql_mode; @@ -656,7 +656,7 @@ my_bool acl_reload(THD *thd) DYNAMIC_ARRAY old_acl_hosts,old_acl_users,old_acl_dbs; MEM_ROOT old_mem; bool old_initialized; - my_bool return_val= 1; + my_bool return_val= TRUE; DBUG_ENTER("acl_reload"); if (thd->locked_tables) @@ -683,8 +683,13 @@ my_bool acl_reload(THD *thd) if (simple_open_n_lock_tables(thd, tables)) { - sql_print_error("Fatal error: Can't open and lock privilege tables: %s", - thd->stmt_da->message()); + /* + Execution might have been interrupted; only print the error message + if an error condition has been raised. + */ + if (thd->stmt_da->is_error()) + sql_print_error("Fatal error: Can't open and lock privilege tables: %s", + thd->stmt_da->message()); goto end; } @@ -1043,7 +1048,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, *mqh= acl_user->user_resource; if (acl_user->host.hostname) - strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME); + strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME - 1); else *sctx->priv_host= 0; } @@ -1144,7 +1149,7 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, sctx->priv_user= acl_user->user ? user : (char *) ""; if (acl_user->host.hostname) - strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME); + strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME - 1); else *sctx->priv_host= 0; } @@ -3018,6 +3023,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, TABLE_LIST tables[3]; bool create_new_users=0; char *db_name, *table_name; + bool save_binlog_row_based; DBUG_ENTER("mysql_table_grant"); if (!initialized) @@ -3113,6 +3119,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, row-based replication. The flag will be reset at the end of the statement. */ + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); thd->clear_current_stmt_binlog_format_row(); #ifdef HAVE_REPLICATION @@ -3128,7 +3135,11 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, */ tables[0].updating= tables[1].updating= tables[2].updating= 1; if (!(thd->spcont || rpl_filter->tables_ok(0, tables))) + { + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(FALSE); + } } #endif @@ -3141,6 +3152,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, if (simple_open_n_lock_tables(thd,tables)) { // Should never happen close_thread_tables(thd); /* purecov: deadcode */ + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(TRUE); /* purecov: deadcode */ } @@ -3267,6 +3280,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, /* Tables are automatically closed */ thd->lex->restore_backup_query_tables_list(&backup); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(result); } @@ -3295,6 +3310,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, TABLE_LIST tables[2]; bool create_new_users=0, result=0; char *db_name, *table_name; + bool save_binlog_row_based; DBUG_ENTER("mysql_routine_grant"); if (!initialized) @@ -3330,6 +3346,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, row-based replication. The flag will be reset at the end of the statement. */ + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); thd->clear_current_stmt_binlog_format_row(); #ifdef HAVE_REPLICATION @@ -3345,13 +3362,19 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, */ tables[0].updating= tables[1].updating= 1; if (!(thd->spcont || rpl_filter->tables_ok(0, tables))) + { + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(FALSE); + } } #endif if (simple_open_n_lock_tables(thd,tables)) { // Should never happen close_thread_tables(thd); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(TRUE); } @@ -3428,6 +3451,8 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, } mysql_rwlock_unlock(&LOCK_grant); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; /* Tables are automatically closed */ DBUG_RETURN(result); @@ -3442,6 +3467,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, char tmp_db[NAME_LEN+1]; bool create_new_users=0; TABLE_LIST tables[2]; + bool save_binlog_row_based; DBUG_ENTER("mysql_grant"); if (!initialized) { @@ -3470,6 +3496,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, row-based replication. The flag will be reset at the end of the statement. */ + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); thd->clear_current_stmt_binlog_format_row(); #ifdef HAVE_REPLICATION @@ -3485,13 +3512,19 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, */ tables[0].updating= tables[1].updating= 1; if (!(thd->spcont || rpl_filter->tables_ok(0, tables))) + { + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(FALSE); + } } #endif if (simple_open_n_lock_tables(thd,tables)) { // This should never happen close_thread_tables(thd); /* purecov: deadcode */ + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(TRUE); /* purecov: deadcode */ } @@ -3551,6 +3584,8 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, if (!result) my_ok(thd); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(result); } @@ -5754,6 +5789,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) List_iterator <LEX_USER> user_list(list); TABLE_LIST tables[GRANT_TABLES]; bool some_users_created= FALSE; + bool save_binlog_row_based; DBUG_ENTER("mysql_create_user"); /* @@ -5761,11 +5797,16 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) row-based replication. The flag will be reset at the end of the statement. */ + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); thd->clear_current_stmt_binlog_format_row(); /* CREATE USER may be skipped on replication client. */ if ((result= open_grant_tables(thd, tables))) + { + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(result != 1); + } mysql_rwlock_wrlock(&LOCK_grant); mysql_mutex_lock(&acl_cache->lock); @@ -5808,6 +5849,8 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) mysql_rwlock_unlock(&LOCK_grant); close_thread_tables(thd); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(result); } @@ -5834,6 +5877,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) TABLE_LIST tables[GRANT_TABLES]; bool some_users_deleted= FALSE; ulong old_sql_mode= thd->variables.sql_mode; + bool save_binlog_row_based; DBUG_ENTER("mysql_drop_user"); /* @@ -5841,11 +5885,16 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) row-based replication. The flag will be reset at the end of the statement. */ + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); thd->clear_current_stmt_binlog_format_row(); /* DROP USER may be skipped on replication client. */ if ((result= open_grant_tables(thd, tables))) + { + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(result != 1); + } thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; @@ -5882,6 +5931,8 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) mysql_rwlock_unlock(&LOCK_grant); close_thread_tables(thd); thd->variables.sql_mode= old_sql_mode; + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(result); } @@ -5908,6 +5959,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) List_iterator <LEX_USER> user_list(list); TABLE_LIST tables[GRANT_TABLES]; bool some_users_renamed= FALSE; + bool save_binlog_row_based; DBUG_ENTER("mysql_rename_user"); /* @@ -5915,11 +5967,16 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) row-based replication. The flag will be reset at the end of the statement. */ + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); thd->clear_current_stmt_binlog_format_row(); /* RENAME USER may be skipped on replication client. */ if ((result= open_grant_tables(thd, tables))) + { + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(result != 1); + } mysql_rwlock_wrlock(&LOCK_grant); mysql_mutex_lock(&acl_cache->lock); @@ -5966,6 +6023,8 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) mysql_rwlock_unlock(&LOCK_grant); close_thread_tables(thd); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(result); } @@ -5990,6 +6049,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) int result; ACL_DB *acl_db; TABLE_LIST tables[GRANT_TABLES]; + bool save_binlog_row_based; DBUG_ENTER("mysql_revoke_all"); /* @@ -5997,10 +6057,15 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) row-based replication. The flag will be reset at the end of the statement. */ + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); thd->clear_current_stmt_binlog_format_row(); if ((result= open_grant_tables(thd, tables))) + { + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(result != 1); + } mysql_rwlock_wrlock(&LOCK_grant); mysql_mutex_lock(&acl_cache->lock); @@ -6153,6 +6218,8 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) /* error for writing binary log has already been reported */ if (result && !binlog_error) my_message(ER_REVOKE_GRANTS, ER(ER_REVOKE_GRANTS), MYF(0)); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(result || binlog_error); } @@ -6244,6 +6311,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, TABLE_LIST tables[GRANT_TABLES]; HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash; Silence_routine_definer_errors error_handler; + bool save_binlog_row_based; DBUG_ENTER("sp_revoke_privileges"); if ((result= open_grant_tables(thd, tables))) @@ -6260,6 +6328,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, row-based replication. The flag will be reset at the end of the statement. */ + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); thd->clear_current_stmt_binlog_format_row(); /* Remove procedure access */ @@ -6296,6 +6365,8 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, close_thread_tables(thd); thd->pop_internal_handler(); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(error_handler.has_errors()); } diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 9758b2b4e4d..90b255b0843 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -727,7 +727,7 @@ static int check_connection(THD *thd) ulong server_capabilites; { /* buff[] needs to big enough to hold the server_version variable */ - char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64]; + char buff[SERVER_VERSION_LENGTH + 1 + SCRAMBLE_LENGTH + 1 + 64]; server_capabilites= CLIENT_BASIC_FLAGS; if (opt_using_transactions) diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 4cb47c7b2df..1be84751581 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -645,7 +645,7 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, DBUG_ENTER("mysql_create_db"); /* do not create 'information_schema' db */ - if (!my_strcasecmp(system_charset_info, db, INFORMATION_SCHEMA_NAME.str)) + if (is_infoschema_db(db)) { my_error(ER_DB_CREATE_EXISTS, MYF(0), db); DBUG_RETURN(-1); @@ -1600,8 +1600,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) } } - if (my_strcasecmp(system_charset_info, new_db_name->str, - INFORMATION_SCHEMA_NAME.str) == 0) + if (is_infoschema_db(new_db_name->str, new_db_name->length)) { /* Switch the current database to INFORMATION_SCHEMA. */ diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 9c621944f2a..b8ba16f2fb1 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -683,7 +683,11 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, if (n++) pfields.append(", "); if (item->name) + { + pfields.append("`"); pfields.append(item->name); + pfields.append("`"); + } else item->print(&pfields, QT_ORDINARY); } @@ -703,7 +707,9 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, val= lv++; if (n++) pfields.append(", "); + pfields.append("`"); pfields.append(item->name); + pfields.append("`"); pfields.append("="); val->print(&pfields, QT_ORDINARY); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f8111a713e0..73ed2e3f017 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -624,8 +624,10 @@ void free_items(Item *item) DBUG_VOID_RETURN; } -/* This works because items are allocated with sql_alloc() */ - +/** + This works because items are allocated with sql_alloc(). + @note The function also handles null pointers (empty list). +*/ void cleanup_items(Item *item) { DBUG_ENTER("cleanup_items"); @@ -1218,8 +1220,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, table_list.alias= table_list.table_name= conv_name.str; packet= arg_end + 1; - if (!my_strcasecmp(system_charset_info, table_list.db, - INFORMATION_SCHEMA_NAME.str)) + if (is_infoschema_db(table_list.db, table_list.db_length)) { ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias); if (schema_table) @@ -2494,6 +2495,8 @@ case SQLCOM_PREPARE: { lex->link_first_table_back(create_table, link_to_local); create_table->create= TRUE; + /* Base table and temporary table are not in the same name space. */ + create_table->skip_temporary= 1; } if (!(res= open_and_lock_tables(thd, lex->query_tables))) @@ -3257,9 +3260,9 @@ end_with_restore_list: select_lex->where, 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL, (ORDER *)NULL, - select_lex->options | thd->variables.option_bits | + (select_lex->options | thd->variables.option_bits | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | - OPTION_SETUP_TABLES_DONE, + OPTION_SETUP_TABLES_DONE) & ~OPTION_BUFFER_RESULT, del_result, unit, select_lex); res|= thd->is_error(); MYSQL_MULTI_DELETE_DONE(res, del_result->num_deleted()); @@ -3286,17 +3289,6 @@ end_with_restore_list: } else { - /* - If this is a slave thread, we may sometimes execute some - DROP / * 40005 TEMPORARY * / TABLE - that come from parts of binlogs (likely if we use RESET SLAVE or CHANGE - MASTER TO), while the temporary table has already been dropped. - To not generate such irrelevant "table does not exist errors", - we silently add IF EXISTS if TEMPORARY was used. - */ - if (thd->slave_thread) - lex->drop_if_exists= 1; - /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ thd->variables.option_bits|= OPTION_KEEP_LOG; } @@ -6286,8 +6278,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX); ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES); ptr->derived= table->sel; - if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db, - INFORMATION_SCHEMA_NAME.str)) + if (!ptr->derived && is_infoschema_db(ptr->db, ptr->db_length)) { ST_SCHEMA_TABLE *schema_table; if (ptr->updating && @@ -6826,13 +6817,13 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, thd->thread_stack= (char*) &tmp_thd; thd->store_globals(); } - + if (thd) { bool reload_acl_failed= acl_reload(thd); bool reload_grants_failed= grant_reload(thd); bool reload_servers_failed= servers_reload(thd); - + if (reload_acl_failed || reload_grants_failed || reload_servers_failed) { result= 1; @@ -7005,7 +6996,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, if (options & REFRESH_USER_RESOURCES) reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */ *write_to_binlog= tmp_write_to_binlog; - return result; + /* + If the query was killed then this function must fail. + */ + return result || (thd ? thd->killed : 0); } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 91cf0333fb5..90d5c553cdf 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -3360,16 +3360,13 @@ int get_partition_id_range(partition_info *part_info, part_func_value-= 0x8000000000000000ULL; while (max_part_id > min_part_id) { - loc_part_id= (max_part_id + min_part_id + 1) >> 1; + loc_part_id= (max_part_id + min_part_id) / 2; if (range_array[loc_part_id] <= part_func_value) min_part_id= loc_part_id + 1; else - max_part_id= loc_part_id - 1; + max_part_id= loc_part_id; } loc_part_id= max_part_id; - if (part_func_value >= range_array[loc_part_id]) - if (loc_part_id != max_partition) - loc_part_id++; *part_id= (uint32)loc_part_id; if (loc_part_id == max_partition && part_func_value >= range_array[loc_part_id] && @@ -3443,6 +3440,7 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info, bool include_endpoint) { longlong *range_array= part_info->range_int_array; + longlong part_end_val; uint max_partition= part_info->num_parts - 1; uint min_part_id= 0, max_part_id= max_partition, loc_part_id; /* Get the partitioning function value for the endpoint */ @@ -3476,46 +3474,45 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info, } } - if (unsigned_flag) part_func_value-= 0x8000000000000000ULL; if (left_endpoint && !include_endpoint) part_func_value++; + + /* + Search for the partition containing part_func_value + (including the right endpoint). + */ while (max_part_id > min_part_id) { - loc_part_id= (max_part_id + min_part_id + 1) >> 1; - if (range_array[loc_part_id] <= part_func_value) + loc_part_id= (max_part_id + min_part_id) / 2; + if (range_array[loc_part_id] < part_func_value) min_part_id= loc_part_id + 1; else - max_part_id= loc_part_id - 1; + max_part_id= loc_part_id; } loc_part_id= max_part_id; - if (loc_part_id < max_partition && - part_func_value >= range_array[loc_part_id+1]) - { - loc_part_id++; - } + + /* Adjust for endpoints */ + part_end_val= range_array[loc_part_id]; if (left_endpoint) { - longlong bound= range_array[loc_part_id]; /* In case of PARTITION p VALUES LESS THAN MAXVALUE the maximum value is in the current partition. */ - if (part_func_value > bound || - (part_func_value == bound && - (!part_info->defined_max_value || loc_part_id < max_partition))) + if (part_func_value == part_end_val && + (loc_part_id < max_partition || !part_info->defined_max_value)) loc_part_id++; } else { - if (loc_part_id < max_partition) - { - if (part_func_value == range_array[loc_part_id]) - loc_part_id += test(include_endpoint); - else if (part_func_value > range_array[loc_part_id]) - loc_part_id++; - } + /* if 'WHERE <= X' and partition is LESS THAN (X) include next partition */ + if (include_endpoint && loc_part_id < max_partition && + part_func_value == part_end_val) + loc_part_id++; + + /* Right endpoint, set end after correct partition */ loc_part_id++; } DBUG_RETURN(loc_part_id); @@ -6062,8 +6059,7 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) part_info->first_log_entry= NULL; build_table_filename(path, sizeof(path) - 1, lpt->db, lpt->table_name, "", 0); - build_table_filename(tmp_path, sizeof(tmp_path) - 1, lpt->db, - lpt->table_name, "#", 0); + build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt); mysql_mutex_lock(&LOCK_gdl); if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) @@ -6119,8 +6115,7 @@ static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) build_table_filename(path, sizeof(path) - 1, lpt->db, lpt->table_name, "", 0); - build_table_filename(tmp_path, sizeof(tmp_path) - 1, lpt->db, - lpt->table_name, "#", 0); + build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt); mysql_mutex_lock(&LOCK_gdl); if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) @@ -6345,7 +6340,7 @@ void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, partition_info *part_info= lpt->part_info; DBUG_ENTER("handle_alter_part_error"); - if (!part_info->first_log_entry && + if (part_info->first_log_entry && execute_ddl_log_entry(current_thd, part_info->first_log_entry->entry_pos)) { diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 63b7649bad5..12de2bbcecc 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1675,6 +1675,8 @@ static bool mysql_test_create_table(Prepared_statement *stmt) { lex->link_first_table_back(create_table, link_to_local); create_table->create= TRUE; + /* Base table and temporary table are not in the same name space. */ + create_table->skip_temporary= true; } if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, 0)) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index fe3f17f57a0..510f9d8dc01 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -917,11 +917,14 @@ impossible position"; thd_proc_info(thd, "Finished reading one binlog; switching to next binlog"); switch (mysql_bin_log.find_next_log(&linfo, 1)) { - case LOG_INFO_EOF: - loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK); - break; case 0: break; + case LOG_INFO_EOF: + if (mysql_bin_log.is_active(log_file_name)) + { + loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK); + break; + } default: errmsg = "could not find next log"; my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 030c12de897..18954e0cf23 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -522,7 +522,7 @@ JOIN::prepare(Item ***rref_pointer_array, thd->lex->allow_sum_func= save_allow_sum_func; } - if (!thd->lex->view_prepare_mode) + if (!thd->lex->view_prepare_mode && !(select_options & SELECT_DESCRIBE)) { Item_subselect *subselect; /* Is it subselect? */ @@ -542,13 +542,26 @@ JOIN::prepare(Item ***rref_pointer_array, if (order) { + bool real_order= FALSE; ORDER *ord; for (ord= order; ord; ord= ord->next) { Item *item= *ord->item; + /* + Disregard sort order if there's only "{VAR}CHAR(0) NOT NULL" fields + there. Such fields don't contain any data to sort. + */ + if (!real_order && + (item->type() != Item::FIELD_ITEM || + ((Item_field *) item)->field->maybe_null() || + ((Item_field *) item)->field->sort_length())) + real_order= TRUE; + if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) item->split_sum_func(thd, ref_pointer_array, all_fields); } + if (!real_order) + order= NULL; } if (having && having->with_sum_func) @@ -945,6 +958,7 @@ JOIN::optimize() DBUG_PRINT("info",("Select tables optimized away")); zero_result_cause= "Select tables optimized away"; tables_list= 0; // All tables resolved + const_tables= tables; /* Extract all table-independent conditions and replace the WHERE clause with them. All other conditions were computed by opt_sum_query @@ -3659,20 +3673,20 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array, cond_func=(Item_func_match *)cond; else if (func->arg_count == 2) { - Item_func *arg0=(Item_func *)(func->arguments()[0]), - *arg1=(Item_func *)(func->arguments()[1]); - if (arg1->const_item() && - arg0->type() == Item::FUNC_ITEM && - arg0->functype() == Item_func::FT_FUNC && + Item *arg0=(Item *)(func->arguments()[0]), + *arg1=(Item *)(func->arguments()[1]); + if (arg1->const_item() && arg1->cols() == 1 && + arg0->type() == Item::FUNC_ITEM && + ((Item_func *) arg0)->functype() == Item_func::FT_FUNC && ((functype == Item_func::GE_FUNC && arg1->val_real() > 0) || (functype == Item_func::GT_FUNC && arg1->val_real() >=0))) - cond_func=(Item_func_match *) arg0; + cond_func= (Item_func_match *) arg0; else if (arg0->const_item() && - arg1->type() == Item::FUNC_ITEM && - arg1->functype() == Item_func::FT_FUNC && + arg1->type() == Item::FUNC_ITEM && + ((Item_func *) arg1)->functype() == Item_func::FT_FUNC && ((functype == Item_func::LE_FUNC && arg0->val_real() > 0) || (functype == Item_func::LT_FUNC && arg0->val_real() >=0))) - cond_func=(Item_func_match *) arg1; + cond_func= (Item_func_match *) arg1; } } else if (cond->type() == Item::COND_ITEM) @@ -7170,6 +7184,7 @@ static void update_depend_map(JOIN *join, ORDER *order) table_map depend_map; order->item[0]->update_used_tables(); order->depend_map=depend_map=order->item[0]->used_tables(); + order->used= 0; // Not item_sum(), RAND() and no reference to table outside of sub select if (!(order->depend_map & (OUTER_REF_TABLE_BIT | RAND_TABLE_BIT)) && !order->item[0]->with_sum_func) diff --git a/sql/sql_select.h b/sql/sql_select.h index 3a664546397..c30aae4fbf9 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -719,6 +719,12 @@ public: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); int res= item->save_in_field(to_field, 1); + /* + Item::save_in_field() may call Item::val_xxx(). And if this is a subquery + we need to check for errors executing it and react accordingly + */ + if (!res && table->in_use->is_error()) + res= 2; dbug_tmp_restore_column_map(table->write_set, old_map); null_key= to_field->is_null() || item->null_value; return (err != 0 || res > 2 ? STORE_KEY_FATAL : (store_key_result) res); @@ -752,6 +758,12 @@ protected: if (!err) err= res; } + /* + Item::save_in_field() may call Item::val_xxx(). And if this is a subquery + we need to check for errors executing it and react accordingly + */ + if (!err && to_field->table->in_use->is_error()) + err= 2; } null_key= to_field->is_null() || item->null_value; return (err > 2 ? STORE_KEY_FATAL : (store_key_result) err); diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 141e00cf50f..a7109af9f64 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -264,8 +264,14 @@ bool servers_reload(THD *thd) if (simple_open_n_lock_tables(thd, tables)) { - sql_print_error("Can't open and lock privilege tables: %s", - thd->stmt_da->message()); + /* + Execution might have been interrupted; only print the error message + if an error condition has been raised. + */ + if (thd->stmt_da->is_error()) + sql_print_error("Can't open and lock privilege tables: %s", + thd->stmt_da->message()); + return_val= FALSE; goto end; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index f8df7eb518f..bb7fa61f39b 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -750,8 +750,7 @@ bool mysqld_show_create_db(THD *thd, char *dbname, DBUG_RETURN(TRUE); } #endif - if (!my_strcasecmp(system_charset_info, dbname, - INFORMATION_SCHEMA_NAME.str)) + if (is_infoschema_db(dbname)) { dbname= INFORMATION_SCHEMA_NAME.str; create.default_table_charset= system_charset_info; @@ -2686,8 +2685,8 @@ int make_db_list(THD *thd, List<LEX_STRING> *files, */ if (lookup_field_vals->db_value.str) { - if (!my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str, - lookup_field_vals->db_value.str)) + if (is_infoschema_db(lookup_field_vals->db_value.str, + lookup_field_vals->db_value.length)) { *with_i_schema= 1; if (files->push_back(i_s_name_copy)) @@ -3318,11 +3317,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) while ((db_name= it++)) { #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (!check_access(thd, SELECT_ACL, db_name->str, - &thd->col_access, NULL, 0, 1) || + if (!(check_access(thd, SELECT_ACL, db_name->str, + &thd->col_access, NULL, 0, 1) || + (!thd->col_access && check_grant_db(thd, db_name->str))) || 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, 0)) #endif { thd->no_warnings_for_error= 1; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 1e06b070494..e623d1d5c45 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -648,7 +648,7 @@ static bool read_ddl_log_file_entry(uint entry_no) Write one entry from ddl log file SYNOPSIS write_ddl_log_file_entry() - entry_no Entry number to read + entry_no Entry number to write RETURN VALUES TRUE Error FALSE Success @@ -750,10 +750,10 @@ static uint read_ddl_log_header() else successful_open= TRUE; } - entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]); - global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]); if (successful_open) { + entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]); + global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]); global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]); DBUG_ASSERT(global_ddl_log.io_size <= sizeof(global_ddl_log.file_entry_buf)); @@ -834,6 +834,7 @@ static bool init_ddl_log() goto end; global_ddl_log.io_size= IO_SIZE; + global_ddl_log.name_len= FN_LEN; create_ddl_log_file_name(file_name); if ((global_ddl_log.file_id= mysql_file_create(key_file_global_ddl_log, file_name, CREATE_MODE, @@ -886,6 +887,13 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) { DBUG_RETURN(FALSE); } + DBUG_PRINT("ddl_log", + ("execute type %c next %u name '%s' from_name '%s' handler '%s'", + ddl_log_entry->action_type, + ddl_log_entry->next_entry, + ddl_log_entry->name, + ddl_log_entry->from_name, + ddl_log_entry->handler_name)); handler_name.str= (char*)ddl_log_entry->handler_name; handler_name.length= strlen(ddl_log_entry->handler_name); init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); @@ -1093,6 +1101,15 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, DBUG_RETURN(TRUE); } error= FALSE; + DBUG_PRINT("ddl_log", + ("write type %c next %u name '%s' from_name '%s' handler '%s'", + (char) global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS], + ddl_log_entry->next_entry, + (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS], + (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + + FN_LEN], + (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + + (2*FN_LEN)])); if (write_ddl_log_file_entry((*active_entry)->entry_pos)) { error= TRUE; @@ -2615,7 +2632,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, !(sql_field->charset= get_charset_by_csname(sql_field->charset->csname, MY_CS_BINSORT,MYF(0)))) { - char tmp[64]; + char tmp[65]; strmake(strmake(tmp, save_cs->csname, sizeof(tmp)-4), STRING_WITH_LEN("_bin")); my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp); diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 8dc4b4ffeb6..fe56d6acf3e 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -168,6 +168,21 @@ TEST_join(JOIN *join) uint i,ref; DBUG_ENTER("TEST_join"); + /* + Assemble results of all the calls to full_name() first, + in order not to garble the tabular output below. + */ + String ref_key_parts[MAX_TABLES]; + for (i= 0; i < join->tables; i++) + { + JOIN_TAB *tab= join->join_tab + i; + for (ref= 0; ref < tab->ref.key_parts; ref++) + { + ref_key_parts[i].append(tab->ref.items[ref]->full_name()); + ref_key_parts[i].append(" "); + } + } + DBUG_LOCK_FILE; (void) fputs("\nInfo about JOIN\n",DBUG_FILE); for (i=0 ; i < join->tables ; i++) @@ -199,13 +214,8 @@ TEST_join(JOIN *join) } if (tab->ref.key_parts) { - (void) fputs(" refs: ",DBUG_FILE); - for (ref=0 ; ref < tab->ref.key_parts ; ref++) - { - Item *item=tab->ref.items[ref]; - fprintf(DBUG_FILE,"%s ", item->full_name()); - } - (void) fputc('\n',DBUG_FILE); + fprintf(DBUG_FILE, + " refs: %s\n", ref_key_parts[i].ptr()); } } DBUG_UNLOCK_FILE; diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index ff7573b4cfd..d0e446fb157 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -421,6 +421,7 @@ int mysql_create_function(THD *thd,udf_func *udf) TABLE *table; TABLE_LIST tables; udf_func *u_d; + bool save_binlog_row_based; DBUG_ENTER("mysql_create_function"); if (!initialized) @@ -460,8 +461,8 @@ int mysql_create_function(THD *thd,udf_func *udf) Turn off row binlogging of this statement and use statement-based so that all supporting tables are updated for CREATE FUNCTION command. */ - if (thd->is_current_stmt_binlog_format_row()) - thd->clear_current_stmt_binlog_format_row(); + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); + thd->clear_current_stmt_binlog_format_row(); mysql_rwlock_wrlock(&THR_LOCK_udf); if ((my_hash_search(&udf_hash,(uchar*) udf->name.str, udf->name.length))) @@ -530,13 +531,21 @@ int mysql_create_function(THD *thd,udf_func *udf) /* Binlog the create function. */ if (write_bin_log(thd, TRUE, thd->query(), thd->query_length())) + { + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(1); + } + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(0); err: if (new_dl) dlclose(dl); mysql_rwlock_unlock(&THR_LOCK_udf); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(1); } @@ -548,6 +557,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) udf_func *udf; char *exact_name_str; uint exact_name_len; + bool save_binlog_row_based; DBUG_ENTER("mysql_drop_function"); if (!initialized) @@ -563,8 +573,8 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) Turn off row binlogging of this statement and use statement-based so that all supporting tables are updated for DROP FUNCTION command. */ - if (thd->is_current_stmt_binlog_format_row()) - thd->clear_current_stmt_binlog_format_row(); + save_binlog_row_based= thd->is_current_stmt_binlog_format_row(); + thd->clear_current_stmt_binlog_format_row(); mysql_rwlock_wrlock(&THR_LOCK_udf); if (!(udf=(udf_func*) my_hash_search(&udf_hash,(uchar*) udf_name->str, @@ -605,10 +615,18 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) /* Binlog the drop function. */ if (write_bin_log(thd, TRUE, thd->query(), thd->query_length())) + { + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(1); + } + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(0); err: mysql_rwlock_unlock(&THR_LOCK_udf); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(1); } diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 5bdff4dc9bf..ad14d2e4ecd 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -335,6 +335,35 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } } + /* + Disable the usage of fulltext searches in the last union branch. + This is a temporary 5.x limitation because of the way the fulltext + search functions are handled by the optimizer. + This is manifestation of the more general problems of "taking away" + parts of a SELECT statement post-fix_fields(). This is generally not + doable since various flags are collected in various places (e.g. + SELECT_LEX) that carry information about the presence of certain + expressions or constructs in the parts of the query. + When part of the query is taken away it's not clear how to "divide" + the meaning of these accumulated flags and what to carry over to the + recipient query (SELECT_LEX). + */ + if (global_parameters->ftfunc_list->elements && + global_parameters->order_list.elements && + global_parameters != fake_select_lex) + { + ORDER *ord; + Item_func::Functype ft= Item_func::FT_FUNC; + for (ord= (ORDER*)global_parameters->order_list.first; ord; ord= ord->next) + if ((*ord->item)->walk (&Item::find_function_processor, FALSE, + (uchar *) &ft)) + { + my_error (ER_CANT_USE_OPTION_HERE, MYF(0), "MATCH()"); + goto err; + } + } + + create_options= (first_sl->options | thd_arg->variables.option_bits | TMP_TABLE_ALL_COLUMNS); /* @@ -669,7 +698,7 @@ bool st_select_lex_unit::cleanup() { ORDER *ord; for (ord= (ORDER*)global_parameters->order_list.first; ord; ord= ord->next) - (*ord->item)->cleanup(); + (*ord->item)->walk (&Item::cleanup_processor, 0, 0); } } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index e3f85c6215d..97abf2cd89b 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -24,6 +24,7 @@ #include "sp_head.h" #include "sql_trigger.h" #include "probes_mysql.h" +#include "debug_sync.h" /* Return 0 if row hasn't changed */ @@ -1137,8 +1138,11 @@ reopen_tables: items from 'fields' list, so the cleanup above is necessary to. */ cleanup_items(thd->free_list); - + cleanup_items(thd->stmt_arena->free_list); close_tables_for_reopen(thd, &table_list); + + DEBUG_SYNC(thd, "multi_update_reopen_tables"); + goto reopen_tables; } @@ -1864,6 +1868,7 @@ void multi_update::abort() into repl event. */ int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); + /* the error of binary logging is ignored */ (void)thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), transactional_tables, FALSE, FALSE, errcode); diff --git a/sql/table.cc b/sql/table.cc index c0c365f4901..3e2e5adc2c7 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -215,10 +215,7 @@ TABLE_CATEGORY get_table_category(const LEX_STRING *db, const LEX_STRING *name) DBUG_ASSERT(db != NULL); DBUG_ASSERT(name != NULL); - if ((db->length == INFORMATION_SCHEMA_NAME.length) && - (my_strcasecmp(system_charset_info, - INFORMATION_SCHEMA_NAME.str, - db->str) == 0)) + if (is_infoschema_db(db->str, db->length)) return TABLE_CATEGORY_INFORMATION; if ((db->length == PERFORMANCE_SCHEMA_DB_NAME.length) && @@ -3941,7 +3938,8 @@ const char *Natural_join_column::db_name() DBUG_ASSERT(!strcmp(table_ref->db, table_ref->table->s->db.str) || (table_ref->schema_table && - is_infoschema_db(table_ref->table->s->db.str))); + is_infoschema_db(table_ref->table->s->db.str, + table_ref->table->s->db.length))); return table_ref->db; } @@ -4159,7 +4157,8 @@ const char *Field_iterator_table_ref::get_db_name() */ DBUG_ASSERT(!strcmp(table_ref->db, table_ref->table->s->db.str) || (table_ref->schema_table && - is_infoschema_db(table_ref->table->s->db.str))); + is_infoschema_db(table_ref->table->s->db.str, + table_ref->table->s->db.length))); return table_ref->db; } |