From f7f10959084aa815e1e4f10b6dc02aafa9de588b Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Sep 2007 12:09:00 +0400 Subject: Bug#30384: Having SQL_BUFFER_RESULT option in the CREATE .. KEY(..) .. SELECT led to creating corrupted index. While execution of the CREATE .. SELECT SQL_BUFFER_RESULT statement the engine->start_bulk_insert function was called twice. On the first call On the first call MyISAM disabled all non-unique indexes and on the second call it decides to not re-enable them because all indexes was disabled. Due to this no indexes was actually created during CREATE TABLE thus producing crashed table. Now the select_inset class has is_bulk_insert_mode flag which prevents calling the start_bulk_insert function twice. The flag is set in the select_create::prepare, select_insert::prepare2 functions and the select_insert class constructor. The flag is reset in the select_insert::send_eof function. mysql-test/t/insert_select.test: A test case is added for the bug#30384: Having SQL_BUFFER_RESULT option in the CREATE .. KEY(..) .. SELECT led to creating corrupted index. mysql-test/r/insert_select.result: A test case is added for the bug#30384: Having SQL_BUFFER_RESULT option in the CREATE .. KEY(..) .. SELECT led to creating corrupted index. sql/sql_class.h: Bug#30384: Having SQL_BUFFER_RESULT option in the CREATE .. KEY(..) .. SELECT led to creating corrupted index. The is_bulk_insert_mode flag is added to the select_insert class. sql/sql_insert.cc: Bug#30384: Having SQL_BUFFER_RESULT option in the CREATE .. KEY(..) .. SELECT led to creating corrupted index. The is_bulk_insert_mode is set in the select_create::prepare, select_insert::prepare2 functions and the select_insert class constructor. The flag is reset in the select_insert::send_eof function. --- sql/sql_class.h | 2 +- sql/sql_insert.cc | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.h b/sql/sql_class.h index 4fac86dc405..e6d65f3133a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2029,7 +2029,7 @@ class select_insert :public select_result_interceptor { ulonglong last_insert_id; COPY_INFO info; bool insert_into_view; - + bool is_bulk_insert_mode; select_insert(TABLE_LIST *table_list_par, TABLE *table_par, List *fields_par, List *update_fields, List *update_values, diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f07af393070..cf0016198da 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2647,7 +2647,8 @@ select_insert::select_insert(TABLE_LIST *table_list_par, TABLE *table_par, bool ignore_check_option_errors) :table_list(table_list_par), table(table_par), fields(fields_par), last_insert_id(0), - insert_into_view(table_list_par && table_list_par->view != 0) + insert_into_view(table_list_par && table_list_par->view != 0), + is_bulk_insert_mode(FALSE) { bzero((char*) &info,sizeof(info)); info.handle_duplicates= duplic; @@ -2832,8 +2833,11 @@ int select_insert::prepare2(void) { DBUG_ENTER("select_insert::prepare2"); if (thd->lex->current_select->options & OPTION_BUFFER_RESULT && - !thd->prelocked_mode) + !thd->prelocked_mode && !is_bulk_insert_mode) + { table->file->start_bulk_insert((ha_rows) 0); + is_bulk_insert_mode= TRUE; + } DBUG_RETURN(0); } @@ -2939,6 +2943,7 @@ bool select_insert::send_eof() DBUG_ENTER("select_insert::send_eof"); error= (!thd->prelocked_mode) ? table->file->end_bulk_insert():0; + is_bulk_insert_mode= FALSE; table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); @@ -3271,7 +3276,10 @@ select_create::prepare(List &values, SELECT_LEX_UNIT *u) if (info.handle_duplicates == DUP_UPDATE) table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE); if (!thd->prelocked_mode) + { table->file->start_bulk_insert((ha_rows) 0); + is_bulk_insert_mode= TRUE; + } thd->abort_on_warning= (!info.ignore && (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | -- cgit v1.2.1 From ebaa05efa757c475161cb5c7f0a1adcbe9f59ff3 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Sep 2007 11:49:27 +0400 Subject: Bug#27216: functions with parameters of different date types may return wrong type of the result. There are several functions that accept parameters of different types. The result field type of such functions was determined based on the aggregated result type of its arguments. As the DATE and the DATETIME types are represented by the STRING type, the result field type of the affected functions was always STRING for DATE/DATETIME arguments. The affected functions are COALESCE, IF, IFNULL, CASE, LEAST/GREATEST, CASE. Now the affected functions aggregate the field types of their arguments rather than their result types and return the result of aggregation as their result field type. The cached_field_type member variable is added to the number of classes to hold the aggregated result field type. The str_to_date() function's result field type now defaults to the MYSQL_TYPE_DATETIME. The agg_field_type() function is added. It aggregates field types with help of the Field::field_type_merge() function. The create_table_from_items() function now uses the item->tmp_table_field_from_field_type() function to get the proper field when the item is a function with a STRING result type. libmysql/libmysql.c: Bug#27216: functions with parameters of different date types may return wrong type of the result. The client library now accepts the NEWDATE type as a string. sql/item_cmpfunc.cc: Bug#27216: functions with parameters of different date types may return wrong type of the result. Now the fix_length_and_dec functions of the Item_func_ifnull,Item_func_if, Item_func_case, Item_func_coalesce classes are use agg_field_type function to find out the type of their result field. sql/item_cmpfunc.h: Bug#27216: functions with parameters of different date types may return wrong type of the result. The cached_field type is added to the Item_func_case, Item_func_if and Item_func_coalesce classes. The field_type function is added to the Item_func_ifnull, Item_func_if, Item_func_coalesce, Item_func_case classes. sql/item_func.cc: Bug#27216: functions with parameters of different date types may return wrong type of the result. The Item_func_min_max::fix_length_and_dec function now uses the agg_field_type function to find out the correct type of the result field. sql/item_func.h: Bug#27216: functions with parameters of different date types may return wrong type of the result. The cached_field_type variable is added to the Item_func_min_max class. sql/item_timefunc.cc: Bug#27216: functions with parameters of different date types may return wrong type of the result. The result of the str_to_date function now defaults to the DATETIME type. sql/mysql_priv.h: Bug#27216: functions with parameters of different date types may return wrong type of the result. The prototype of the agg_field_type function is added. sql/protocol.cc: Bug#27216: functions with parameters of different date types may return wrong type of the result. The Protocol_simple::store function is now used to store fields of NEWDATE type. sql/sql_insert.cc: Bug#27216: functions with parameters of different date types may return wrong type of the result. The create_table_from_items function now uses the tmp_table_field_from_field_type function to get field for items with the STRING result type. mysql-test/r/date_formats.result: A test case result corrected after fixing bug#27216. mysql-test/r/type_datetime.result: Added a test case for the bug#27216: functions with parameters of different date types may return wrong type of the result. mysql-test/t/type_datetime.test: Added a test case for the bug#27216: functions with parameters of different date types may return wrong type of the result. --- sql/item_cmpfunc.cc | 40 ++++++++++++++++++++++++++++++++++++---- sql/item_cmpfunc.h | 8 +++++++- sql/item_func.cc | 1 + sql/item_func.h | 4 +++- sql/item_timefunc.cc | 2 +- sql/mysql_priv.h | 1 + sql/protocol.cc | 1 + sql/sql_insert.cc | 5 ++++- 8 files changed, 54 insertions(+), 8 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 86eb10d50b0..1599bcc1571 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -147,6 +147,36 @@ static int agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems) } +/** + @brief Aggregates field types from the array of items. + + @param[in] items array of items to aggregate the type from + @paran[in] nitems number of items in the array + + @details This function aggregates field types from the array of items. + Found type is supposed to be used later as the result field type + of a multi-argument function. + Aggregation itself is performed by the Field::field_type_merge() + function. + + @note The term "aggregation" is used here in the sense of inferring the + result type of a function from its argument types. + + @return aggregated field type. +*/ + +enum_field_types agg_field_type(Item **items, uint nitems) +{ + uint i; + if (!nitems || items[0]->result_type() == ROW_RESULT ) + return (enum_field_types)-1; + enum_field_types res= items[0]->field_type(); + for (i= 1 ; i < nitems ; i++) + res= Field::field_type_merge(res, items[i]->field_type()); + return res; +} + + static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname) { @@ -2009,9 +2039,7 @@ Item_func_ifnull::fix_length_and_dec() default: DBUG_ASSERT(0); } - cached_field_type= args[0]->field_type(); - if (cached_field_type != args[1]->field_type()) - cached_field_type= Item_func::field_type(); + cached_field_type= agg_field_type(args, 2); } @@ -2159,11 +2187,13 @@ Item_func_if::fix_length_and_dec() { cached_result_type= arg2_type; collation.set(args[2]->collation.collation); + cached_field_type= args[2]->field_type(); } else if (null2) { cached_result_type= arg1_type; collation.set(args[1]->collation.collation); + cached_field_type= args[1]->field_type(); } else { @@ -2177,6 +2207,7 @@ Item_func_if::fix_length_and_dec() { collation.set(&my_charset_bin); // Number } + cached_field_type= agg_field_type(args + 1, 2); } if ((cached_result_type == DECIMAL_RESULT ) @@ -2556,7 +2587,7 @@ void Item_func_case::fix_length_and_dec() agg_arg_charsets(collation, agg, nagg, MY_COLL_ALLOW_CONV, 1)) return; - + cached_field_type= agg_field_type(agg, nagg); /* Aggregate first expression and all THEN expression types and collations when string comparison @@ -2695,6 +2726,7 @@ my_decimal *Item_func_coalesce::decimal_op(my_decimal *decimal_value) void Item_func_coalesce::fix_length_and_dec() { + cached_field_type= agg_field_type(args, arg_count); agg_result_type(&hybrid_type, args, arg_count); switch (hybrid_type) { case STRING_RESULT: diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 8410c66b034..4d3df7aebf9 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -640,6 +640,7 @@ public: class Item_func_coalesce :public Item_func_numhybrid { protected: + enum_field_types cached_field_type; Item_func_coalesce(Item *a, Item *b) :Item_func_numhybrid(a, b) {} public: Item_func_coalesce(List &list) :Item_func_numhybrid(list) {} @@ -652,13 +653,13 @@ public: enum Item_result result_type () const { return hybrid_type; } const char *func_name() const { return "coalesce"; } table_map not_null_tables() const { return 0; } + enum_field_types field_type() const { return cached_field_type; } }; class Item_func_ifnull :public Item_func_coalesce { protected: - enum_field_types cached_field_type; bool field_type_defined; public: Item_func_ifnull(Item *a, Item *b) :Item_func_coalesce(a,b) {} @@ -677,6 +678,7 @@ public: class Item_func_if :public Item_func { enum Item_result cached_result_type; + enum_field_types cached_field_type; public: Item_func_if(Item *a,Item *b,Item *c) :Item_func(a,b,c), cached_result_type(INT_RESULT) @@ -686,6 +688,7 @@ public: String *val_str(String *str); my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return cached_result_type; } + enum_field_types field_type() const { return cached_field_type; } bool fix_fields(THD *, Item **); void fix_length_and_dec(); uint decimal_precision() const; @@ -722,6 +725,7 @@ class Item_func_case :public Item_func uint ncases; Item_result cmp_type; DTCollation cmp_collation; + enum_field_types cached_field_type; public: Item_func_case(List &list, Item *first_expr_arg, Item *else_expr_arg) :Item_func(), first_expr_num(-1), else_expr_num(-1), @@ -749,6 +753,7 @@ public: uint decimal_precision() const; table_map not_null_tables() const { return 0; } enum Item_result result_type () const { return cached_result_type; } + enum_field_types field_type() const { return cached_field_type; } const char *func_name() const { return "case"; } void print(String *str); Item *find_item(String *str); @@ -1382,6 +1387,7 @@ public: bool subst_argument_checker(byte **arg) { return TRUE; } Item *compile(Item_analyzer analyzer, byte **arg_p, Item_transformer transformer, byte *arg_t); + enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } }; diff --git a/sql/item_func.cc b/sql/item_func.cc index d03d497dfd0..f1c519896b4 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2243,6 +2243,7 @@ void Item_func_min_max::fix_length_and_dec() else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT)) max_length= my_decimal_precision_to_length(max_int_part+decimals, decimals, unsigned_flag); + cached_field_type= agg_field_type(args, arg_count); } diff --git a/sql/item_func.h b/sql/item_func.h index 56b5e75652c..57e33daf0c4 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -692,7 +692,8 @@ class Item_func_min_max :public Item_func /* An item used for issuing warnings while string to DATETIME conversion. */ Item *datetime_item; THD *thd; - +protected: + enum_field_types cached_field_type; public: Item_func_min_max(List &list,int cmp_sign_arg) :Item_func(list), cmp_type(INT_RESULT), cmp_sign(cmp_sign_arg), compare_as_dates(FALSE), @@ -705,6 +706,7 @@ public: enum Item_result result_type () const { return cmp_type; } bool result_as_longlong() { return compare_as_dates; }; uint cmp_datetimes(ulonglong *value); + enum_field_types field_type() const { return cached_field_type; } }; class Item_func_min :public Item_func_min_max diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index ae18e4786d7..b7c9086c127 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -3310,7 +3310,7 @@ void Item_func_str_to_date::fix_length_and_dec() String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format; maybe_null= 1; decimals=0; - cached_field_type= MYSQL_TYPE_STRING; + cached_field_type= MYSQL_TYPE_DATETIME; max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; cached_timestamp_type= MYSQL_TIMESTAMP_NONE; format= args[1]->val_str(&format_str); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 44eb5590a28..5bec94857f7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1220,6 +1220,7 @@ my_bool mysql_rm_tmp_tables(void); /* item_func.cc */ extern bool check_reserved_words(LEX_STRING *name); +extern enum_field_types agg_field_type(Item **items, uint nitems); /* strfunc.cc */ ulonglong find_set(TYPELIB *lib, const char *x, uint length, CHARSET_INFO *cs, diff --git a/sql/protocol.cc b/sql/protocol.cc index ced6d78519a..2bdbe83eea1 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -824,6 +824,7 @@ bool Protocol_simple::store(const char *from, uint length, field_types[field_pos] == MYSQL_TYPE_DECIMAL || field_types[field_pos] == MYSQL_TYPE_BIT || field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL || + field_types[field_pos] == MYSQL_TYPE_NEWDATE || (field_types[field_pos] >= MYSQL_TYPE_ENUM && field_types[field_pos] <= MYSQL_TYPE_GEOMETRY)); field_pos++; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f07af393070..fc403132240 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3129,7 +3129,10 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, create_field *cr_field; Field *field, *def_field; if (item->type() == Item::FUNC_ITEM) - field= item->tmp_table_field(&tmp_table); + if (item->result_type() != STRING_RESULT) + field= item->tmp_table_field(&tmp_table); + else + field= item->tmp_table_field_from_field_type(&tmp_table); else field= create_tmp_field(thd, &tmp_table, item, item->type(), (Item ***) 0, &tmp_field, &def_field, 0, 0, 0, 0, -- cgit v1.2.1