diff options
author | Kristofer Pettersson <kristofer.pettersson@sun.com> | 2009-03-06 11:49:39 +0100 |
---|---|---|
committer | Kristofer Pettersson <kristofer.pettersson@sun.com> | 2009-03-06 11:49:39 +0100 |
commit | 55c779cdbf0e402338bb32253a2fc1db7fa02129 (patch) | |
tree | a2136f93bb28c0e655cf133c9245ead5bf039ae9 /sql | |
parent | ac821c65701d38ced2d3167cf9c54559599d4f52 (diff) | |
parent | b4fdb8aec14b533db4a5ea2f99c1a9f3ce07946c (diff) | |
download | mariadb-git-55c779cdbf0e402338bb32253a2fc1db7fa02129.tar.gz |
Manual merge
Diffstat (limited to 'sql')
57 files changed, 1718 insertions, 748 deletions
diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index 0b57fe86e62..aaaa3b8ffb4 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -416,37 +416,96 @@ int ha_tina::find_current_row(byte *buf) if ((end_ptr= find_eoln(share->mapped_file, current_position, share->file_stat.st_size)) == 0) DBUG_RETURN(HA_ERR_END_OF_FILE); + /* + Parse the line obtained using the following algorithm + + BEGIN + 1) Store the EOL (end of line) for the current row + 2) Until all the fields in the current query have not been + filled + 2.1) If the current character begins with a quote + 2.1.1) Until EOL has not been reached + a) If end of current field is reached, move + to next field and jump to step 2.3 + b) If current character begins with \\ handle + \\n, \\r, \\, \\" + c) else append the current character into the buffer + before checking that EOL has not been reached. + 2.2) If the current character does not begin with a quote + 2.2.1) Until EOL has not been reached + a) If the end of field has been reached move to the + next field and jump to step 2.3 + b) append the current character into the buffer + 2.3) Store the current field value and jump to 2) + TERMINATE + */ + for (Field **field=table->field ; *field ; field++) { buffer.length(0); - mapped_ptr++; // Increment past the first quote - for(;mapped_ptr != end_ptr; mapped_ptr++) + /* Handle the case where the first character begins with a quote */ + if (*mapped_ptr == '"') { - //Need to convert line feeds! - if (*mapped_ptr == '"' && - (((mapped_ptr[1] == ',') && (mapped_ptr[2] == '"')) || (mapped_ptr == end_ptr -1 ))) + /* Increment past the first quote */ + mapped_ptr++; + /* Loop through the row to extract the values for the current field */ + for(; mapped_ptr != end_ptr; mapped_ptr++) { - mapped_ptr += 2; // Move past the , and the " - break; - } - if (*mapped_ptr == '\\' && mapped_ptr != (end_ptr - 1)) - { - mapped_ptr++; - if (*mapped_ptr == 'r') - buffer.append('\r'); - else if (*mapped_ptr == 'n' ) - buffer.append('\n'); - else if ((*mapped_ptr == '\\') || (*mapped_ptr == '"')) - buffer.append(*mapped_ptr); - else /* This could only happed with an externally created file */ + /* check for end of the current field */ + if (*mapped_ptr == '"' && + (mapped_ptr[1] == ',' || mapped_ptr == end_ptr -1 )) { - buffer.append('\\'); + /* Move past the , and the " */ + mapped_ptr += 2; + break; + } + if (*mapped_ptr == '\\' && mapped_ptr != (end_ptr - 1)) + { + mapped_ptr++; + if (*mapped_ptr == 'r') + buffer.append('\r'); + else if (*mapped_ptr == 'n' ) + buffer.append('\n'); + else if ((*mapped_ptr == '\\') || (*mapped_ptr == '"')) + buffer.append(*mapped_ptr); + else /* This could only happed with an externally created file */ + { + buffer.append('\\'); + buffer.append(*mapped_ptr); + } + } + else + { + /* + If no last quote was found, but the end of row has been reached + it implies that there has been error. + */ + if (mapped_ptr == end_ptr -1) + DBUG_RETURN(HA_ERR_END_OF_FILE); + /* Store current character in the buffer for the field */ buffer.append(*mapped_ptr); } - } - else + } + } + else + { + /* Handle the case where the current row does not start with quotes */ + + /* Loop through the row to extract the values for the current field */ + for (; mapped_ptr != end_ptr; mapped_ptr++) + { + /* check for end of current field */ + if (*mapped_ptr == ',') + { + /* Increment past the current comma */ + mapped_ptr++; + break; + } + /* store the current character in the buffer for the field */ buffer.append(*mapped_ptr); + } } + /* Store the field value from the buffer */ (*field)->store(buffer.ptr(), buffer.length(), buffer.charset()); } next_position= (end_ptr - share->mapped_file)+1; diff --git a/sql/field.cc b/sql/field.cc index 3d3f698f912..f8ab4b852ec 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -3473,7 +3473,7 @@ int Field_longlong::store(double nr) error= 1; } else - res=(longlong) (ulonglong) nr; + res=(longlong) double2ulonglong(nr); } else { @@ -5372,6 +5372,7 @@ int Field_newdate::store_time(MYSQL_TIME *ltime, timestamp_type time_type) { char buff[MAX_DATE_STRING_REP_LENGTH]; String str(buff, sizeof(buff), &my_charset_latin1); + tmp= 0; make_date((DATE_TIME_FORMAT *) 0, ltime, &str); set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, str.ptr(), str.length(), MYSQL_TIMESTAMP_DATE, 1); @@ -5608,6 +5609,7 @@ int Field_datetime::store_time(MYSQL_TIME *ltime,timestamp_type time_type) { char buff[MAX_DATE_STRING_REP_LENGTH]; String str(buff, sizeof(buff), &my_charset_latin1); + tmp= 0; make_datetime((DATE_TIME_FORMAT *) 0, ltime, &str); set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, str.ptr(), str.length(), MYSQL_TIMESTAMP_DATETIME,1); diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index b4788dd9c87..d4144a41a2a 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -1320,6 +1320,14 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) thr_lock_init(&share->lock); pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST); } + else + { + /* + Free tmp_share.scheme allocated in the parse_url() + as we found share in the hash and tmp_share isn't needed anymore. + */ + my_free((gptr) tmp_share.scheme, MYF(MY_ALLOW_ZERO_PTR)); + } share->use_count++; pthread_mutex_unlock(&federated_mutex); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 1c0f8a6e9b3..3bae0da3e02 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -524,6 +524,20 @@ convert_error_code_to_mysql( mark_transaction_to_rollback(thd, TRUE); return(HA_ERR_LOCK_TABLE_FULL); + } else if (error == DB_TOO_MANY_CONCURRENT_TRXS) { + + /* Once MySQL add the appropriate code to errmsg.txt then + we can get rid of this #ifdef. NOTE: The code checked by + the #ifdef is the suggested name for the error condition + and the actual error code name could very well be different. + This will require some monitoring, ie. the status + of this request on our part.*/ +#ifdef ER_TOO_MANY_CONCURRENT_TRXS + return(ER_TOO_MANY_CONCURRENT_TRXS); +#else + return(HA_ERR_RECORD_FILE_FULL); +#endif + } else if (error == DB_UNSUPPORTED) { return(HA_ERR_UNSUPPORTED); @@ -2158,6 +2172,14 @@ ha_innobase::open( UT_NOT_USED(test_if_locked); thd = current_thd; + + /* Under some cases MySQL seems to call this function while + holding btr_search_latch. This breaks the latching order as + we acquire dict_sys->mutex below and leads to a deadlock. */ + if (thd != NULL) { + innobase_release_temporary_latches(thd); + } + normalize_table_name(norm_name, name); user_thd = NULL; @@ -3723,7 +3745,6 @@ convert_search_mode_to_innobase( case HA_READ_MBR_WITHIN: case HA_READ_MBR_DISJOINT: case HA_READ_MBR_EQUAL: - my_error(ER_TABLE_CANT_HANDLE_SPKEYS, MYF(0)); return(PAGE_CUR_UNSUPP); /* do not use "default:" in order to produce a gcc warning: enumeration value '...' not handled in switch @@ -5204,7 +5225,7 @@ ha_innobase::records_in_range( mode2); } else { - n_rows = 0; + n_rows = HA_POS_ERROR; } dtuple_free_for_mysql(heap1); diff --git a/sql/handler.cc b/sql/handler.cc index 67ec5f3e759..71d184ad84b 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1957,8 +1957,53 @@ bool handler::get_error_message(int error, String* buf) } +/** + Check for incompatible collation changes. + + @retval + HA_ADMIN_NEEDS_UPGRADE Table may have data requiring upgrade. + @retval + 0 No upgrade required. +*/ + +int handler::check_collation_compatibility() +{ + ulong mysql_version= table->s->mysql_version; + + if (mysql_version < 50048) + { + KEY *key= table->key_info; + KEY *key_end= key + table->s->keys; + for (; key < key_end; key++) + { + KEY_PART_INFO *key_part= key->key_part; + KEY_PART_INFO *key_part_end= key_part + key->key_parts; + for (; key_part < key_part_end; key_part++) + { + if (!key_part->fieldnr) + continue; + Field *field= table->field[key_part->fieldnr - 1]; + uint cs_number= field->charset()->number; + if (mysql_version < 50048 && + (cs_number == 11 || /* ascii_general_ci - bug #29499, bug #27562 */ + cs_number == 41 || /* latin7_general_ci - bug #29461 */ + cs_number == 42 || /* latin7_general_cs - bug #29461 */ + cs_number == 20 || /* latin7_estonian_cs - bug #29461 */ + cs_number == 21 || /* latin2_hungarian_ci - bug #29461 */ + cs_number == 22 || /* koi8u_general_ci - bug #29461 */ + cs_number == 23 || /* cp1251_ukrainian_ci - bug #29461 */ + cs_number == 26)) /* cp1250_general_ci - bug #29461 */ + return HA_ADMIN_NEEDS_UPGRADE; + } + } + } + return 0; +} + + int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt) { + int error; KEY *keyinfo, *keyend; KEY_PART_INFO *keypart, *keypartend; @@ -1987,6 +2032,10 @@ int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt) } if (table->s->frm_version != FRM_VER_TRUE_VARCHAR) return HA_ADMIN_NEEDS_ALTER; + + if ((error= check_collation_compatibility())) + return error; + return check_for_upgrade(check_opt); } diff --git a/sql/handler.h b/sql/handler.h index aa3377c3868..8706aae5fce 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -787,6 +787,7 @@ protected: virtual int check_for_upgrade(HA_CHECK_OPT *check_opt) { return 0; } public: + int check_collation_compatibility(); int ha_check_for_upgrade(HA_CHECK_OPT *check_opt); int check_old_types(); /* to be actually called to get 'check()' functionality*/ diff --git a/sql/item.cc b/sql/item.cc index 182f4abdfe6..f32828629cf 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -321,7 +321,7 @@ int Item::save_time_in_field(Field *field) { MYSQL_TIME ltime; if (get_time(<ime)) - return set_field_to_null(field); + return set_field_to_null_with_conversions(field, 0); field->set_notnull(); return field->store_time(<ime, MYSQL_TIMESTAMP_TIME); } @@ -331,7 +331,7 @@ int Item::save_date_in_field(Field *field) { MYSQL_TIME ltime; if (get_date(<ime, TIME_FUZZY_DATE)) - return set_field_to_null(field); + return set_field_to_null_with_conversions(field, 0); field->set_notnull(); return field->store_time(<ime, MYSQL_TIMESTAMP_DATETIME); } @@ -1243,13 +1243,26 @@ Item::Type Item_name_const::type() const valid_args guarantees value_item->basic_const_item(); if type is FUNC_ITEM, then we have a fudged item_func_neg() on our hands and return the underlying type. + For Item_func_set_collation() + e.g. NAME_CONST('name', 'value' COLLATE collation) we return its + 'value' argument type. */ - return valid_args ? - (((value_item->type() == FUNC_ITEM) && - (((Item_func *) value_item)->functype() == Item_func::NEG_FUNC)) ? - ((Item_func *) value_item)->key_item()->type() : - value_item->type()) : - NULL_ITEM; + if (!valid_args) + return NULL_ITEM; + Item::Type value_type= value_item->type(); + if (value_type == FUNC_ITEM) + { + /* + The second argument of NAME_CONST('name', 'value') must be + a simple constant item or a NEG_FUNC/COLLATE_FUNC. + */ + DBUG_ASSERT(((Item_func *) value_item)->functype() == + Item_func::NEG_FUNC || + ((Item_func *) value_item)->functype() == + Item_func::COLLATE_FUNC); + return ((Item_func *) value_item)->key_item()->type(); + } + return value_type; } @@ -1595,42 +1608,11 @@ bool agg_item_collations_for_comparison(DTCollation &c, const char *fname, } -/* - Collect arguments' character sets together. - We allow to apply automatic character set conversion in some cases. - The conditions when conversion is possible are: - - arguments A and B have different charsets - - A wins according to coercibility rules - (i.e. a column is stronger than a string constant, - an explicit COLLATE clause is stronger than a column) - - character set of A is either superset for character set of B, - or B is a string constant which can be converted into the - character set of A without data loss. - - If all of the above is true, then it's possible to convert - B into the character set of A, and then compare according - to the collation of A. - - For functions with more than two arguments: - collect(A,B,C) ::= collect(collect(A,B),C) - - Since this function calls THD::change_item_tree() on the passed Item ** - pointers, it is necessary to pass the original Item **'s, not copies. - Otherwise their values will not be properly restored (see BUG#20769). - If the items are not consecutive (eg. args[2] and args[5]), use the - item_sep argument, ie. - - agg_item_charsets(coll, fname, &args[2], 2, flags, 3) - -*/ - -bool agg_item_charsets(DTCollation &coll, const char *fname, - Item **args, uint nargs, uint flags, int item_sep) +bool agg_item_set_converter(DTCollation &coll, const char *fname, + Item **args, uint nargs, uint flags, int item_sep) { Item **arg, *safe_args[2]; - if (agg_item_collations(coll, fname, args, nargs, flags, item_sep)) - return TRUE; /* For better error reporting: save the first and the second argument. @@ -1711,6 +1693,46 @@ bool agg_item_charsets(DTCollation &coll, const char *fname, } +/* + Collect arguments' character sets together. + We allow to apply automatic character set conversion in some cases. + The conditions when conversion is possible are: + - arguments A and B have different charsets + - A wins according to coercibility rules + (i.e. a column is stronger than a string constant, + an explicit COLLATE clause is stronger than a column) + - character set of A is either superset for character set of B, + or B is a string constant which can be converted into the + character set of A without data loss. + + If all of the above is true, then it's possible to convert + B into the character set of A, and then compare according + to the collation of A. + + For functions with more than two arguments: + + collect(A,B,C) ::= collect(collect(A,B),C) + + Since this function calls THD::change_item_tree() on the passed Item ** + pointers, it is necessary to pass the original Item **'s, not copies. + Otherwise their values will not be properly restored (see BUG#20769). + If the items are not consecutive (eg. args[2] and args[5]), use the + item_sep argument, ie. + + agg_item_charsets(coll, fname, &args[2], 2, flags, 3) + +*/ + +bool agg_item_charsets(DTCollation &coll, const char *fname, + Item **args, uint nargs, uint flags, int item_sep) +{ + if (agg_item_collations(coll, fname, args, nargs, flags, item_sep)) + return TRUE; + + return agg_item_set_converter(coll, fname, args, nargs, flags, item_sep); +} + + void Item_ident_for_show::make_field(Send_field *tmp_field) { tmp_field->table_name= tmp_field->org_table_name= table_name; @@ -2041,6 +2063,12 @@ bool Item_field::val_bool_result() } +bool Item_field::is_null_result() +{ + return (null_value=result_field->is_null()); +} + + bool Item_field::eq(const Item *item, bool binary_cmp) const { Item *real_item= ((Item *) item)->real_item(); @@ -2991,7 +3019,7 @@ bool Item_param::convert_str_value(THD *thd) str_value.set_charset(value.cs_info.final_character_set_of_str_value); /* Here str_value is guaranteed to be in final_character_set_of_str_value */ - max_length= str_value.length(); + max_length= str_value.numchars() * str_value.charset()->mbmaxlen; decimals= 0; /* str_value_ptr is returned from val_str(). It must be not alloced @@ -4950,6 +4978,9 @@ int Item_hex_string::save_in_field(Field *field, bool no_conversions) ulonglong nr; uint32 length= str_value.length(); + if (!length) + return 1; + if (length > 8) { nr= field->flags & UNSIGNED_FLAG ? ULONGLONG_MAX : LONGLONG_MAX; @@ -5626,6 +5657,15 @@ double Item_ref::val_result() } +bool Item_ref::is_null_result() +{ + if (result_field) + return (null_value=result_field->is_null()); + + return is_null(); +} + + longlong Item_ref::val_int_result() { if (result_field) @@ -5731,7 +5771,9 @@ String *Item_ref::val_str(String* tmp) bool Item_ref::is_null() { DBUG_ASSERT(fixed); - return (*ref)->is_null(); + bool tmp=(*ref)->is_null_result(); + null_value=(*ref)->null_value; + return tmp; } @@ -6792,7 +6834,7 @@ enum_field_types Item_type_holder::get_real_type(Item *item) */ Item_sum *item_sum= (Item_sum *) item; if (item_sum->keep_field_type()) - return get_real_type(item_sum->args[0]); + return get_real_type(item_sum->get_arg(0)); break; } case FUNC_ITEM: @@ -7056,7 +7098,7 @@ void Item_type_holder::get_full_info(Item *item) if (item->type() == Item::SUM_FUNC_ITEM && (((Item_sum*)item)->sum_func() == Item_sum::MAX_FUNC || ((Item_sum*)item)->sum_func() == Item_sum::MIN_FUNC)) - item = ((Item_sum*)item)->args[0]; + item = ((Item_sum*)item)->get_arg(0); /* We can have enum/set type after merging only if we have one enum|set field (or MIN|MAX(enum|set field)) and number of NULL fields diff --git a/sql/item.h b/sql/item.h index 250bb3f67ef..852b0fcc1ba 100644 --- a/sql/item.h +++ b/sql/item.h @@ -652,6 +652,7 @@ public: virtual my_decimal *val_decimal_result(my_decimal *val) { return val_decimal(val); } virtual bool val_bool_result() { return val_bool(); } + virtual bool is_null_result() { return is_null(); } /* bit map of tables used by item */ virtual table_map used_tables() const { return (table_map) 0L; } @@ -1168,6 +1169,8 @@ bool agg_item_collations(DTCollation &c, const char *name, Item **items, uint nitems, uint flags, int item_sep); bool agg_item_collations_for_comparison(DTCollation &c, const char *name, Item **items, uint nitems, uint flags); +bool agg_item_set_converter(DTCollation &coll, const char *fname, + Item **args, uint nargs, uint flags, int item_sep); bool agg_item_charsets(DTCollation &c, const char *name, Item **items, uint nitems, uint flags, int item_sep); @@ -1301,6 +1304,7 @@ public: String *str_result(String* tmp); my_decimal *val_decimal_result(my_decimal *); bool val_bool_result(); + bool is_null_result(); bool send(Protocol *protocol, String *str_arg); void reset_field(Field *f); bool fix_fields(THD *, Item **); @@ -1942,6 +1946,7 @@ public: String *str_result(String* tmp); my_decimal *val_decimal_result(my_decimal *); bool val_bool_result(); + bool is_null_result(); bool send(Protocol *prot, String *tmp); void make_field(Send_field *field); bool fix_fields(THD *, Item **); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 0410c781590..01d3e9bed52 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -490,7 +490,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols()); return 1; } - comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)); + if (comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i))) + return 1; } break; } @@ -745,11 +746,11 @@ Arg_comparator::can_compare_as_dates(Item *a, Item *b, ulonglong *const_value) obtained value */ -ulonglong +longlong get_time_value(THD *thd, Item ***item_arg, Item **cache_arg, Item *warn_item, bool *is_null) { - ulonglong value; + longlong value; Item *item= **item_arg; MYSQL_TIME ltime; @@ -761,7 +762,7 @@ get_time_value(THD *thd, Item ***item_arg, Item **cache_arg, else { *is_null= item->get_time(<ime); - value= !*is_null ? TIME_to_ulonglong_datetime(<ime) : 0; + value= !*is_null ? (longlong) TIME_to_ulonglong_datetime(<ime) : 0; } /* Do not cache GET_USER_VAR() function as its const_item() may return TRUE @@ -835,6 +836,16 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg, get_value_func= &get_time_value; return 0; } + else if (type == STRING_RESULT && + (*a)->result_type() == STRING_RESULT && + (*b)->result_type() == STRING_RESULT) + { + DTCollation coll; + coll.set((*a)->collation.collation); + if (agg_item_set_converter(coll, owner_arg->func_name(), + b, 1, MY_COLL_CMP_CONV, 1)) + return 1; + } return set_compare_func(owner_arg, type); } @@ -886,11 +897,11 @@ void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1) obtained value */ -ulonglong +longlong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, Item *warn_item, bool *is_null) { - ulonglong value= 0; + longlong value= 0; String buf, *str= 0; Item *item= **item_arg; @@ -925,7 +936,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, enum_field_types f_type= warn_item->field_type(); timestamp_type t_type= f_type == MYSQL_TYPE_DATE ? MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME; - value= get_date_from_str(thd, str, t_type, warn_item->name, &error); + value= (longlong) get_date_from_str(thd, str, t_type, warn_item->name, &error); /* If str did not contain a valid date according to the current SQL_MODE, get_date_from_str() has already thrown a warning, @@ -979,7 +990,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, int Arg_comparator::compare_datetime() { bool a_is_null, b_is_null; - ulonglong a_value, b_value; + longlong a_value, b_value; /* Get DATE/DATETIME/TIME value of the 'a' item. */ a_value= (*get_value_func)(thd, &a, &a_cache, *b, &a_is_null); @@ -1434,7 +1445,8 @@ bool Item_in_optimizer::fix_left(THD *thd, Item **ref) } not_null_tables_cache= args[0]->not_null_tables(); with_sum_func= args[0]->with_sum_func; - const_item_cache= args[0]->const_item(); + if ((const_item_cache= args[0]->const_item())) + cache->store(args[0]); return 0; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 1bd60ff37d9..db831c7030c 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -42,8 +42,8 @@ class Arg_comparator: public Sql_alloc bool is_nulls_eq; // TRUE <=> compare for the EQUAL_FUNC enum enum_date_cmp_type { CMP_DATE_DFLT= 0, CMP_DATE_WITH_DATE, CMP_DATE_WITH_STR, CMP_STR_WITH_DATE }; - ulonglong (*get_value_func)(THD *thd, Item ***item_arg, Item **cache_arg, - Item *warn_item, bool *is_null); + longlong (*get_value_func)(THD *thd, Item ***item_arg, Item **cache_arg, + Item *warn_item, bool *is_null); public: DTCollation cmp_collation; @@ -1028,7 +1028,7 @@ public: */ class cmp_item_datetime :public cmp_item { - ulonglong value; + longlong value; public: THD *thd; /* Item used for issuing warnings. */ diff --git a/sql/item_func.cc b/sql/item_func.cc index e663e1fcf83..55324923fe2 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1316,8 +1316,10 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value) void Item_func_div::result_precision() { - uint arg_prec= args[0]->decimal_precision() + prec_increment; - uint precision=min(arg_prec, DECIMAL_MAX_PRECISION); + uint precision=min(args[0]->decimal_precision() + + args[1]->decimals + prec_increment, + DECIMAL_MAX_PRECISION); + /* Integer operations keep unsigned_flag if one of arguments is unsigned */ if (result_type() == INT_RESULT) unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag; @@ -2273,7 +2275,7 @@ void Item_func_min_max::fix_length_and_dec() uint Item_func_min_max::cmp_datetimes(ulonglong *value) { - ulonglong min_max; + longlong min_max; uint min_max_idx= 0; LINT_INIT(min_max); @@ -2281,7 +2283,7 @@ uint Item_func_min_max::cmp_datetimes(ulonglong *value) { Item **arg= args + i; bool is_null; - ulonglong res= get_datetime_value(thd, &arg, 0, datetime_item, &is_null); + longlong res= get_datetime_value(thd, &arg, 0, datetime_item, &is_null); if ((null_value= args[i]->null_value)) return 0; if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0) @@ -4283,6 +4285,15 @@ my_decimal *Item_func_set_user_var::val_decimal_result(my_decimal *val) } +bool Item_func_set_user_var::is_null_result() +{ + DBUG_ASSERT(fixed == 1); + check(TRUE); + update(); // Store expression + return is_null(); +} + + void Item_func_set_user_var::print(String *str) { str->append(STRING_WITH_LEN("(@")); @@ -4950,7 +4961,10 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref) if (item->type() == Item::REF_ITEM) args[i]= item= *((Item_ref *)item)->ref; if (item->type() != Item::FIELD_ITEM) - key=NO_SUCH_KEY; + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "AGAINST"); + return TRUE; + } } /* Check that all columns come from the same table. @@ -5022,7 +5036,9 @@ bool Item_func_match::fix_index() for (keynr=0 ; keynr < table->s->keys ; keynr++) { if ((table->key_info[keynr].flags & HA_FULLTEXT) && - (table->s->keys_in_use.is_set(keynr))) + (flags & FT_BOOL ? table->keys_in_use_for_query.is_set(keynr) : + table->s->keys_in_use.is_set(keynr))) + { ft_to_key[fts]=keynr; ft_cnt[fts]=0; diff --git a/sql/item_func.h b/sql/item_func.h index 6dcf32cba07..7e15a536cf2 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -351,7 +351,10 @@ public: Item_func_unsigned(Item *a) :Item_func_signed(a) {} const char *func_name() const { return "cast_as_unsigned"; } void fix_length_and_dec() - { max_length=args[0]->max_length; unsigned_flag=1; } + { + max_length= min(args[0]->max_length, DECIMAL_MAX_PRECISION + 2); + unsigned_flag=1; + } longlong val_int(); void print(String *str); }; @@ -1299,6 +1302,7 @@ public: longlong val_int_result(); String *str_result(String *str); my_decimal *val_decimal_result(my_decimal *); + bool is_null_result(); bool update_hash(void *ptr, uint length, enum Item_result type, CHARSET_INFO *cs, Derivation dv, bool unsigned_arg); bool send(Protocol *protocol, String *str_arg); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index d1e3f45bba1..34f974042a5 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1696,6 +1696,12 @@ Item *Item_func_sysconst::safe_charset_converter(CHARSET_INFO *tocs) Item_string *conv; uint conv_errors; String tmp, cstr, *ostr= val_str(&tmp); + if (null_value) + { + Item *null_item= new Item_null((char *) fully_qualified_func_name()); + null_item->collation.set (tocs); + return null_item; + } cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &conv_errors); if (conv_errors || !(conv= new Item_static_string_func(fully_qualified_func_name(), diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 3648438a69b..23ac20a4017 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -516,8 +516,9 @@ public: { collation.set(default_charset()); uint char_length= args[0]->max_length/args[0]->collation.collation->mbmaxlen; - max_length= ((char_length + (char_length-args[0]->decimals)/3) * - collation.collation->mbmaxlen); + uint max_sep_count= char_length/3 + (decimals ? 1 : 0) + /*sign*/1; + max_length= (char_length + max_sep_count + decimals) * + collation.collation->mbmaxlen; } const char *func_name() const { return "format"; } void print(String *); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 91320d6b56b..d33d92a5238 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -370,6 +370,10 @@ Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements), args[i++]= item; } } + if (!(orig_args= (Item **) sql_alloc(sizeof(Item *) * arg_count))) + { + args= NULL; + } mark_as_sum_func(); list.empty(); // Fields are used } @@ -380,18 +384,28 @@ Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements), */ Item_sum::Item_sum(THD *thd, Item_sum *item): - Item_result_field(thd, item), arg_count(item->arg_count), + Item_result_field(thd, item), aggr_sel(item->aggr_sel), nest_level(item->nest_level), aggr_level(item->aggr_level), - quick_group(item->quick_group), used_tables_cache(item->used_tables_cache), + quick_group(item->quick_group), + arg_count(item->arg_count), orig_args(NULL), + used_tables_cache(item->used_tables_cache), forced_const(item->forced_const) { if (arg_count <= 2) + { args=tmp_args; + orig_args=tmp_orig_args; + } else + { if (!(args= (Item**) thd->alloc(sizeof(Item*)*arg_count))) return; + if (!(orig_args= (Item**) thd->alloc(sizeof(Item*)*arg_count))) + return; + } memcpy(args, item->args, sizeof(Item*)*arg_count); + memcpy(orig_args, item->orig_args, sizeof(Item*)*arg_count); } @@ -426,12 +440,13 @@ void Item_sum::make_field(Send_field *tmp_field) void Item_sum::print(String *str) { + Item **pargs= orig_args; str->append(func_name()); for (uint i=0 ; i < arg_count ; i++) { if (i) str->append(','); - args[i]->print(str); + pargs[i]->print(str); } str->append(')'); } @@ -532,6 +547,13 @@ void Item_sum::update_used_tables () } +Item *Item_sum::set_arg(int i, THD *thd, Item *new_val) +{ + thd->change_item_tree(args + i, new_val); + return new_val; +} + + String * Item_sum_num::val_str(String *str) { @@ -583,6 +605,7 @@ Item_sum_num::fix_fields(THD *thd, Item **ref) if (check_sum_func(thd, ref)) return TRUE; + memcpy (orig_args, args, sizeof (Item *) * arg_count); fixed= 1; return FALSE; } @@ -670,6 +693,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) if (check_sum_func(thd, ref)) return TRUE; + orig_args[0]= args[0]; fixed= 1; return FALSE; } @@ -3107,6 +3131,12 @@ Item_func_group_concat(Name_resolution_context *context_arg, sizeof(ORDER*)*arg_count_order))) return; + if (!(orig_args= (Item **) sql_alloc(sizeof(Item *) * arg_count))) + { + args= NULL; + return; + } + order= (ORDER**)(args + arg_count); /* fill args items of show and sort */ @@ -3334,6 +3364,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref) if (check_sum_func(thd, ref)) return TRUE; + memcpy (orig_args, args, sizeof (Item *) * arg_count); fixed= 1; return FALSE; } diff --git a/sql/item_sum.h b/sql/item_sum.h index d39fc96e254..51a1eff9bbf 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -228,10 +228,8 @@ public: VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC }; - Item **args, *tmp_args[2]; Item **ref_by; /* pointer to a ref to the object used to register it */ Item_sum *next; /* next in the circular chain of registered objects */ - uint arg_count; Item_sum *in_sum_func; /* embedding set function if any */ st_select_lex * aggr_sel; /* select where the function is aggregated */ int8 nest_level; /* number of the nesting level of the set function */ @@ -248,24 +246,32 @@ public: List<Item_field> outer_fields; protected: + uint arg_count; + Item **args, *tmp_args[2]; + /* + Copy of the arguments list to hold the original set of arguments. + Used in EXPLAIN EXTENDED instead of the current argument list because + the current argument list can be altered by usage of temporary tables. + */ + Item **orig_args, *tmp_orig_args[2]; table_map used_tables_cache; bool forced_const; public: void mark_as_sum_func(); - Item_sum() :arg_count(0), quick_group(1), forced_const(FALSE) + Item_sum() :quick_group(1), arg_count(0), forced_const(FALSE) { mark_as_sum_func(); } - Item_sum(Item *a) :args(tmp_args), arg_count(1), quick_group(1), - forced_const(FALSE) + Item_sum(Item *a) :quick_group(1), arg_count(1), args(tmp_args), + orig_args(tmp_orig_args), forced_const(FALSE) { args[0]=a; mark_as_sum_func(); } - Item_sum( Item *a, Item *b ) :args(tmp_args), arg_count(2), quick_group(1), - forced_const(FALSE) + Item_sum( Item *a, Item *b ) :quick_group(1), arg_count(2), args(tmp_args), + orig_args(tmp_orig_args), forced_const(FALSE) { args[0]=a; args[1]=b; mark_as_sum_func(); @@ -374,6 +380,10 @@ public: bool register_sum_func(THD *thd, Item **ref); st_select_lex *depended_from() { return (nest_level == aggr_level ? 0 : aggr_sel); } + + Item *get_arg(int i) { return args[i]; } + Item *set_arg(int i, THD *thd, Item *new_val); + uint get_arg_count() { return arg_count; } }; @@ -981,6 +991,7 @@ public: if (udf.fix_fields(thd, this, this->arg_count, this->args)) return TRUE; + memcpy (orig_args, args, sizeof (Item *) * arg_count); return check_sum_func(thd, ref); } enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 0cb3c963dad..38d9d62bd99 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1036,12 +1036,25 @@ longlong Item_func_month::val_int() } +void Item_func_monthname::fix_length_and_dec() +{ + THD* thd= current_thd; + CHARSET_INFO *cs= thd->variables.collation_connection; + uint32 repertoire= my_charset_repertoire(cs); + locale= thd->variables.lc_time_names; + collation.set(cs, DERIVATION_COERCIBLE, repertoire); + decimals=0; + max_length= locale->max_month_name_length * collation.collation->mbmaxlen; + maybe_null=1; +} + + String* Item_func_monthname::val_str(String* str) { DBUG_ASSERT(fixed == 1); const char *month_name; - uint month= (uint) val_int(); - THD *thd= current_thd; + uint month= (uint) val_int(); + uint err; if (null_value || !month) { @@ -1049,8 +1062,9 @@ String* Item_func_monthname::val_str(String* str) return (String*) 0; } null_value=0; - month_name= thd->variables.lc_time_names->month_names->type_names[month-1]; - str->set(month_name, strlen(month_name), system_charset_info); + month_name= locale->month_names->type_names[month-1]; + str->copy(month_name, strlen(month_name), &my_charset_utf8_bin, + collation.collation, &err); return str; } @@ -1169,19 +1183,32 @@ longlong Item_func_weekday::val_int() odbc_type) + test(odbc_type); } +void Item_func_dayname::fix_length_and_dec() +{ + THD* thd= current_thd; + CHARSET_INFO *cs= thd->variables.collation_connection; + uint32 repertoire= my_charset_repertoire(cs); + locale= thd->variables.lc_time_names; + collation.set(cs, DERIVATION_COERCIBLE, repertoire); + decimals=0; + max_length= locale->max_day_name_length * collation.collation->mbmaxlen; + maybe_null=1; +} + String* Item_func_dayname::val_str(String* str) { DBUG_ASSERT(fixed == 1); uint weekday=(uint) val_int(); // Always Item_func_daynr() const char *day_name; - THD *thd= current_thd; + uint err; if (null_value) return (String*) 0; - day_name= thd->variables.lc_time_names->day_names->type_names[weekday]; - str->set(day_name, strlen(day_name), system_charset_info); + day_name= locale->day_names->type_names[weekday]; + str->copy(day_name, strlen(day_name), &my_charset_utf8_bin, + collation.collation, &err); return str; } @@ -2550,6 +2577,8 @@ void Item_char_typecast::fix_length_and_dec() and thus avoid unnecessary character set conversion. - If the argument is not a number, then from_cs is set to the argument's charset. + + Note (TODO): we could use repertoire technique here. */ from_cs= (args[0]->result_type() == INT_RESULT || args[0]->result_type() == DECIMAL_RESULT || @@ -2557,12 +2586,13 @@ void Item_char_typecast::fix_length_and_dec() (cast_cs->mbminlen == 1 ? cast_cs : &my_charset_latin1) : args[0]->collation.collation; charset_conversion= (cast_cs->mbmaxlen > 1) || - !my_charset_same(from_cs, cast_cs) && - from_cs != &my_charset_bin && - cast_cs != &my_charset_bin; + (!my_charset_same(from_cs, cast_cs) && + from_cs != &my_charset_bin && + cast_cs != &my_charset_bin); collation.set(cast_cs, DERIVATION_IMPLICIT); - char_length= (cast_length >= 0) ? cast_length : - args[0]->max_length/from_cs->mbmaxlen; + char_length= (cast_length >= 0) ? + cast_length : + args[0]->max_length / args[0]->collation.collation->mbmaxlen; max_length= char_length * cast_cs->mbmaxlen; } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 7960c03d2e5..2c99d6044af 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -108,18 +108,13 @@ public: class Item_func_monthname :public Item_func_month { + MY_LOCALE *locale; public: Item_func_monthname(Item *a) :Item_func_month(a) {} const char *func_name() const { return "monthname"; } String *val_str(String *str); enum Item_result result_type () const { return STRING_RESULT; } - void fix_length_and_dec() - { - collation.set(&my_charset_bin); - decimals=0; - max_length=10*my_charset_bin.mbmaxlen; - maybe_null=1; - } + void fix_length_and_dec(); }; @@ -272,18 +267,13 @@ public: class Item_func_dayname :public Item_func_weekday { + MY_LOCALE *locale; public: Item_func_dayname(Item *a) :Item_func_weekday(a,0) {} const char *func_name() const { return "dayname"; } String *val_str(String *str); enum Item_result result_type () const { return STRING_RESULT; } - void fix_length_and_dec() - { - collation.set(&my_charset_bin); - decimals=0; - max_length=9*MY_CHARSET_BIN_MB_MAXLEN; - maybe_null=1; - } + void fix_length_and_dec(); }; @@ -408,6 +398,8 @@ public: { return save_time_in_field(field); } + longlong val_int() { return val_int_from_decimal(); } + bool result_as_longlong() { return TRUE; } }; diff --git a/sql/log.cc b/sql/log.cc index 5a1cfe46686..c411f7c8238 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -417,6 +417,7 @@ MYSQL_LOG::MYSQL_LOG() index_file_name[0] = 0; bzero((char*) &log_file,sizeof(log_file)); bzero((char*) &index_file, sizeof(index_file)); + bzero((char*) &purge_temp, sizeof(purge_temp)); } /* this is called only once */ @@ -1059,10 +1060,10 @@ err: IMPLEMENTATION - Protects index file with LOCK_index + - Read the next file name from the index file and store in rli->linfo - Delete relevant relay log files - Copy all file names after these ones to the front of the index file - If the OS has truncate, truncate the file, else fill it with \n' - - Read the next file name from the index file and store in rli->linfo RETURN VALUES 0 ok @@ -1076,6 +1077,7 @@ err: int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli, bool included) { int error; + char *to_purge_if_included= NULL; DBUG_ENTER("purge_first_log"); DBUG_ASSERT(is_open()); @@ -1083,36 +1085,20 @@ int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli, bool included) DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name)); pthread_mutex_lock(&LOCK_index); - pthread_mutex_lock(&rli->log_space_lock); - rli->relay_log.purge_logs(rli->group_relay_log_name, included, - 0, 0, &rli->log_space_total); - // Tell the I/O thread to take the relay_log_space_limit into account - rli->ignore_log_space_limit= 0; - pthread_mutex_unlock(&rli->log_space_lock); + to_purge_if_included= my_strdup(rli->group_relay_log_name, MYF(0)); /* - Ok to broadcast after the critical region as there is no risk of - the mutex being destroyed by this thread later - this helps save - context switches - */ - pthread_cond_broadcast(&rli->log_space_cond); - - /* Read the next log file name from the index file and pass it back to - the caller - If included is true, we want the first relay log; - otherwise we want the one after event_relay_log_name. + the caller. */ - if ((included && (error=find_log_pos(&rli->linfo, NullS, 0))) || - (!included && - ((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)) || - (error=find_next_log(&rli->linfo, 0))))) + if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)) || + (error=find_next_log(&rli->linfo, 0))) { char buff[22]; sql_print_error("next log error: %d offset: %s log: %s included: %d", error, llstr(rli->linfo.index_file_offset,buff), - rli->group_relay_log_name, + rli->event_relay_log_name, included); goto err; } @@ -1140,7 +1126,42 @@ int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli, bool included) /* Store where we are in the new file for the execution thread */ flush_relay_log_info(rli); + DBUG_EXECUTE_IF("crash_before_purge_logs", abort();); + + pthread_mutex_lock(&rli->log_space_lock); + rli->relay_log.purge_logs(to_purge_if_included, included, + 0, 0, &rli->log_space_total); + // Tell the I/O thread to take the relay_log_space_limit into account + rli->ignore_log_space_limit= 0; + pthread_mutex_unlock(&rli->log_space_lock); + + /* + Ok to broadcast after the critical region as there is no risk of + the mutex being destroyed by this thread later - this helps save + context switches + */ + pthread_cond_broadcast(&rli->log_space_cond); + + /* + * Need to update the log pos because purge logs has been called + * after fetching initially the log pos at the begining of the method. + */ + if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0))) + { + char buff[22]; + sql_print_error("next log error: %d offset: %s log: %s included: %d", + error, + llstr(rli->linfo.index_file_offset,buff), + rli->group_relay_log_name, + included); + goto err; + } + + /* If included was passed, rli->linfo should be the first entry. */ + DBUG_ASSERT(!included || rli->linfo.index_file_start_offset == 0); + err: + my_free(to_purge_if_included, MYF(0)); pthread_mutex_unlock(&LOCK_index); DBUG_RETURN(error); } @@ -1199,8 +1220,36 @@ int MYSQL_LOG::purge_logs(const char *to_log, if (need_mutex) pthread_mutex_lock(&LOCK_index); - if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/))) + if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/))) + { + sql_print_error("MYSQL_LOG::purge_logs was called with file %s not " + "listed in the index.", to_log); goto err; + } + + /* + For crash recovery reasons the index needs to be updated before + any files are deleted. Move files to be deleted into a temp file + to be processed after the index is updated. + */ + if (!my_b_inited(&purge_temp)) + { + if ((error=open_cached_file(&purge_temp, mysql_tmpdir, TEMP_PREFIX, + DISK_BUFFER_SIZE, MYF(MY_WME)))) + { + sql_print_error("MYSQL_LOG::purge_logs failed to open purge_temp"); + goto err; + } + } + else + { + if ((error=reinit_io_cache(&purge_temp, WRITE_CACHE, 0, 0, 1))) + { + sql_print_error("MYSQL_LOG::purge_logs failed to reinit purge_temp " + "for write"); + goto err; + } + } /* File name exists in index file; delete until we find this file @@ -1211,6 +1260,59 @@ int MYSQL_LOG::purge_logs(const char *to_log, while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) && !log_in_use(log_info.log_file_name)) { + if ((error=my_b_write(&purge_temp, (byte*)log_info.log_file_name, + strlen(log_info.log_file_name))) || + (error=my_b_write(&purge_temp, (byte*)"\n", 1))) + { + sql_print_error("MYSQL_LOG::purge_logs failed to copy %s to purge_temp", + log_info.log_file_name); + goto err; + } + + if (find_next_log(&log_info, 0) || exit_loop) + break; + } + + /* We know how many files to delete. Update index file. */ + if ((error=update_log_index(&log_info, need_update_threads))) + { + sql_print_error("MSYQL_LOG::purge_logs failed to update the index file"); + goto err; + } + + DBUG_EXECUTE_IF("crash_after_update_index", abort();); + + /* Switch purge_temp for read. */ + if ((error=reinit_io_cache(&purge_temp, READ_CACHE, 0, 0, 0))) + { + sql_print_error("MSYQL_LOG::purge_logs failed to reinit purge_temp " + "for read"); + goto err; + } + + /* Read each entry from purge_temp and delete the file. */ + for (;;) + { + uint length; + + if ((length=my_b_gets(&purge_temp, log_info.log_file_name, + FN_REFLEN)) <= 1) + { + if (purge_temp.error) + { + error= purge_temp.error; + sql_print_error("MSYQL_LOG::purge_logs error %d reading from " + "purge_temp", error); + goto err; + } + + /* Reached EOF */ + break; + } + + /* Get rid of the trailing '\n' */ + log_info.log_file_name[length-1]= 0; + MY_STAT s; if (!my_stat(log_info.log_file_name, &s, MYF(0))) { @@ -1304,17 +1406,10 @@ int MYSQL_LOG::purge_logs(const char *to_log, } } } - if (find_next_log(&log_info, 0) || exit_loop) - break; } - - /* - If we get killed -9 here, the sysadmin would have to edit - the log index file after restart - otherwise, this should be safe - */ - error= update_log_index(&log_info, need_update_threads); err: + close_cached_file(&purge_temp); if (need_mutex) pthread_mutex_unlock(&LOCK_index); DBUG_RETURN(error); @@ -1326,7 +1421,6 @@ err: SYNOPSIS purge_logs_before_date() - thd Thread pointer before_date Delete all log files before given date. NOTES @@ -1343,6 +1437,7 @@ err: int MYSQL_LOG::purge_logs_before_date(time_t purge_time) { int error; + char to_log[FN_REFLEN]; LOG_INFO log_info; MY_STAT stat_area; THD *thd= current_thd; @@ -1350,12 +1445,8 @@ int MYSQL_LOG::purge_logs_before_date(time_t purge_time) DBUG_ENTER("purge_logs_before_date"); pthread_mutex_lock(&LOCK_index); + to_log[0]= 0; - /* - Delete until we find curren file - or a file that is used or a file - that is older than purge_time. - */ if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/))) goto err; @@ -1405,54 +1496,18 @@ int MYSQL_LOG::purge_logs_before_date(time_t purge_time) } else { - if (stat_area.st_mtime >= purge_time) + if (stat_area.st_mtime < purge_time) + strmake(to_log, + log_info.log_file_name, + sizeof(log_info.log_file_name)); + else break; - if (my_delete(log_info.log_file_name, MYF(0))) - { - if (my_errno == ENOENT) - { - /* It's not fatal even if we can't delete a log file */ - if (thd) - { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), - log_info.log_file_name); - } - sql_print_information("Failed to delete file '%s'", - log_info.log_file_name); - my_errno= 0; - } - else - { - if (thd) - { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, - ER_BINLOG_PURGE_FATAL_ERR, - "a problem with deleting %s; " - "consider examining correspondence " - "of your binlog index file " - "to the actual binlog files", - log_info.log_file_name); - } - else - { - sql_print_information("Failed to delete log file '%s'", - log_info.log_file_name); - } - error= LOG_INFO_FATAL; - goto err; - } - } } if (find_next_log(&log_info, 0)) break; } - /* - If we get killed -9 here, the sysadmin would have to edit - the log index file after restart - otherwise, this should be safe - */ - error= update_log_index(&log_info, 1); + error= (to_log[0] ? purge_logs(to_log, 1, 0, 1, (ulonglong *) 0) : 0); err: pthread_mutex_unlock(&LOCK_index); diff --git a/sql/log_event.cc b/sql/log_event.cc index ef419aaee40..ba282fd8e59 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -976,7 +976,7 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) fputc('#', file); print_timestamp(file); - fprintf(file, " server id %d end_log_pos %s ", server_id, + fprintf(file, " server id %lu end_log_pos %s ", (ulong) server_id, llstr(log_pos,llbuff)); /* mysqlbinlog --hexdump */ @@ -1117,6 +1117,11 @@ void Query_log_event::pack_info(Protocol *protocol) static void write_str_with_code_and_len(char **dst, const char *src, int len, uint code) { + /* + only 1 byte to store the length of catalog, so it should not + surpass 255 + */ + DBUG_ASSERT(len <= 255); DBUG_ASSERT(src); *((*dst)++)= code; *((*dst)++)= (uchar) len; @@ -1136,16 +1141,8 @@ static void write_str_with_code_and_len(char **dst, const char *src, bool Query_log_event::write(IO_CACHE* file) { - uchar buf[QUERY_HEADER_LEN+ - 1+4+ // code of flags2 and flags2 - 1+8+ // code of sql_mode and sql_mode - 1+1+FN_REFLEN+ // code of catalog and catalog length and catalog - 1+4+ // code of autoinc and the 2 autoinc variables - 1+6+ // code of charset and charset - 1+1+MAX_TIME_ZONE_NAME_LENGTH+ // code of tz and tz length and tz name - 1+2+ // code of lc_time_names and lc_time_names_number - 1+2 // code of charset_database and charset_database_number - ], *start, *start_of_status; + uchar buf[QUERY_HEADER_LEN + MAX_SIZE_LOG_EVENT_STATUS]; + uchar *start, *start_of_status; ulong event_length; if (!query) @@ -1251,10 +1248,8 @@ bool Query_log_event::write(IO_CACHE* file) { /* In the TZ sys table, column Name is of length 64 so this should be ok */ DBUG_ASSERT(time_zone_len <= MAX_TIME_ZONE_NAME_LENGTH); - *start++= Q_TIME_ZONE_CODE; - *start++= time_zone_len; - memcpy(start, time_zone_str, time_zone_len); - start+= time_zone_len; + write_str_with_code_and_len((char **)(&start), + time_zone_str, time_zone_len, Q_TIME_ZONE_CODE); } if (lc_time_names_number) { @@ -1270,7 +1265,17 @@ bool Query_log_event::write(IO_CACHE* file) int2store(start, charset_database_number); start+= 2; } + if (table_map_for_update) + { + *start++= Q_TABLE_MAP_FOR_UPDATE_CODE; + int8store(start, table_map_for_update); + start+= 8; + } /* + 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. + Here there could be code like if (command-line-option-which-says-"log_this_variable" && inited) { @@ -1348,7 +1353,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, auto_increment_increment(thd_arg->variables.auto_increment_increment), auto_increment_offset(thd_arg->variables.auto_increment_offset), lc_time_names_number(thd_arg->variables.lc_time_names->number), - charset_database_number(0) + charset_database_number(0), + table_map_for_update((ulonglong)thd_arg->table_map_for_update) { time_t end_time; @@ -1471,6 +1477,7 @@ code_name(int code) case Q_CATALOG_NZ_CODE: return "Q_CATALOG_NZ_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"; } sprintf(buf, "CODE#%d", code); return buf; @@ -1507,7 +1514,8 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, db(NullS), catalog_len(0), status_vars_len(0), 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) + time_zone_len(0), lc_time_names_number(0), charset_database_number(0), + table_map_for_update(0) { ulong data_len; uint32 tmp; @@ -1649,6 +1657,11 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, charset_database_number= uint2korr(pos); pos+= 2; break; + case Q_TABLE_MAP_FOR_UPDATE_CODE: + CHECK_SPACE(pos, end, 8); + table_map_for_update= uint8korr(pos); + pos+= 8; + 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\ @@ -2036,6 +2049,8 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli, else thd->variables.collation_database= thd->db_charset; + thd->table_map_for_update= (table_map)table_map_for_update; + /* Execute the query (note that we bypass dispatch_command()) */ const char* found_semicolon= NULL; mysql_parse(thd, thd->query, thd->query_length, &found_semicolon); diff --git a/sql/log_event.h b/sql/log_event.h index 5b065a33dd1..6ccbf8e4d5c 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -204,12 +204,15 @@ struct sql_ex_info packet (i.e. a query) sent from client to master; First, an auxiliary log_event status vars estimation: */ -#define MAX_SIZE_LOG_EVENT_STATUS (4 /* flags2 */ + \ - 8 /* sql mode */ + \ - 1 + 1 + 255 /* catalog */ + \ - 4 /* autoinc */ + \ - 6 /* charset */ + \ - MAX_TIME_ZONE_NAME_LENGTH) +#define MAX_SIZE_LOG_EVENT_STATUS (1 + 4 /* type, flags2 */ + \ + 1 + 8 /* type, sql_mode */ + \ + 1 + 1 + 255 /* type, length, catalog */ + \ + 1 + 4 /* type, auto_increment */ + \ + 1 + 6 /* type, charset */ + \ + 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 */) #define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \ LOG_EVENT_HEADER_LEN + /* write_header */ \ QUERY_HEADER_LEN + /* write_data */ \ @@ -273,6 +276,8 @@ struct sql_ex_info #define Q_LC_TIME_NAMES_CODE 7 #define Q_CHARSET_DATABASE_CODE 8 + +#define Q_TABLE_MAP_FOR_UPDATE_CODE 9 /* Intvar event post-header */ #define I_TYPE_OFFSET 0 @@ -800,6 +805,11 @@ public: const char *time_zone_str; uint lc_time_names_number; /* 0 means en_US */ uint charset_database_number; + /* + map for tables that will be updated for a multi-table update query + statement, for other query statements, this will be zero. + */ + ulonglong table_map_for_update; #ifndef MYSQL_CLIENT diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index 31a5b09370a..a235edbd73c 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -216,7 +216,7 @@ my_decimal *date2my_decimal(MYSQL_TIME *ltime, my_decimal *dec) date = (ltime->year*100L + ltime->month)*100L + ltime->day; if (ltime->time_type > MYSQL_TIMESTAMP_DATE) date= ((date*100L + ltime->hour)*100L+ ltime->minute)*100L + ltime->second; - if (int2my_decimal(E_DEC_FATAL_ERROR, date, FALSE, dec)) + if (int2my_decimal(E_DEC_FATAL_ERROR, ltime->neg ? -date : date, FALSE, dec)) return dec; if (ltime->second_part) { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 1568f042b7e..b855af9a8d3 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -132,15 +132,20 @@ typedef struct my_locale_st TYPELIB *ab_month_names; TYPELIB *day_names; TYPELIB *ab_day_names; + uint max_month_name_length; + uint max_day_name_length; #ifdef __cplusplus my_locale_st(uint number_par, const char *name_par, const char *descr_par, bool is_ascii_par, TYPELIB *month_names_par, TYPELIB *ab_month_names_par, - TYPELIB *day_names_par, TYPELIB *ab_day_names_par) : + TYPELIB *day_names_par, TYPELIB *ab_day_names_par, + uint max_month_name_length_par, uint max_day_name_length_par) : number(number_par), name(name_par), description(descr_par), is_ascii(is_ascii_par), month_names(month_names_par), ab_month_names(ab_month_names_par), - day_names(day_names_par), ab_day_names(ab_day_names_par) + day_names(day_names_par), ab_day_names(ab_day_names_par), + max_month_name_length(max_month_name_length_par), + max_day_name_length(max_day_name_length_par) {} #endif } MY_LOCALE; @@ -435,6 +440,7 @@ MY_LOCALE *my_locale_by_number(uint number); #define UNCACHEABLE_PREPARE 16 /* For uncorrelated SELECT in an UNION with some correlated SELECTs */ #define UNCACHEABLE_UNITED 32 +#define UNCACHEABLE_CHECKOPTION 64 /* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */ #define UNDEF_POS (-1) @@ -645,6 +651,8 @@ struct Query_cache_query_flags unsigned int client_long_flag:1; unsigned int client_protocol_41:1; unsigned int more_results_exists:1; + unsigned int in_trans:1; + unsigned int autocommit:1; unsigned int pkt_nr; uint character_set_client_num; uint character_set_results_num; @@ -977,6 +985,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond); 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); +bool schema_table_store_record(THD *thd, TABLE *table); #define is_schema_db(X) \ !my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str, (X)) @@ -1556,8 +1565,8 @@ void make_date(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time, String *str); void make_time(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time, String *str); -ulonglong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, - Item *warn_item, bool *is_null); +longlong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, + Item *warn_item, bool *is_null); int test_if_number(char *str,int *res,bool allow_wildcards); void change_byte(byte *,uint,char,char); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c3e5449b22b..fcde4e2b626 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -186,39 +186,41 @@ int initgroups(const char *,unsigned int); #ifdef HAVE_FP_EXCEPT // Fix type conflict typedef fp_except fp_except_t; #endif +#endif /* __FreeBSD__ && HAVE_IEEEFP_H */ +#ifdef HAVE_SYS_FPU_H +/* for IRIX to use set_fpc_csr() */ +#include <sys/fpu.h> +#endif +inline void setup_fpu() +{ +#if defined(__FreeBSD__) && defined(HAVE_IEEEFP_H) /* We can't handle floating point exceptions with threads, so disable this on freebsd + Don't fall for overflow, underflow,divide-by-zero or loss of precision */ - -inline void set_proper_floating_point_mode() -{ - /* Don't fall for overflow, underflow,divide-by-zero or loss of precision */ #if defined(__i386__) fpsetmask(~(FP_X_INV | FP_X_DNML | FP_X_OFL | FP_X_UFL | FP_X_DZ | FP_X_IMP)); #else - fpsetmask(~(FP_X_INV | FP_X_OFL | FP_X_UFL | FP_X_DZ | - FP_X_IMP)); -#endif -} -#elif defined(__sgi) -/* for IRIX to use set_fpc_csr() */ -#include <sys/fpu.h> + fpsetmask(~(FP_X_INV | FP_X_OFL | FP_X_UFL | FP_X_DZ | + FP_X_IMP)); +#endif /* __i386__ */ +#endif /* __FreeBSD__ && HAVE_IEEEFP_H */ -inline void set_proper_floating_point_mode() -{ +#ifdef HAVE_FESETROUND + /* Set FPU rounding mode to "round-to-nearest" */ + fesetround(FE_TONEAREST); +#endif /* HAVE_FESETROUND */ + +#if defined(__sgi) && defined(HAVE_SYS_FPU_H) /* Enable denormalized DOUBLE values support for IRIX */ - { - union fpc_csr n; - n.fc_word = get_fpc_csr(); - n.fc_struct.flush = 0; - set_fpc_csr(n.fc_word); - } + union fpc_csr n; + n.fc_word = get_fpc_csr(); + n.fc_struct.flush = 0; + set_fpc_csr(n.fc_word); +#endif } -#else -#define set_proper_floating_point_mode() -#endif /* __FreeBSD__ && HAVE_IEEEFP_H */ } /* cplusplus */ @@ -3035,12 +3037,14 @@ static int init_common_variables(const char *conf_file_name, int argc, sys_init_connect.value_length= strlen(opt_init_connect); else sys_init_connect.value=my_strdup("",MYF(0)); + sys_init_connect.is_os_charset= TRUE; sys_init_slave.value_length= 0; if ((sys_init_slave.value= opt_init_slave)) sys_init_slave.value_length= strlen(opt_init_slave); else sys_init_slave.value=my_strdup("",MYF(0)); + sys_init_slave.is_os_charset= TRUE; if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1)) return 1; @@ -3277,7 +3281,7 @@ static int init_server_components() query_cache_init(); query_cache_resize(query_cache_size); randominit(&sql_rand,(ulong) server_start_time,(ulong) server_start_time/2); - set_proper_floating_point_mode(); + setup_fpu(); init_thr_lock(); #ifdef HAVE_REPLICATION init_slave_list(); @@ -3615,6 +3619,44 @@ void decrement_handler_count() #ifndef EMBEDDED_LIBRARY +#ifndef DBUG_OFF +/* + Debugging helper function to keep the locale database + (see sql_locale.cc) and max_month_name_length and + max_day_name_length variable values in consistent state. +*/ +static void test_lc_time_sz() +{ + DBUG_ENTER("test_lc_time_sz"); + for (MY_LOCALE **loc= my_locales; *loc; loc++) + { + uint max_month_len= 0; + uint max_day_len = 0; + for (const char **month= (*loc)->month_names->type_names; *month; month++) + { + set_if_bigger(max_month_len, + my_numchars_mb(&my_charset_utf8_general_ci, + *month, *month + strlen(*month))); + } + for (const char **day= (*loc)->day_names->type_names; *day; day++) + { + set_if_bigger(max_day_len, + my_numchars_mb(&my_charset_utf8_general_ci, + *day, *day + strlen(*day))); + } + if ((*loc)->max_month_name_length != max_month_len || + (*loc)->max_day_name_length != max_day_len) + { + DBUG_PRINT("Wrong max day name(or month name) length for locale:", + ("%s", (*loc)->name)); + DBUG_ASSERT(0); + } + } + DBUG_VOID_RETURN; +} +#endif//DBUG_OFF + + #ifdef __WIN__ int win_main(int argc, char **argv) #else @@ -3710,6 +3752,10 @@ int main(int argc, char **argv) openlog(libwrapName, LOG_PID, LOG_AUTH); #endif +#ifndef DBUG_OFF + test_lc_time_sz(); +#endif + /* We have enough space for fiddling with the argv, continue */ @@ -3840,6 +3886,9 @@ we force server id to 2, but this MySQL server will not act as a slave."); : mysqld_unix_port), mysqld_port, MYSQL_COMPILATION_COMMENT); +#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY) + Service.SetRunning(); +#endif #if defined(__NT__) || defined(HAVE_SMEM) handle_connections_methods(); @@ -6573,6 +6622,7 @@ struct show_var_st status_vars[]= { {"Qcache_queries_in_cache", (char*) &query_cache.queries_in_cache, SHOW_LONG_CONST}, {"Qcache_total_blocks", (char*) &query_cache.total_blocks, SHOW_LONG_CONST}, #endif /*HAVE_QUERY_CACHE*/ + {"Queries", (char*) 0, SHOW_QUERIES}, {"Questions", (char*) offsetof(STATUS_VAR, questions), SHOW_LONG_STATUS}, diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc index a04f284a3de..e570898f373 100644 --- a/sql/nt_servc.cc +++ b/sql/nt_servc.cc @@ -245,10 +245,6 @@ void NTService::ServiceMain(DWORD argc, LPTSTR *argv) if (!pService->StartService()) goto error; - // Check that the service is now running. - if (!pService->SetStatus(SERVICE_RUNNING,NO_ERROR, 0, 0, 0)) - goto error; - // wait for exit event WaitForSingleObject (pService->hExitEvent, INFINITE); @@ -264,6 +260,14 @@ error: return; } + +void NTService::SetRunning() +{ + if (pService) + pService->SetStatus(SERVICE_RUNNING,NO_ERROR, 0, 0, 0); +} + + /* ------------------------------------------------------------------------ StartService() - starts the appliaction thread -------------------------------------------------------------------------- */ diff --git a/sql/nt_servc.h b/sql/nt_servc.h index a3c12569114..9b689e434e1 100644 --- a/sql/nt_servc.h +++ b/sql/nt_servc.h @@ -56,7 +56,19 @@ class NTService BOOL IsService(LPCSTR ServiceName); BOOL got_service_option(char **argv, char *service_option); BOOL is_super_user(); - void Stop(void); //to be called from app. to stop service + + /* + SetRunning() is to be called by the application + when initialization completes and it can accept + stop request + */ + void SetRunning(void); + + /* + Stop() is to be called by the application to stop + the service + */ + void Stop(void); protected: LPSTR ServiceName; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 204ebdb6f33..018fc8a9d44 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1109,6 +1109,9 @@ QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT() quick->file= NULL; quick_selects.delete_elements(); delete pk_quick_select; + /* It's ok to call the next two even if they are already deinitialized */ + end_read_record(&read_record); + free_io_cache(head); free_root(&alloc,MYF(0)); DBUG_VOID_RETURN; } @@ -7735,7 +7738,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) DBUG_RETURN(NULL); /* The argument of MIN/MAX. */ - Item *expr= min_max_item->args[0]->real_item(); + Item *expr= min_max_item->get_arg(0)->real_item(); if (expr->type() == Item::FIELD_ITEM) /* Is it an attribute? */ { if (! min_max_arg_item) @@ -7772,32 +7775,37 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) */ KEY *cur_index_info= table->key_info; KEY *cur_index_info_end= cur_index_info + table->s->keys; - KEY_PART_INFO *cur_part= NULL; - KEY_PART_INFO *end_part; /* Last part for loops. */ - /* Last index part. */ - KEY_PART_INFO *last_part= NULL; - KEY_PART_INFO *first_non_group_part= NULL; - KEY_PART_INFO *first_non_infix_part= NULL; - uint key_infix_parts= 0; - uint cur_group_key_parts= 0; - uint cur_group_prefix_len= 0; /* Cost-related variables for the best index so far. */ double best_read_cost= DBL_MAX; ha_rows best_records= 0; SEL_ARG *best_index_tree= NULL; ha_rows best_quick_prefix_records= 0; uint best_param_idx= 0; - double cur_read_cost= DBL_MAX; - ha_rows cur_records; + + const uint pk= param->table->s->primary_key; SEL_ARG *cur_index_tree= NULL; ha_rows cur_quick_prefix_records= 0; uint cur_param_idx=MAX_KEY; - key_map cur_used_key_parts; - uint pk= param->table->s->primary_key; for (uint cur_index= 0 ; cur_index_info != cur_index_info_end ; cur_index_info++, cur_index++) { + KEY_PART_INFO *cur_part; + KEY_PART_INFO *end_part; /* Last part for loops. */ + /* Last index part. */ + KEY_PART_INFO *last_part; + KEY_PART_INFO *first_non_group_part; + KEY_PART_INFO *first_non_infix_part; + uint key_infix_parts; + uint cur_group_key_parts= 0; + uint cur_group_prefix_len= 0; + double cur_read_cost; + ha_rows cur_records; + key_map used_key_parts_map; + uint cur_key_infix_len= 0; + byte cur_key_infix[MAX_KEY_LENGTH]; + uint cur_used_key_parts; + /* Check (B1) - if current index is covering. */ if (!table->used_keys.is_set(cur_index)) goto next_index; @@ -7876,7 +7884,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) else if (join->select_distinct) { select_items_it.rewind(); - cur_used_key_parts.clear_all(); + used_key_parts_map.clear_all(); uint max_key_part= 0; while ((item= select_items_it++)) { @@ -7887,13 +7895,13 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) Check if this attribute was already present in the select list. If it was present, then its corresponding key part was alredy used. */ - if (cur_used_key_parts.is_set(key_part_nr)) + if (used_key_parts_map.is_set(key_part_nr)) continue; if (key_part_nr < 1 || key_part_nr > join->fields_list.elements) goto next_index; cur_part= cur_index_info->key_part + key_part_nr - 1; cur_group_prefix_len+= cur_part->store_length; - cur_used_key_parts.set_bit(key_part_nr); + used_key_parts_map.set_bit(key_part_nr); ++cur_group_key_parts; max_key_part= max(max_key_part,key_part_nr); } @@ -7905,7 +7913,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) */ ulonglong all_parts, cur_parts; all_parts= (1<<max_key_part) - 1; - cur_parts= cur_used_key_parts.to_ulonglong() >> 1; + cur_parts= used_key_parts_map.to_ulonglong() >> 1; if (all_parts != cur_parts) goto next_index; } @@ -7955,7 +7963,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) &dummy); if (!get_constant_key_infix(cur_index_info, index_range_tree, first_non_group_part, min_max_arg_part, - last_part, thd, key_infix, &key_infix_len, + last_part, thd, cur_key_infix, + &cur_key_infix_len, &first_non_infix_part)) goto next_index; } @@ -8007,9 +8016,9 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) } /* If we got to this point, cur_index_info passes the test. */ - key_infix_parts= key_infix_len ? + key_infix_parts= cur_key_infix_len ? (first_non_infix_part - first_non_group_part) : 0; - used_key_parts= cur_group_key_parts + key_infix_parts; + cur_used_key_parts= cur_group_key_parts + key_infix_parts; /* Compute the cost of using this index. */ if (tree) @@ -8021,7 +8030,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) cur_quick_prefix_records= check_quick_select(param, cur_param_idx, cur_index_tree); } - cost_group_min_max(table, cur_index_info, used_key_parts, + cost_group_min_max(table, cur_index_info, cur_used_key_parts, cur_group_key_parts, tree, cur_index_tree, cur_quick_prefix_records, have_min, have_max, &cur_read_cost, &cur_records); @@ -8032,7 +8041,6 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) */ if (cur_read_cost < best_read_cost - (DBL_EPSILON * cur_read_cost)) { - DBUG_ASSERT(tree != 0 || cur_param_idx == MAX_KEY); index_info= cur_index_info; index= cur_index; best_read_cost= cur_read_cost; @@ -8042,11 +8050,13 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) best_param_idx= cur_param_idx; group_key_parts= cur_group_key_parts; group_prefix_len= cur_group_prefix_len; + key_infix_len= cur_key_infix_len; + if (key_infix_len) + memcpy (key_infix, cur_key_infix, sizeof (key_infix)); + used_key_parts= cur_used_key_parts; } - next_index: - cur_group_key_parts= 0; - cur_group_prefix_len= 0; + next_index:; } if (!index_info) /* No usable index found. */ DBUG_RETURN(NULL); diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 3fc62d05ae5..39db1344588 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -160,7 +160,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) to the number of rows in the tables if this number is exact and there are no outer joins. */ - if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null && + if (!conds && !((Item_sum_count*) item)->get_arg(0)->maybe_null && !outer_tables && is_exact_count) { ((Item_sum_count*) item)->make_const(count); @@ -176,7 +176,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) parts of the key is found in the COND, then we can use indexes to find the key. */ - Item *expr=item_sum->args[0]; + Item *expr=item_sum->get_arg(0); if (expr->real_item()->type() == Item::FIELD_ITEM) { byte key_buff[MAX_KEY_LENGTH]; @@ -319,7 +319,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) parts of the key is found in the COND, then we can use indexes to find the key. */ - Item *expr=item_sum->args[0]; + Item *expr=item_sum->get_arg(0); if (expr->real_item()->type() == Item::FIELD_ITEM) { byte key_buff[MAX_KEY_LENGTH]; diff --git a/sql/parse_file.cc b/sql/parse_file.cc index 2b947fcac4f..c4b07ed9dac 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -88,7 +88,6 @@ write_escaped_string(IO_CACHE *file, LEX_STRING *val_s) file pointer to IO_CACHE structure for writing base pointer to data structure parameter pointer to parameter descriptor - old_version for returning back old version number value RETURN FALSE - OK @@ -96,8 +95,7 @@ write_escaped_string(IO_CACHE *file, LEX_STRING *val_s) */ static my_bool -write_parameter(IO_CACHE *file, gptr base, File_option *parameter, - ulonglong *old_version) +write_parameter(IO_CACHE *file, gptr base, File_option *parameter) { char num_buf[20]; // buffer for numeric operations // string for numeric operations @@ -125,15 +123,6 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter, DBUG_RETURN(TRUE); break; } - case FILE_OPTIONS_REV: - { - ulonglong *val_i= (ulonglong *)(base + parameter->offset); - *old_version= (*val_i)++; - num.set(*val_i, &my_charset_bin); - if (my_b_append(file, (const byte *)num.ptr(), num.length())) - DBUG_RETURN(TRUE); - break; - } case FILE_OPTIONS_TIMESTAMP: { /* string have to be allocated already */ @@ -205,7 +194,6 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter, base base address for parameter reading (structure like TABLE) parameters parameters description - max_versions number of versions to save RETURN FALSE - OK @@ -215,13 +203,11 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter, my_bool sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, const LEX_STRING *type, - gptr base, File_option *parameters, - uint max_versions) + gptr base, File_option *parameters) { File handler; IO_CACHE file; char path[FN_REFLEN+1]; // +1 to put temporary file name for sure - ulonglong old_version= ULONGLONG_MAX; int path_end; File_option *param; DBUG_ENTER("sql_create_definition_file"); @@ -255,7 +241,7 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, if (my_b_append(&file, (const byte *)param->name.str, param->name.length) || my_b_append(&file, (const byte *)STRING_WITH_LEN("=")) || - write_parameter(&file, base, param, &old_version) || + write_parameter(&file, base, param) || my_b_append(&file, (const byte *)STRING_WITH_LEN("\n"))) goto err_w_cache; } @@ -263,61 +249,17 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, if (end_io_cache(&file)) goto err_w_file; + if (opt_sync_frm) { + if (my_sync(handler, MYF(MY_WME))) + goto err_w_file; + } + if (my_close(handler, MYF(MY_WME))) { DBUG_RETURN(TRUE); } path[path_end]='\0'; -#ifdef FRM_ARCHIVE - // archive copies management: disabled unused feature (see bug #17823). - if (!access(path, F_OK)) - { - if (old_version != ULONGLONG_MAX && max_versions != 0) - { - // save backup - char path_arc[FN_REFLEN]; - // backup old version - char path_to[FN_REFLEN]; - - // check archive directory existence - fn_format(path_arc, "arc", dir->str, "", MY_UNPACK_FILENAME); - if (access(path_arc, F_OK)) - { - if (my_mkdir(path_arc, 0777, MYF(MY_WME))) - { - DBUG_RETURN(TRUE); - } - } - - my_snprintf(path_to, FN_REFLEN, "%s/%s-%04lu", - path_arc, file_name->str, (ulong) old_version); - if (my_rename(path, path_to, MYF(MY_WME))) - { - DBUG_RETURN(TRUE); - } - - // remove very old version - if (old_version > max_versions) - { - my_snprintf(path_to, FN_REFLEN, "%s/%s-%04lu", - path_arc, file_name->str, - (ulong)(old_version - max_versions)); - if (!access(path_arc, F_OK) && my_delete(path_to, MYF(MY_WME))) - { - DBUG_RETURN(TRUE); - } - } - } - else - { - if (my_delete(path, MYF(MY_WME))) // no backups - { - DBUG_RETURN(TRUE); - } - } - } -#endif//FRM_ARCHIVE { // rename temporary file @@ -346,8 +288,6 @@ err_w_file: schema name of given schema old_name original file name new_name new file name - revision revision number - num_view_backups number of backups RETURN 0 - OK @@ -356,8 +296,7 @@ err_w_file: */ my_bool rename_in_schema_file(THD *thd, const char *schema, const char *old_name, - const char *new_name, ulonglong revision, - uint num_view_backups) + const char *new_name) { char old_path[FN_REFLEN], new_path[FN_REFLEN], arc_path[FN_REFLEN]; @@ -376,23 +315,6 @@ my_bool rename_in_schema_file(THD *thd, strxnmov(arc_path, FN_REFLEN, mysql_data_home, "/", schema, "/arc", NullS); (void) unpack_filename(arc_path, arc_path); -#ifdef FRM_ARCHIVE - if (revision > 0 && !access(arc_path, F_OK)) - { - ulonglong limit= ((revision > num_view_backups) ? - revision - num_view_backups : 0); - for (; revision > limit ; revision--) - { - my_snprintf(old_path, FN_REFLEN, "%s/%s%s-%04lu", - arc_path, old_name, reg_ext, (ulong)revision); - (void) unpack_filename(old_path, old_path); - my_snprintf(new_path, FN_REFLEN, "%s/%s%s-%04lu", - arc_path, new_name, reg_ext, (ulong)revision); - (void) unpack_filename(new_path, new_path); - my_rename(old_path, new_path, MYF(0)); - } - } -#else//FRM_ARCHIVE { // remove obsolete 'arc' directory and files if any MY_DIR *new_dirp; if ((new_dirp = my_dir(arc_path, MYF(MY_DONT_SORT)))) @@ -401,7 +323,6 @@ my_bool rename_in_schema_file(THD *thd, (void) mysql_rm_arc_files(thd, new_dirp, arc_path); } } -#endif//FRM_ARCHIVE return 0; } @@ -838,7 +759,6 @@ File_parser::parse(gptr base, MEM_ROOT *mem_root, break; } case FILE_OPTIONS_ULONGLONG: - case FILE_OPTIONS_REV: if (!(eol= strchr(ptr, '\n'))) { my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), diff --git a/sql/parse_file.h b/sql/parse_file.h index ec920b58667..ad7d1629e0a 100644 --- a/sql/parse_file.h +++ b/sql/parse_file.h @@ -23,7 +23,6 @@ enum file_opt_type { FILE_OPTIONS_STRING, /* String (LEX_STRING) */ FILE_OPTIONS_ESTRING, /* Escaped string (LEX_STRING) */ FILE_OPTIONS_ULONGLONG, /* ulonglong parameter (ulonglong) */ - FILE_OPTIONS_REV, /* Revision version number (ulonglong) */ FILE_OPTIONS_TIMESTAMP, /* timestamp (LEX_STRING have to be allocated with length 20 (19+1) */ FILE_OPTIONS_STRLIST, /* list of escaped strings @@ -81,11 +80,10 @@ File_parser *sql_parse_prepare(const LEX_STRING *file_name, my_bool sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, const LEX_STRING *type, - gptr base, File_option *parameters, uint versions); + gptr base, File_option *parameters); my_bool rename_in_schema_file(THD *thd, const char *schema, const char *old_name, - const char *new_name, ulonglong revision, - uint num_view_backups); + const char *new_name); class File_parser: public Sql_alloc { diff --git a/sql/protocol.cc b/sql/protocol.cc index ff58d96f59b..2309bac88a9 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -616,7 +616,8 @@ bool Protocol::send_fields(List<Item> *list, uint flags) else { /* With conversion */ - uint max_char_len; + ulonglong max_length; + uint32 field_length; int2store(pos, thd_charset->number); /* For TEXT/BLOB columns, field_length describes the maximum data @@ -627,12 +628,21 @@ bool Protocol::send_fields(List<Item> *list, uint flags) char_count * mbmaxlen, where character count is taken from the definition of the column. In other words, the maximum number of characters here is limited by the column definition. + + When one has a LONG TEXT column with a single-byte + character set, and the connection character set is multi-byte, the + client may get fields longer than UINT_MAX32, due to + <character set column> -> <character set connection> conversion. + In that case column max length does not fit into the 4 bytes + reserved for it in the protocol. */ - max_char_len= (field.type >= (int) MYSQL_TYPE_TINY_BLOB && - field.type <= (int) MYSQL_TYPE_BLOB) ? - field.length / item->collation.collation->mbminlen : - field.length / item->collation.collation->mbmaxlen; - int4store(pos+2, max_char_len * thd_charset->mbmaxlen); + max_length= (field.type >= MYSQL_TYPE_TINY_BLOB && + field.type <= MYSQL_TYPE_BLOB) ? + field.length / item->collation.collation->mbminlen : + field.length / item->collation.collation->mbmaxlen; + max_length*= thd_charset->mbmaxlen; + field_length= (max_length > UINT_MAX32) ? UINT_MAX32 : max_length; + int4store(pos + 2, field_length); } pos[6]= field.type; int2store(pos+7,field.flags); diff --git a/sql/set_var.cc b/sql/set_var.cc index 6bc19f2e6eb..a29abe6581f 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -138,7 +138,7 @@ sys_var_thd_ulong sys_auto_increment_offset("auto_increment_offset", sys_var_bool_ptr sys_automatic_sp_privileges("automatic_sp_privileges", &sp_automatic_privileges); -sys_var_const_str sys_basedir("basedir", mysql_home); +sys_var_const_os_str sys_basedir("basedir", mysql_home); sys_var_long_ptr sys_binlog_cache_size("binlog_cache_size", &binlog_cache_size); sys_var_thd_ulong sys_bulk_insert_buff_size("bulk_insert_buffer_size", @@ -151,6 +151,8 @@ sys_var_character_set_client sys_character_set_client("character_set_client"); sys_var_character_set_connection sys_character_set_connection("character_set_connection"); sys_var_character_set_results sys_character_set_results("character_set_results"); sys_var_character_set_filesystem sys_character_set_filesystem("character_set_filesystem"); +sys_var_const_os_str sys_character_sets_dir("character_sets_dir", + mysql_charsets_dir); sys_var_thd_ulong sys_completion_type("completion_type", &SV::completion_type, check_completion_type, @@ -162,7 +164,7 @@ sys_var_long_ptr sys_concurrent_insert("concurrent_insert", &myisam_concurrent_insert); sys_var_long_ptr sys_connect_timeout("connect_timeout", &connect_timeout); -sys_var_const_str sys_datadir("datadir", mysql_real_data_home); +sys_var_const_os_str sys_datadir("datadir", mysql_real_data_home); sys_var_enum sys_delay_key_write("delay_key_write", &delay_key_write_options, &delay_key_write_typelib, @@ -311,6 +313,7 @@ sys_var_thd_ulong sys_optimizer_prune_level("optimizer_prune_level", &SV::optimizer_prune_level); sys_var_thd_ulong sys_optimizer_search_depth("optimizer_search_depth", &SV::optimizer_search_depth); +sys_var_const_os_str sys_plugin_dir("plugin_dir", opt_plugin_dir); sys_var_thd_ulong sys_preload_buff_size("preload_buffer_size", &SV::preload_buff_size); sys_var_thd_ulong sys_read_buff_size("read_buffer_size", @@ -338,7 +341,7 @@ sys_var_thd_ulong sys_query_alloc_block_size("query_alloc_block_size", sys_var_thd_ulong sys_query_prealloc_size("query_prealloc_size", &SV::query_prealloc_size, 0, fix_thd_mem_root); -sys_var_readonly sys_tmpdir("tmpdir", OPT_GLOBAL, SHOW_CHAR, get_tmpdir); +sys_var_readonly_os sys_tmpdir("tmpdir", OPT_GLOBAL, SHOW_CHAR, get_tmpdir); sys_var_thd_ulong sys_trans_alloc_block_size("transaction_alloc_block_size", &SV::trans_alloc_block_size, 0, fix_trans_mem_root); @@ -363,9 +366,11 @@ sys_var_bool_ptr sys_secure_auth("secure_auth", &opt_secure_auth); sys_var_const_str_ptr sys_secure_file_priv("secure_file_priv", &opt_secure_file_priv); sys_var_long_ptr sys_server_id("server_id", &server_id, fix_server_id); +#ifdef HAVE_REPLICATION sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol", &opt_slave_compressed_protocol); -#ifdef HAVE_REPLICATION +sys_var_const_os_str_ptr sys_slave_load_tmpdir("slave_load_tmpdir", + &slave_load_tmpdir); sys_var_long_ptr sys_slave_net_timeout("slave_net_timeout", &slave_net_timeout); sys_var_long_ptr sys_slave_trans_retries("slave_transaction_retries", @@ -380,17 +385,17 @@ sys_var_thd_sql_mode sys_sql_mode("sql_mode", #ifdef HAVE_OPENSSL extern char *opt_ssl_ca, *opt_ssl_capath, *opt_ssl_cert, *opt_ssl_cipher, *opt_ssl_key; -sys_var_const_str_ptr sys_ssl_ca("ssl_ca", &opt_ssl_ca); -sys_var_const_str_ptr sys_ssl_capath("ssl_capath", &opt_ssl_capath); -sys_var_const_str_ptr sys_ssl_cert("ssl_cert", &opt_ssl_cert); -sys_var_const_str_ptr sys_ssl_cipher("ssl_cipher", &opt_ssl_cipher); -sys_var_const_str_ptr sys_ssl_key("ssl_key", &opt_ssl_key); +sys_var_const_os_str_ptr sys_ssl_ca("ssl_ca", &opt_ssl_ca); +sys_var_const_os_str_ptr sys_ssl_capath("ssl_capath", &opt_ssl_capath); +sys_var_const_os_str_ptr sys_ssl_cert("ssl_cert", &opt_ssl_cert); +sys_var_const_os_str_ptr sys_ssl_cipher("ssl_cipher", &opt_ssl_cipher); +sys_var_const_os_str_ptr sys_ssl_key("ssl_key", &opt_ssl_key); #else -sys_var_const_str sys_ssl_ca("ssl_ca", NULL); -sys_var_const_str sys_ssl_capath("ssl_capath", NULL); -sys_var_const_str sys_ssl_cert("ssl_cert", NULL); -sys_var_const_str sys_ssl_cipher("ssl_cipher", NULL); -sys_var_const_str sys_ssl_key("ssl_key", NULL); +sys_var_const_os_str sys_ssl_ca("ssl_ca", NULL); +sys_var_const_os_str sys_ssl_capath("ssl_capath", NULL); +sys_var_const_os_str sys_ssl_cert("ssl_cert", NULL); +sys_var_const_os_str sys_ssl_cipher("ssl_cipher", NULL); +sys_var_const_os_str sys_ssl_key("ssl_key", NULL); #endif sys_var_thd_enum sys_updatable_views_with_limit("updatable_views_with_limit", @@ -460,6 +465,14 @@ sys_var_long_ptr sys_innodb_commit_concurrency("innodb_commit_concurrency", sys_var_long_ptr sys_innodb_flush_log_at_trx_commit( "innodb_flush_log_at_trx_commit", &srv_flush_log_at_trx_commit); +sys_var_const_os_str_ptr sys_innodb_data_file_path("innodb_data_file_path", + &innobase_data_file_path); +sys_var_const_os_str_ptr sys_innodb_data_home_dir("innodb_data_home_dir", + &innobase_data_home_dir); +sys_var_const_os_str_ptr sys_innodb_log_arch_dir("innodb_log_arch_dir", + &innobase_log_arch_dir); +sys_var_const_os_str_ptr sys_innodb_log_group_home_dir("innodb_log_group_home_dir", + &innobase_log_group_home_dir); #endif /* Condition pushdown to storage engine */ @@ -844,7 +857,7 @@ struct show_var_st init_vars[]= { {sys_character_set_results.name,(char*) &sys_character_set_results, SHOW_SYS}, {sys_character_set_server.name, (char*) &sys_character_set_server,SHOW_SYS}, {sys_charset_system.name, (char*) &sys_charset_system, SHOW_SYS}, - {"character_sets_dir", mysql_charsets_dir, SHOW_CHAR}, + {sys_character_sets_dir.name, (char *) &sys_character_sets_dir, SHOW_SYS}, {sys_collation_connection.name,(char*) &sys_collation_connection, SHOW_SYS}, {sys_collation_database.name,(char*) &sys_collation_database, SHOW_SYS}, {sys_collation_server.name,(char*) &sys_collation_server, SHOW_SYS}, @@ -905,8 +918,8 @@ struct show_var_st init_vars[]= { {"innodb_checksums", (char*) &innobase_use_checksums, SHOW_MY_BOOL}, {sys_innodb_commit_concurrency.name, (char*) &sys_innodb_commit_concurrency, SHOW_SYS}, {sys_innodb_concurrency_tickets.name, (char*) &sys_innodb_concurrency_tickets, SHOW_SYS}, - {"innodb_data_file_path", (char*) &innobase_data_file_path, SHOW_CHAR_PTR}, - {"innodb_data_home_dir", (char*) &innobase_data_home_dir, SHOW_CHAR_PTR}, + {sys_innodb_data_file_path.name, (char*) &sys_innodb_data_file_path, SHOW_SYS}, + {sys_innodb_data_home_dir.name, (char*) &sys_innodb_data_home_dir, SHOW_SYS}, {"innodb_adaptive_hash_index", (char*) &innobase_adaptive_hash_index, SHOW_MY_BOOL}, {"innodb_doublewrite", (char*) &innobase_use_doublewrite, SHOW_MY_BOOL}, {sys_innodb_fast_shutdown.name,(char*) &sys_innodb_fast_shutdown, SHOW_SYS}, @@ -917,12 +930,12 @@ struct show_var_st init_vars[]= { {"innodb_force_recovery", (char*) &innobase_force_recovery, SHOW_LONG }, {"innodb_lock_wait_timeout", (char*) &innobase_lock_wait_timeout, SHOW_LONG }, {"innodb_locks_unsafe_for_binlog", (char*) &innobase_locks_unsafe_for_binlog, SHOW_MY_BOOL}, - {"innodb_log_arch_dir", (char*) &innobase_log_arch_dir, SHOW_CHAR_PTR}, + {sys_innodb_log_arch_dir.name, (char*) &sys_innodb_log_arch_dir, SHOW_SYS}, {"innodb_log_archive", (char*) &innobase_log_archive, SHOW_MY_BOOL}, {"innodb_log_buffer_size", (char*) &innobase_log_buffer_size, SHOW_LONG }, {"innodb_log_file_size", (char*) &innobase_log_file_size, SHOW_LONGLONG}, {"innodb_log_files_in_group", (char*) &innobase_log_files_in_group, SHOW_LONG}, - {"innodb_log_group_home_dir", (char*) &innobase_log_group_home_dir, SHOW_CHAR_PTR}, + {sys_innodb_log_group_home_dir.name, (char*) &sys_innodb_log_group_home_dir, SHOW_SYS}, {sys_innodb_max_dirty_pages_pct.name, (char*) &sys_innodb_max_dirty_pages_pct, SHOW_SYS}, {sys_innodb_max_purge_lag.name, (char*) &sys_innodb_max_purge_lag, SHOW_SYS}, {"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG}, @@ -1026,7 +1039,7 @@ struct show_var_st init_vars[]= { {sys_optimizer_search_depth.name,(char*) &sys_optimizer_search_depth, SHOW_SYS}, {"pid_file", (char*) pidfile_name, SHOW_CHAR}, - {"plugin_dir", (char*) opt_plugin_dir, SHOW_CHAR}, + {sys_plugin_dir.name, (char*) &sys_plugin_dir, SHOW_SYS}, {"port", (char*) &mysqld_port, SHOW_INT}, {sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS}, {"protocol_version", (char*) &protocol_version, SHOW_INT}, @@ -1068,7 +1081,7 @@ struct show_var_st init_vars[]= { #ifdef HAVE_REPLICATION {sys_slave_compressed_protocol.name, (char*) &sys_slave_compressed_protocol, SHOW_SYS}, - {"slave_load_tmpdir", (char*) &slave_load_tmpdir, SHOW_CHAR_PTR}, + {sys_slave_load_tmpdir.name,(char*) &sys_slave_load_tmpdir, SHOW_SYS}, {sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout, SHOW_SYS}, {"slave_skip_errors", (char*) &slave_error_mask, SHOW_SLAVE_SKIP_ERRORS}, {sys_slave_trans_retries.name,(char*) &sys_slave_trans_retries, SHOW_SYS}, @@ -1175,6 +1188,7 @@ bool update_sys_var_str(sys_var_str *var_str, rw_lock_t *var_mutex, old_value= var_str->value; var_str->value= res; var_str->value_length= new_length; + var_str->is_os_charset= FALSE; rw_unlock(var_mutex); my_free(old_value, MYF(MY_ALLOW_ZERO_PTR)); return 0; @@ -1914,11 +1928,11 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base) char *str= (char*) value_ptr(thd, var_type, base); if (str) tmp= new Item_string(str, strlen(str), - system_charset_info, DERIVATION_SYSCONST); + charset(thd), DERIVATION_SYSCONST); else { tmp= new Item_null(); - tmp->collation.set(system_charset_info, DERIVATION_SYSCONST); + tmp->collation.set(charset(thd), DERIVATION_SYSCONST); } pthread_mutex_unlock(&LOCK_global_system_variables); return tmp; @@ -1930,6 +1944,13 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base) } +CHARSET_INFO *sys_var::charset(THD *thd) +{ + return is_os_charset ? thd->variables.character_set_filesystem : + system_charset_info; +} + + bool sys_var_thd_enum::update(THD *thd, set_var *var) { if (var->type == OPT_GLOBAL) @@ -3454,6 +3475,7 @@ int set_var_password::check(THD *thd) #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!user->host.str) { + DBUG_ASSERT(thd->security_ctx->priv_host); if (*thd->security_ctx->priv_host != 0) { user->host.str= (char *) thd->security_ctx->priv_host; @@ -3465,6 +3487,12 @@ int set_var_password::check(THD *thd) user->host.length= 1; } } + if (!user->user.str) + { + DBUG_ASSERT(thd->security_ctx->priv_user); + user->user.str= (char *) thd->security_ctx->priv_user; + user->user.length= strlen(thd->security_ctx->priv_user); + } /* Returns 1 as the function sends error to client */ return check_change_password(thd, user->host.str, user->user.str, password, strlen(password)) ? 1 : 0; diff --git a/sql/set_var.h b/sql/set_var.h index c37cc400e43..f43d3b75cee 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -46,9 +46,17 @@ public: sys_after_update_func after_update; bool no_support_one_shot; + /* + true if the value is in character_set_filesystem, + false otherwise. + Note that we can't use a pointer to the charset as the system var is + instantiated in global scope and the charset pointers are initialized + later. + */ + bool is_os_charset; sys_var(const char *name_arg, sys_after_update_func func= NULL) :name(name_arg), after_update(func) - , no_support_one_shot(1) + , no_support_one_shot(1), is_os_charset(FALSE) {} virtual ~sys_var() {} virtual bool check(THD *thd, set_var *var); @@ -68,6 +76,7 @@ public: Item *item(THD *thd, enum_var_type type, LEX_STRING *base); virtual bool is_struct() { return 0; } virtual bool is_readonly() const { return 0; } + CHARSET_INFO *charset(THD *thd); }; @@ -247,6 +256,17 @@ public: }; +class sys_var_const_os_str: public sys_var_const_str +{ +public: + sys_var_const_os_str(const char *name_arg, const char *value_arg) + :sys_var_const_str(name_arg, value_arg) + { + is_os_charset= TRUE; + } +}; + + class sys_var_const_str_ptr :public sys_var { public: @@ -276,6 +296,17 @@ public: }; +class sys_var_const_os_str_ptr :public sys_var_const_str_ptr +{ +public: + sys_var_const_os_str_ptr(const char *name_arg, char **value_arg) + :sys_var_const_str_ptr(name_arg, value_arg) + { + is_os_charset= TRUE; + } +}; + + class sys_var_enum :public sys_var { uint *value; @@ -791,6 +822,20 @@ public: bool is_readonly() const { return 1; } }; + +class sys_var_readonly_os: public sys_var_readonly +{ +public: + sys_var_readonly_os(const char *name_arg, enum_var_type type, + SHOW_TYPE show_type_arg, + sys_value_ptr_func value_ptr_func_arg) + :sys_var_readonly(name_arg, type, show_type_arg, value_ptr_func_arg) + { + is_os_charset= TRUE; + } +}; + + class sys_var_thd_time_zone :public sys_var_thd { public: diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index df5e844749f..c59c42d512a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3866,6 +3866,11 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, Security_context *sctx= thd->security_ctx; ulong want_access= want_access_arg; const char *table_name= NULL; + /* + Flag that gets set if privilege checking has to be performed on column + level. + */ + bool using_column_privileges= FALSE; if (grant_option) { @@ -3909,6 +3914,8 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, GRANT_COLUMN *grant_column= column_hash_search(grant_table, field_name, (uint) strlen(field_name)); + if (grant_column) + using_column_privileges= TRUE; if (!grant_column || (~grant_column->rights & want_access)) goto err; } @@ -3924,12 +3931,21 @@ err: char command[128]; get_privilege_desc(command, sizeof(command), want_access); - my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), - command, - sctx->priv_user, - sctx->host_or_ip, - fields->name(), - table_name); + /* + Do not give an error message listing a column name unless the user has + privilege to see all columns. + */ + if (using_column_privileges) + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), + command, sctx->priv_user, + sctx->host_or_ip, table_name); + else + my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), + command, + sctx->priv_user, + sctx->host_or_ip, + fields->name(), + table_name); return 1; } @@ -5953,10 +5969,12 @@ int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr) } -void update_schema_privilege(TABLE *table, char *buff, const char* db, - const char* t_name, const char* column, - uint col_length, const char *priv, - uint priv_length, const char* is_grantable) +#ifndef NO_EMBEDDED_ACCESS_CHECKS +static bool update_schema_privilege(THD *thd, TABLE *table, char *buff, + const char* db, const char* t_name, + const char* column, uint col_length, + const char *priv, uint priv_length, + const char* is_grantable) { int i= 2; CHARSET_INFO *cs= system_charset_info; @@ -5970,13 +5988,15 @@ void update_schema_privilege(TABLE *table, char *buff, const char* db, table->field[i++]->store(column, col_length, cs); table->field[i++]->store(priv, priv_length, cs); table->field[i]->store(is_grantable, strlen(is_grantable), cs); - table->file->write_row(table->record[0]); + return schema_table_store_record(thd, table); } +#endif int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) { #ifndef NO_EMBEDDED_ACCESS_CHECKS + int error= 0; uint counter; ACL_USER *acl_user; ulong want_access; @@ -6010,8 +6030,14 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) strxmov(buff,"'",user,"'@'",host,"'",NullS); if (!(want_access & ~GRANT_ACL)) - update_schema_privilege(table, buff, 0, 0, 0, 0, - STRING_WITH_LEN("USAGE"), is_grantable); + { + if (update_schema_privilege(thd, table, buff, 0, 0, 0, 0, + STRING_WITH_LEN("USAGE"), is_grantable)) + { + error= 1; + goto err; + } + } else { uint priv_id; @@ -6019,16 +6045,22 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) for (priv_id=0, j = SELECT_ACL;j <= GLOBAL_ACLS; priv_id++,j <<= 1) { if (test_access & j) - update_schema_privilege(table, buff, 0, 0, 0, 0, - command_array[priv_id], - command_lengths[priv_id], is_grantable); + { + if (update_schema_privilege(thd, table, buff, 0, 0, 0, 0, + command_array[priv_id], + command_lengths[priv_id], is_grantable)) + { + error= 1; + goto err; + } + } } } } - +err: pthread_mutex_unlock(&acl_cache->lock); - DBUG_RETURN(0); + DBUG_RETURN(error); #else return(0); #endif @@ -6038,6 +6070,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) { #ifndef NO_EMBEDDED_ACCESS_CHECKS + int error= 0; uint counter; ACL_DB *acl_db; ulong want_access; @@ -6075,24 +6108,36 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) } strxmov(buff,"'",user,"'@'",host,"'",NullS); if (!(want_access & ~GRANT_ACL)) - update_schema_privilege(table, buff, acl_db->db, 0, 0, - 0, STRING_WITH_LEN("USAGE"), is_grantable); + { + if (update_schema_privilege(thd, table, buff, acl_db->db, 0, 0, + 0, STRING_WITH_LEN("USAGE"), is_grantable)) + { + error= 1; + goto err; + } + } else { int cnt; ulong j,test_access= want_access & ~GRANT_ACL; for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1) if (test_access & j) - update_schema_privilege(table, buff, acl_db->db, 0, 0, 0, - command_array[cnt], command_lengths[cnt], - is_grantable); + { + if (update_schema_privilege(thd, table, buff, acl_db->db, 0, 0, 0, + command_array[cnt], command_lengths[cnt], + is_grantable)) + { + error= 1; + goto err; + } + } } } } - +err: pthread_mutex_unlock(&acl_cache->lock); - DBUG_RETURN(0); + DBUG_RETURN(error); #else return (0); #endif @@ -6102,6 +6147,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) { #ifndef NO_EMBEDDED_ACCESS_CHECKS + int error= 0; uint index; char buff[100]; TABLE *table= tables->table; @@ -6141,8 +6187,15 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) strxmov(buff, "'", user, "'@'", host, "'", NullS); if (!test_access) - update_schema_privilege(table, buff, grant_table->db, grant_table->tname, - 0, 0, STRING_WITH_LEN("USAGE"), is_grantable); + { + if (update_schema_privilege(thd, table, buff, grant_table->db, + grant_table->tname, 0, 0, + STRING_WITH_LEN("USAGE"), is_grantable)) + { + error= 1; + goto err; + } + } else { ulong j; @@ -6150,17 +6203,24 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) for (cnt= 0, j= SELECT_ACL; j <= TABLE_ACLS; cnt++, j<<= 1) { if (test_access & j) - update_schema_privilege(table, buff, grant_table->db, - grant_table->tname, 0, 0, command_array[cnt], - command_lengths[cnt], is_grantable); + { + if (update_schema_privilege(thd, table, buff, grant_table->db, + grant_table->tname, 0, 0, + command_array[cnt], + command_lengths[cnt], is_grantable)) + { + error= 1; + goto err; + } + } } } - } + } } - +err: rw_unlock(&LOCK_grant); - DBUG_RETURN(0); + DBUG_RETURN(error); #else return (0); #endif @@ -6170,6 +6230,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond) { #ifndef NO_EMBEDDED_ACCESS_CHECKS + int error= 0; uint index; char buff[100]; TABLE *table= tables->table; @@ -6219,22 +6280,28 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond) GRANT_COLUMN *grant_column = (GRANT_COLUMN*) hash_element(&grant_table->hash_columns,col_index); if ((grant_column->rights & j) && (table_access & j)) - update_schema_privilege(table, buff, grant_table->db, - grant_table->tname, - grant_column->column, - grant_column->key_length, - command_array[cnt], - command_lengths[cnt], is_grantable); + { + if (update_schema_privilege(thd, table, buff, grant_table->db, + grant_table->tname, + grant_column->column, + grant_column->key_length, + command_array[cnt], + command_lengths[cnt], is_grantable)) + { + error= 1; + goto err; + } + } } } } } } } - +err: rw_unlock(&LOCK_grant); - DBUG_RETURN(0); + DBUG_RETURN(error); #else return (0); #endif diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 873a3eac24e..781bbc0a553 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2102,7 +2102,10 @@ bool reopen_table(TABLE *table,bool locked) for (key=0 ; key < table->s->keys ; key++) { for (part=0 ; part < table->key_info[key].usable_key_parts ; part++) + { table->key_info[key].key_part[part].field->table= table; + table->key_info[key].key_part[part].field->orig_table= table; + } } if (table->triggers) table->triggers->set_table(table); @@ -5476,7 +5479,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, #ifndef NO_EMBEDDED_ACCESS_CHECKS /* Ensure that we have access rights to all fields to be inserted. */ - if (!((table && (table->grant.privilege & SELECT_ACL) || + if (!((table && !tables->view && (table->grant.privilege & SELECT_ACL) || tables->view && (tables->grant.privilege & SELECT_ACL))) && !any_privileges) { diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index b4fe1e65bbc..4a060ba7178 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -747,7 +747,12 @@ void query_cache_end_of_result(THD *thd) if (thd->net.query_cache_query == 0) DBUG_VOID_RETURN; - if (thd->killed) + /* + Check if the NET layer raised a unreported error -- my_error() and + as a consequence query_cache_abort() haven't been called. Abort the + cached result as it might be only partially complete. + */ + if (thd->killed || thd->net.report_error) { query_cache_abort(&thd->net); DBUG_VOID_RETURN; @@ -896,6 +901,8 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) CLIENT_PROTOCOL_41); flags.more_results_exists= test(thd->server_status & SERVER_MORE_RESULTS_EXISTS); + flags.in_trans= test(thd->server_status & SERVER_STATUS_IN_TRANS); + flags.autocommit= test(thd->server_status & SERVER_STATUS_AUTOCOMMIT); flags.pkt_nr= net->pkt_nr; flags.character_set_client_num= thd->variables.character_set_client->number; @@ -916,7 +923,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, pkt_nr: %d, \ CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \ sql mode: 0x%lx, sort len: %lu, conncat len: %lu, div_precision: %lu, \ -def_week_frmt: %lu", +def_week_frmt: %lu, in_trans: %d, autocommit: %d", (int)flags.client_long_flag, (int)flags.client_protocol_41, (int)flags.more_results_exists, @@ -930,7 +937,10 @@ def_week_frmt: %lu", flags.max_sort_length, flags.group_concat_max_len, flags.div_precision_increment, - flags.default_week_format)); + flags.default_week_format, + (int)flags.in_trans, + (int)flags.autocommit)); + /* Make InnoDB to release the adaptive hash index latch before acquiring the query cache mutex. @@ -1191,6 +1201,8 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) CLIENT_PROTOCOL_41); flags.more_results_exists= test(thd->server_status & SERVER_MORE_RESULTS_EXISTS); + flags.in_trans= test(thd->server_status & SERVER_STATUS_IN_TRANS); + flags.autocommit= test(thd->server_status & SERVER_STATUS_AUTOCOMMIT); flags.pkt_nr= thd->net.pkt_nr; flags.character_set_client_num= thd->variables.character_set_client->number; flags.character_set_results_num= @@ -1209,7 +1221,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, pkt_nr: %d, \ CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \ sql mode: 0x%lx, sort len: %lu, conncat len: %lu, div_precision: %lu, \ -def_week_frmt: %lu", +def_week_frmt: %lu, in_trans: %d, autocommit: %d", (int)flags.client_long_flag, (int)flags.client_protocol_41, (int)flags.more_results_exists, @@ -1223,7 +1235,9 @@ def_week_frmt: %lu", flags.max_sort_length, flags.group_concat_max_len, flags.div_precision_increment, - flags.default_week_format)); + flags.default_week_format, + (int)flags.in_trans, + (int)flags.autocommit)); memcpy((void *)(sql + (tot_length - QUERY_CACHE_FLAGS_SIZE)), &flags, QUERY_CACHE_FLAGS_SIZE); query_block = (Query_cache_block *) hash_search(&queries, (byte*) sql, diff --git a/sql/sql_class.cc b/sql/sql_class.cc index e00323ebab1..88b7dfb46d7 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -172,7 +172,9 @@ THD::THD() /* statement id */ 0), Open_tables_state(refresh_version), lock_id(&main_lock_id), - user_time(0), in_sub_stmt(0), global_read_lock(0), is_fatal_error(0), + user_time(0), in_sub_stmt(0), + table_map_for_update(0), + global_read_lock(0), is_fatal_error(0), transaction_rollback_request(0), is_fatal_sub_stmt_error(0), rand_used(0), time_zone_used(0), last_insert_id_used(0), last_insert_id_used_bin_log(0), insert_id_used(0), @@ -397,6 +399,10 @@ void THD::init_for_queries() void THD::change_user(void) { + pthread_mutex_lock(&LOCK_status); + add_to_status(&global_status_var, &status_var); + pthread_mutex_unlock(&LOCK_status); + cleanup(); cleanup_done= 0; init(); @@ -653,6 +659,8 @@ void THD::cleanup_after_query() free_items(); /* Reset where. */ where= THD::DEFAULT_WHERE; + /* reset table map for multi-table update */ + table_map_for_update= 0; } @@ -1049,6 +1057,11 @@ bool select_send::send_data(List<Item> &items) my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); break; } + /* + Reset buffer to its original state, as it may have been altered in + Item::send(). + */ + buffer.set(buff, sizeof(buff), &my_charset_bin); } thd->sent_row_count++; if (!thd->vio_ok()) diff --git a/sql/sql_class.h b/sql/sql_class.h index c8d42d44df7..3e3dfcd08fa 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -205,6 +205,13 @@ class MYSQL_LOG: public TC_LOG time_t last_time,query_start; IO_CACHE log_file; IO_CACHE index_file; + /* + purge_temp is a temp file used in purge_logs so that the index file + can be updated before deleting files from disk, yielding better crash + recovery. It is created on demand the first time purge_logs is called + and then reused for subsequent calls. It is cleaned up in cleanup(). + */ + IO_CACHE purge_temp; char *name; char time_buff[20],db[NAME_LEN+1]; char log_file_name[FN_REFLEN],index_file_name[FN_REFLEN]; @@ -1351,6 +1358,13 @@ public: Note: in the parser, stmt_arena == thd, even for PS/SP. */ Query_arena *stmt_arena; + + /* + map for tables that will be updated for a multi-table update query + statement, for other query statements, this will be zero. + */ + table_map table_map_for_update; + /* next_insert_id is set on SET INSERT_ID= #. This is used as the next generated auto_increment value in handler.cc diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index 16567765ba6..83c60814cf3 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -85,6 +85,7 @@ class Materialized_cursor: public Server_side_cursor List<Item> item_list; ulong fetch_limit; ulong fetch_count; + bool is_rnd_inited; public: Materialized_cursor(select_result *result, TABLE *table); @@ -191,7 +192,11 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result, such command is SHOW VARIABLES or SHOW STATUS. */ if (rc) + { + if (result_materialize->materialized_cursor) + delete result_materialize->materialized_cursor; goto err_open; + } if (sensitive_cursor->is_open()) { @@ -532,7 +537,8 @@ Materialized_cursor::Materialized_cursor(select_result *result_arg, :Server_side_cursor(&table_arg->mem_root, result_arg), table(table_arg), fetch_limit(0), - fetch_count(0) + fetch_count(0), + is_rnd_inited(0) { fake_unit.init_query(); fake_unit.thd= table->in_use; @@ -589,11 +595,12 @@ int Materialized_cursor::open(JOIN *join __attribute__((unused))) THD *thd= fake_unit.thd; int rc; Query_arena backup_arena; - thd->set_n_backup_active_arena(this, &backup_arena); /* Create a list of fields and start sequential scan */ - rc= (result->prepare(item_list, &fake_unit) || - table->file->ha_rnd_init(TRUE)); + rc= result->prepare(item_list, &fake_unit); + if (!rc && !(rc= table->file->ha_rnd_init(TRUE))) + is_rnd_inited= 1; + thd->restore_active_arena(this, &backup_arena); if (rc == 0) { @@ -673,7 +680,8 @@ void Materialized_cursor::close() { /* Free item_list items */ free_items(); - (void) table->file->ha_rnd_end(); + if (is_rnd_inited) + (void) table->file->ha_rnd_end(); /* We need to grab table->mem_root to prevent free_tmp_table from freeing: the cursor object was allocated in this memory. diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 8fbb407555a..c3cf7429222 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -909,7 +909,6 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, /* .frm archive: Those archives are obsolete, but following code should exist to remove existent "arc" directories. - See #ifdef FRM_ARCHIVE directives for obsolete code. */ char newpath[FN_REFLEN]; MY_DIR *new_dirp; @@ -1069,7 +1068,6 @@ static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error) NOTE A support of "arc" directories is obsolete, however this function should exist to remove existent "arc" directories. - See #ifdef FRM_ARCHIVE directives for obsolete code. */ long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path) { diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 822f2b2c419..f58a4ec4921 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -151,6 +151,9 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables) } VOID(pthread_mutex_unlock(&LOCK_open)); } + + /* Mark table as closed, ready for re-open if necessary. */ + tables->table= NULL; } /* @@ -168,8 +171,7 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables) 'reopen' is set when a handler table is to be re-opened. In this case, 'tables' is the pointer to the hashed TABLE_LIST object which has been saved on the original open. - 'reopen' is also used to suppress the sending of an 'ok' message or - error messages. + 'reopen' is also used to suppress the sending of an 'ok' message. RETURN FALSE OK @@ -205,8 +207,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) strlen(tables->alias) + 1)) { DBUG_PRINT("info",("duplicate '%s'", tables->alias)); - if (! reopen) - my_error(ER_NONUNIQ_TABLE, MYF(0), tables->alias); + my_error(ER_NONUNIQ_TABLE, MYF(0), tables->alias); goto err; } } @@ -251,8 +252,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) /* There can be only one table in '*tables'. */ if (! (tables->table->file->table_flags() & HA_CAN_SQL_HANDLER)) { - if (! reopen) - my_error(ER_ILLEGAL_HA, MYF(0), tables->alias); + my_error(ER_ILLEGAL_HA, MYF(0), tables->alias); goto err; } @@ -464,8 +464,7 @@ retry: if (need_reopen) { - mysql_ha_close_table(thd, tables); - hash_tables->table= NULL; + mysql_ha_close_table(thd, hash_tables); /* The lock might have been aborted, we need to manually reset thd->some_tables_deleted because handler's tables are closed diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc index 4e61c664106..3def9864c29 100644 --- a/sql/sql_locale.cc +++ b/sql/sql_locale.cc @@ -49,7 +49,9 @@ MY_LOCALE my_locale_ar_AE &my_locale_typelib_month_names_ar_AE, &my_locale_typelib_ab_month_names_ar_AE, &my_locale_typelib_day_names_ar_AE, - &my_locale_typelib_ab_day_names_ar_AE + &my_locale_typelib_ab_day_names_ar_AE, + 6, + 8 ); /***** LOCALE END ar_AE *****/ @@ -79,7 +81,9 @@ MY_LOCALE my_locale_ar_BH &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, - &my_locale_typelib_ab_day_names_ar_BH + &my_locale_typelib_ab_day_names_ar_BH, + 6, + 8 ); /***** LOCALE END ar_BH *****/ @@ -109,7 +113,9 @@ MY_LOCALE my_locale_ar_JO &my_locale_typelib_month_names_ar_JO, &my_locale_typelib_ab_month_names_ar_JO, &my_locale_typelib_day_names_ar_JO, - &my_locale_typelib_ab_day_names_ar_JO + &my_locale_typelib_ab_day_names_ar_JO, + 12, + 8 ); /***** LOCALE END ar_JO *****/ @@ -139,7 +145,9 @@ MY_LOCALE my_locale_ar_SA &my_locale_typelib_month_names_ar_SA, &my_locale_typelib_ab_month_names_ar_SA, &my_locale_typelib_day_names_ar_SA, - &my_locale_typelib_ab_day_names_ar_SA + &my_locale_typelib_ab_day_names_ar_SA, + 12, + 8 ); /***** LOCALE END ar_SA *****/ @@ -169,7 +177,9 @@ MY_LOCALE my_locale_ar_SY &my_locale_typelib_month_names_ar_SY, &my_locale_typelib_ab_month_names_ar_SY, &my_locale_typelib_day_names_ar_SY, - &my_locale_typelib_ab_day_names_ar_SY + &my_locale_typelib_ab_day_names_ar_SY, + 12, + 8 ); /***** LOCALE END ar_SY *****/ @@ -199,7 +209,9 @@ MY_LOCALE my_locale_be_BY &my_locale_typelib_month_names_be_BY, &my_locale_typelib_ab_month_names_be_BY, &my_locale_typelib_day_names_be_BY, - &my_locale_typelib_ab_day_names_be_BY + &my_locale_typelib_ab_day_names_be_BY, + 10, + 10 ); /***** LOCALE END be_BY *****/ @@ -229,7 +241,9 @@ MY_LOCALE my_locale_bg_BG &my_locale_typelib_month_names_bg_BG, &my_locale_typelib_ab_month_names_bg_BG, &my_locale_typelib_day_names_bg_BG, - &my_locale_typelib_ab_day_names_bg_BG + &my_locale_typelib_ab_day_names_bg_BG, + 9, + 10 ); /***** LOCALE END bg_BG *****/ @@ -259,7 +273,9 @@ MY_LOCALE my_locale_ca_ES &my_locale_typelib_month_names_ca_ES, &my_locale_typelib_ab_month_names_ca_ES, &my_locale_typelib_day_names_ca_ES, - &my_locale_typelib_ab_day_names_ca_ES + &my_locale_typelib_ab_day_names_ca_ES, + 8, + 9 ); /***** LOCALE END ca_ES *****/ @@ -289,7 +305,9 @@ MY_LOCALE my_locale_cs_CZ &my_locale_typelib_month_names_cs_CZ, &my_locale_typelib_ab_month_names_cs_CZ, &my_locale_typelib_day_names_cs_CZ, - &my_locale_typelib_ab_day_names_cs_CZ + &my_locale_typelib_ab_day_names_cs_CZ, + 8, + 7 ); /***** LOCALE END cs_CZ *****/ @@ -319,7 +337,9 @@ MY_LOCALE my_locale_da_DK &my_locale_typelib_month_names_da_DK, &my_locale_typelib_ab_month_names_da_DK, &my_locale_typelib_day_names_da_DK, - &my_locale_typelib_ab_day_names_da_DK + &my_locale_typelib_ab_day_names_da_DK, + 9, + 7 ); /***** LOCALE END da_DK *****/ @@ -349,7 +369,9 @@ MY_LOCALE my_locale_de_AT &my_locale_typelib_month_names_de_AT, &my_locale_typelib_ab_month_names_de_AT, &my_locale_typelib_day_names_de_AT, - &my_locale_typelib_ab_day_names_de_AT + &my_locale_typelib_ab_day_names_de_AT, + 9, + 10 ); /***** LOCALE END de_AT *****/ @@ -379,7 +401,9 @@ MY_LOCALE my_locale_de_DE &my_locale_typelib_month_names_de_DE, &my_locale_typelib_ab_month_names_de_DE, &my_locale_typelib_day_names_de_DE, - &my_locale_typelib_ab_day_names_de_DE + &my_locale_typelib_ab_day_names_de_DE, + 9, + 10 ); /***** LOCALE END de_DE *****/ @@ -409,7 +433,9 @@ MY_LOCALE my_locale_en_US &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, - &my_locale_typelib_ab_day_names_en_US + &my_locale_typelib_ab_day_names_en_US, + 9, + 9 ); /***** LOCALE END en_US *****/ @@ -439,7 +465,9 @@ MY_LOCALE my_locale_es_ES &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_ES *****/ @@ -469,7 +497,9 @@ MY_LOCALE my_locale_et_EE &my_locale_typelib_month_names_et_EE, &my_locale_typelib_ab_month_names_et_EE, &my_locale_typelib_day_names_et_EE, - &my_locale_typelib_ab_day_names_et_EE + &my_locale_typelib_ab_day_names_et_EE, + 9, + 9 ); /***** LOCALE END et_EE *****/ @@ -499,7 +529,9 @@ MY_LOCALE my_locale_eu_ES &my_locale_typelib_month_names_eu_ES, &my_locale_typelib_ab_month_names_eu_ES, &my_locale_typelib_day_names_eu_ES, - &my_locale_typelib_ab_day_names_eu_ES + &my_locale_typelib_ab_day_names_eu_ES, + 9, + 10 ); /***** LOCALE END eu_ES *****/ @@ -529,7 +561,9 @@ MY_LOCALE my_locale_fi_FI &my_locale_typelib_month_names_fi_FI, &my_locale_typelib_ab_month_names_fi_FI, &my_locale_typelib_day_names_fi_FI, - &my_locale_typelib_ab_day_names_fi_FI + &my_locale_typelib_ab_day_names_fi_FI, + 9, + 11 ); /***** LOCALE END fi_FI *****/ @@ -559,7 +593,9 @@ MY_LOCALE my_locale_fo_FO &my_locale_typelib_month_names_fo_FO, &my_locale_typelib_ab_month_names_fo_FO, &my_locale_typelib_day_names_fo_FO, - &my_locale_typelib_ab_day_names_fo_FO + &my_locale_typelib_ab_day_names_fo_FO, + 9, + 12 ); /***** LOCALE END fo_FO *****/ @@ -589,7 +625,9 @@ MY_LOCALE my_locale_fr_FR &my_locale_typelib_month_names_fr_FR, &my_locale_typelib_ab_month_names_fr_FR, &my_locale_typelib_day_names_fr_FR, - &my_locale_typelib_ab_day_names_fr_FR + &my_locale_typelib_ab_day_names_fr_FR, + 9, + 8 ); /***** LOCALE END fr_FR *****/ @@ -619,7 +657,9 @@ MY_LOCALE my_locale_gl_ES &my_locale_typelib_month_names_gl_ES, &my_locale_typelib_ab_month_names_gl_ES, &my_locale_typelib_day_names_gl_ES, - &my_locale_typelib_ab_day_names_gl_ES + &my_locale_typelib_ab_day_names_gl_ES, + 8, + 8 ); /***** LOCALE END gl_ES *****/ @@ -649,7 +689,9 @@ MY_LOCALE my_locale_gu_IN &my_locale_typelib_month_names_gu_IN, &my_locale_typelib_ab_month_names_gu_IN, &my_locale_typelib_day_names_gu_IN, - &my_locale_typelib_ab_day_names_gu_IN + &my_locale_typelib_ab_day_names_gu_IN, + 10, + 8 ); /***** LOCALE END gu_IN *****/ @@ -679,7 +721,9 @@ MY_LOCALE my_locale_he_IL &my_locale_typelib_month_names_he_IL, &my_locale_typelib_ab_month_names_he_IL, &my_locale_typelib_day_names_he_IL, - &my_locale_typelib_ab_day_names_he_IL + &my_locale_typelib_ab_day_names_he_IL, + 7, + 5 ); /***** LOCALE END he_IL *****/ @@ -709,7 +753,9 @@ MY_LOCALE my_locale_hi_IN &my_locale_typelib_month_names_hi_IN, &my_locale_typelib_ab_month_names_hi_IN, &my_locale_typelib_day_names_hi_IN, - &my_locale_typelib_ab_day_names_hi_IN + &my_locale_typelib_ab_day_names_hi_IN, + 7, + 9 ); /***** LOCALE END hi_IN *****/ @@ -739,7 +785,9 @@ MY_LOCALE my_locale_hr_HR &my_locale_typelib_month_names_hr_HR, &my_locale_typelib_ab_month_names_hr_HR, &my_locale_typelib_day_names_hr_HR, - &my_locale_typelib_ab_day_names_hr_HR + &my_locale_typelib_ab_day_names_hr_HR, + 8, + 11 ); /***** LOCALE END hr_HR *****/ @@ -769,7 +817,9 @@ MY_LOCALE my_locale_hu_HU &my_locale_typelib_month_names_hu_HU, &my_locale_typelib_ab_month_names_hu_HU, &my_locale_typelib_day_names_hu_HU, - &my_locale_typelib_ab_day_names_hu_HU + &my_locale_typelib_ab_day_names_hu_HU, + 10, + 9 ); /***** LOCALE END hu_HU *****/ @@ -799,7 +849,9 @@ MY_LOCALE my_locale_id_ID &my_locale_typelib_month_names_id_ID, &my_locale_typelib_ab_month_names_id_ID, &my_locale_typelib_day_names_id_ID, - &my_locale_typelib_ab_day_names_id_ID + &my_locale_typelib_ab_day_names_id_ID, + 9, + 6 ); /***** LOCALE END id_ID *****/ @@ -829,7 +881,9 @@ MY_LOCALE my_locale_is_IS &my_locale_typelib_month_names_is_IS, &my_locale_typelib_ab_month_names_is_IS, &my_locale_typelib_day_names_is_IS, - &my_locale_typelib_ab_day_names_is_IS + &my_locale_typelib_ab_day_names_is_IS, + 9, + 12 ); /***** LOCALE END is_IS *****/ @@ -859,7 +913,9 @@ MY_LOCALE my_locale_it_CH &my_locale_typelib_month_names_it_CH, &my_locale_typelib_ab_month_names_it_CH, &my_locale_typelib_day_names_it_CH, - &my_locale_typelib_ab_day_names_it_CH + &my_locale_typelib_ab_day_names_it_CH, + 9, + 9 ); /***** LOCALE END it_CH *****/ @@ -889,7 +945,9 @@ MY_LOCALE my_locale_ja_JP &my_locale_typelib_month_names_ja_JP, &my_locale_typelib_ab_month_names_ja_JP, &my_locale_typelib_day_names_ja_JP, - &my_locale_typelib_ab_day_names_ja_JP + &my_locale_typelib_ab_day_names_ja_JP, + 3, + 3 ); /***** LOCALE END ja_JP *****/ @@ -919,7 +977,9 @@ MY_LOCALE my_locale_ko_KR &my_locale_typelib_month_names_ko_KR, &my_locale_typelib_ab_month_names_ko_KR, &my_locale_typelib_day_names_ko_KR, - &my_locale_typelib_ab_day_names_ko_KR + &my_locale_typelib_ab_day_names_ko_KR, + 3, + 3 ); /***** LOCALE END ko_KR *****/ @@ -949,7 +1009,9 @@ MY_LOCALE my_locale_lt_LT &my_locale_typelib_month_names_lt_LT, &my_locale_typelib_ab_month_names_lt_LT, &my_locale_typelib_day_names_lt_LT, - &my_locale_typelib_ab_day_names_lt_LT + &my_locale_typelib_ab_day_names_lt_LT, + 9, + 14 ); /***** LOCALE END lt_LT *****/ @@ -979,7 +1041,9 @@ MY_LOCALE my_locale_lv_LV &my_locale_typelib_month_names_lv_LV, &my_locale_typelib_ab_month_names_lv_LV, &my_locale_typelib_day_names_lv_LV, - &my_locale_typelib_ab_day_names_lv_LV + &my_locale_typelib_ab_day_names_lv_LV, + 10, + 11 ); /***** LOCALE END lv_LV *****/ @@ -1009,7 +1073,9 @@ MY_LOCALE my_locale_mk_MK &my_locale_typelib_month_names_mk_MK, &my_locale_typelib_ab_month_names_mk_MK, &my_locale_typelib_day_names_mk_MK, - &my_locale_typelib_ab_day_names_mk_MK + &my_locale_typelib_ab_day_names_mk_MK, + 9, + 10 ); /***** LOCALE END mk_MK *****/ @@ -1039,7 +1105,9 @@ MY_LOCALE my_locale_mn_MN &my_locale_typelib_month_names_mn_MN, &my_locale_typelib_ab_month_names_mn_MN, &my_locale_typelib_day_names_mn_MN, - &my_locale_typelib_ab_day_names_mn_MN + &my_locale_typelib_ab_day_names_mn_MN, + 18, + 6 ); /***** LOCALE END mn_MN *****/ @@ -1069,7 +1137,9 @@ MY_LOCALE my_locale_ms_MY &my_locale_typelib_month_names_ms_MY, &my_locale_typelib_ab_month_names_ms_MY, &my_locale_typelib_day_names_ms_MY, - &my_locale_typelib_ab_day_names_ms_MY + &my_locale_typelib_ab_day_names_ms_MY, + 9, + 6 ); /***** LOCALE END ms_MY *****/ @@ -1099,7 +1169,9 @@ MY_LOCALE my_locale_nb_NO &my_locale_typelib_month_names_nb_NO, &my_locale_typelib_ab_month_names_nb_NO, &my_locale_typelib_day_names_nb_NO, - &my_locale_typelib_ab_day_names_nb_NO + &my_locale_typelib_ab_day_names_nb_NO, + 9, + 7 ); /***** LOCALE END nb_NO *****/ @@ -1129,7 +1201,9 @@ MY_LOCALE my_locale_nl_NL &my_locale_typelib_month_names_nl_NL, &my_locale_typelib_ab_month_names_nl_NL, &my_locale_typelib_day_names_nl_NL, - &my_locale_typelib_ab_day_names_nl_NL + &my_locale_typelib_ab_day_names_nl_NL, + 9, + 9 ); /***** LOCALE END nl_NL *****/ @@ -1159,7 +1233,9 @@ MY_LOCALE my_locale_pl_PL &my_locale_typelib_month_names_pl_PL, &my_locale_typelib_ab_month_names_pl_PL, &my_locale_typelib_day_names_pl_PL, - &my_locale_typelib_ab_day_names_pl_PL + &my_locale_typelib_ab_day_names_pl_PL, + 11, + 12 ); /***** LOCALE END pl_PL *****/ @@ -1189,7 +1265,9 @@ MY_LOCALE my_locale_pt_BR &my_locale_typelib_month_names_pt_BR, &my_locale_typelib_ab_month_names_pt_BR, &my_locale_typelib_day_names_pt_BR, - &my_locale_typelib_ab_day_names_pt_BR + &my_locale_typelib_ab_day_names_pt_BR, + 9, + 7 ); /***** LOCALE END pt_BR *****/ @@ -1219,7 +1297,9 @@ MY_LOCALE my_locale_pt_PT &my_locale_typelib_month_names_pt_PT, &my_locale_typelib_ab_month_names_pt_PT, &my_locale_typelib_day_names_pt_PT, - &my_locale_typelib_ab_day_names_pt_PT + &my_locale_typelib_ab_day_names_pt_PT, + 9, + 7 ); /***** LOCALE END pt_PT *****/ @@ -1249,7 +1329,9 @@ MY_LOCALE my_locale_ro_RO &my_locale_typelib_month_names_ro_RO, &my_locale_typelib_ab_month_names_ro_RO, &my_locale_typelib_day_names_ro_RO, - &my_locale_typelib_ab_day_names_ro_RO + &my_locale_typelib_ab_day_names_ro_RO, + 10, + 8 ); /***** LOCALE END ro_RO *****/ @@ -1279,7 +1361,9 @@ MY_LOCALE my_locale_ru_RU &my_locale_typelib_month_names_ru_RU, &my_locale_typelib_ab_month_names_ru_RU, &my_locale_typelib_day_names_ru_RU, - &my_locale_typelib_ab_day_names_ru_RU + &my_locale_typelib_ab_day_names_ru_RU, + 8, + 11 ); /***** LOCALE END ru_RU *****/ @@ -1309,7 +1393,9 @@ MY_LOCALE my_locale_ru_UA &my_locale_typelib_month_names_ru_UA, &my_locale_typelib_ab_month_names_ru_UA, &my_locale_typelib_day_names_ru_UA, - &my_locale_typelib_ab_day_names_ru_UA + &my_locale_typelib_ab_day_names_ru_UA, + 8, + 11 ); /***** LOCALE END ru_UA *****/ @@ -1339,7 +1425,9 @@ MY_LOCALE my_locale_sk_SK &my_locale_typelib_month_names_sk_SK, &my_locale_typelib_ab_month_names_sk_SK, &my_locale_typelib_day_names_sk_SK, - &my_locale_typelib_ab_day_names_sk_SK + &my_locale_typelib_ab_day_names_sk_SK, + 9, + 8 ); /***** LOCALE END sk_SK *****/ @@ -1369,7 +1457,9 @@ MY_LOCALE my_locale_sl_SI &my_locale_typelib_month_names_sl_SI, &my_locale_typelib_ab_month_names_sl_SI, &my_locale_typelib_day_names_sl_SI, - &my_locale_typelib_ab_day_names_sl_SI + &my_locale_typelib_ab_day_names_sl_SI, + 9, + 10 ); /***** LOCALE END sl_SI *****/ @@ -1399,7 +1489,9 @@ MY_LOCALE my_locale_sq_AL &my_locale_typelib_month_names_sq_AL, &my_locale_typelib_ab_month_names_sq_AL, &my_locale_typelib_day_names_sq_AL, - &my_locale_typelib_ab_day_names_sq_AL + &my_locale_typelib_ab_day_names_sq_AL, + 7, + 10 ); /***** LOCALE END sq_AL *****/ @@ -1429,7 +1521,9 @@ MY_LOCALE my_locale_sr_YU &my_locale_typelib_month_names_sr_YU, &my_locale_typelib_ab_month_names_sr_YU, &my_locale_typelib_day_names_sr_YU, - &my_locale_typelib_ab_day_names_sr_YU + &my_locale_typelib_ab_day_names_sr_YU, + 9, + 10 ); /***** LOCALE END sr_YU *****/ @@ -1459,7 +1553,9 @@ MY_LOCALE my_locale_sv_SE &my_locale_typelib_month_names_sv_SE, &my_locale_typelib_ab_month_names_sv_SE, &my_locale_typelib_day_names_sv_SE, - &my_locale_typelib_ab_day_names_sv_SE + &my_locale_typelib_ab_day_names_sv_SE, + 9, + 7 ); /***** LOCALE END sv_SE *****/ @@ -1489,7 +1585,9 @@ MY_LOCALE my_locale_ta_IN &my_locale_typelib_month_names_ta_IN, &my_locale_typelib_ab_month_names_ta_IN, &my_locale_typelib_day_names_ta_IN, - &my_locale_typelib_ab_day_names_ta_IN + &my_locale_typelib_ab_day_names_ta_IN, + 10, + 8 ); /***** LOCALE END ta_IN *****/ @@ -1519,7 +1617,9 @@ MY_LOCALE my_locale_te_IN &my_locale_typelib_month_names_te_IN, &my_locale_typelib_ab_month_names_te_IN, &my_locale_typelib_day_names_te_IN, - &my_locale_typelib_ab_day_names_te_IN + &my_locale_typelib_ab_day_names_te_IN, + 10, + 9 ); /***** LOCALE END te_IN *****/ @@ -1549,7 +1649,9 @@ MY_LOCALE my_locale_th_TH &my_locale_typelib_month_names_th_TH, &my_locale_typelib_ab_month_names_th_TH, &my_locale_typelib_day_names_th_TH, - &my_locale_typelib_ab_day_names_th_TH + &my_locale_typelib_ab_day_names_th_TH, + 10, + 8 ); /***** LOCALE END th_TH *****/ @@ -1579,7 +1681,9 @@ MY_LOCALE my_locale_tr_TR &my_locale_typelib_month_names_tr_TR, &my_locale_typelib_ab_month_names_tr_TR, &my_locale_typelib_day_names_tr_TR, - &my_locale_typelib_ab_day_names_tr_TR + &my_locale_typelib_ab_day_names_tr_TR, + 7, + 9 ); /***** LOCALE END tr_TR *****/ @@ -1609,7 +1713,9 @@ MY_LOCALE my_locale_uk_UA &my_locale_typelib_month_names_uk_UA, &my_locale_typelib_ab_month_names_uk_UA, &my_locale_typelib_day_names_uk_UA, - &my_locale_typelib_ab_day_names_uk_UA + &my_locale_typelib_ab_day_names_uk_UA, + 8, + 9 ); /***** LOCALE END uk_UA *****/ @@ -1639,7 +1745,9 @@ MY_LOCALE my_locale_ur_PK &my_locale_typelib_month_names_ur_PK, &my_locale_typelib_ab_month_names_ur_PK, &my_locale_typelib_day_names_ur_PK, - &my_locale_typelib_ab_day_names_ur_PK + &my_locale_typelib_ab_day_names_ur_PK, + 6, + 6 ); /***** LOCALE END ur_PK *****/ @@ -1669,7 +1777,9 @@ MY_LOCALE my_locale_vi_VN &my_locale_typelib_month_names_vi_VN, &my_locale_typelib_ab_month_names_vi_VN, &my_locale_typelib_day_names_vi_VN, - &my_locale_typelib_ab_day_names_vi_VN + &my_locale_typelib_ab_day_names_vi_VN, + 16, + 11 ); /***** LOCALE END vi_VN *****/ @@ -1699,7 +1809,9 @@ MY_LOCALE my_locale_zh_CN &my_locale_typelib_month_names_zh_CN, &my_locale_typelib_ab_month_names_zh_CN, &my_locale_typelib_day_names_zh_CN, - &my_locale_typelib_ab_day_names_zh_CN + &my_locale_typelib_ab_day_names_zh_CN, + 3, + 3 ); /***** LOCALE END zh_CN *****/ @@ -1729,7 +1841,9 @@ MY_LOCALE my_locale_zh_TW &my_locale_typelib_month_names_zh_TW, &my_locale_typelib_ab_month_names_zh_TW, &my_locale_typelib_day_names_zh_TW, - &my_locale_typelib_ab_day_names_zh_TW + &my_locale_typelib_ab_day_names_zh_TW, + 3, + 2 ); /***** LOCALE END zh_TW *****/ @@ -1743,7 +1857,9 @@ MY_LOCALE my_locale_ar_DZ &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, - &my_locale_typelib_ab_day_names_ar_BH + &my_locale_typelib_ab_day_names_ar_BH, + 6, + 8 ); /***** LOCALE END ar_DZ *****/ @@ -1757,7 +1873,9 @@ MY_LOCALE my_locale_ar_EG &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, - &my_locale_typelib_ab_day_names_ar_BH + &my_locale_typelib_ab_day_names_ar_BH, + 6, + 8 ); /***** LOCALE END ar_EG *****/ @@ -1771,7 +1889,9 @@ MY_LOCALE my_locale_ar_IN &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, - &my_locale_typelib_ab_day_names_ar_BH + &my_locale_typelib_ab_day_names_ar_BH, + 6, + 8 ); /***** LOCALE END ar_IN *****/ @@ -1785,7 +1905,9 @@ MY_LOCALE my_locale_ar_IQ &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, - &my_locale_typelib_ab_day_names_ar_BH + &my_locale_typelib_ab_day_names_ar_BH, + 6, + 8 ); /***** LOCALE END ar_IQ *****/ @@ -1799,7 +1921,9 @@ MY_LOCALE my_locale_ar_KW &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, - &my_locale_typelib_ab_day_names_ar_BH + &my_locale_typelib_ab_day_names_ar_BH, + 6, + 8 ); /***** LOCALE END ar_KW *****/ @@ -1813,7 +1937,9 @@ MY_LOCALE my_locale_ar_LB &my_locale_typelib_month_names_ar_JO, &my_locale_typelib_ab_month_names_ar_JO, &my_locale_typelib_day_names_ar_JO, - &my_locale_typelib_ab_day_names_ar_JO + &my_locale_typelib_ab_day_names_ar_JO, + 12, + 8 ); /***** LOCALE END ar_LB *****/ @@ -1827,7 +1953,9 @@ MY_LOCALE my_locale_ar_LY &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, - &my_locale_typelib_ab_day_names_ar_BH + &my_locale_typelib_ab_day_names_ar_BH, + 6, + 8 ); /***** LOCALE END ar_LY *****/ @@ -1841,7 +1969,9 @@ MY_LOCALE my_locale_ar_MA &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, - &my_locale_typelib_ab_day_names_ar_BH + &my_locale_typelib_ab_day_names_ar_BH, + 6, + 8 ); /***** LOCALE END ar_MA *****/ @@ -1855,7 +1985,9 @@ MY_LOCALE my_locale_ar_OM &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, - &my_locale_typelib_ab_day_names_ar_BH + &my_locale_typelib_ab_day_names_ar_BH, + 6, + 8 ); /***** LOCALE END ar_OM *****/ @@ -1869,7 +2001,9 @@ MY_LOCALE my_locale_ar_QA &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, - &my_locale_typelib_ab_day_names_ar_BH + &my_locale_typelib_ab_day_names_ar_BH, + 6, + 8 ); /***** LOCALE END ar_QA *****/ @@ -1883,7 +2017,9 @@ MY_LOCALE my_locale_ar_SD &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, - &my_locale_typelib_ab_day_names_ar_BH + &my_locale_typelib_ab_day_names_ar_BH, + 6, + 8 ); /***** LOCALE END ar_SD *****/ @@ -1897,7 +2033,9 @@ MY_LOCALE my_locale_ar_TN &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, - &my_locale_typelib_ab_day_names_ar_BH + &my_locale_typelib_ab_day_names_ar_BH, + 6, + 8 ); /***** LOCALE END ar_TN *****/ @@ -1911,7 +2049,9 @@ MY_LOCALE my_locale_ar_YE &my_locale_typelib_month_names_ar_BH, &my_locale_typelib_ab_month_names_ar_BH, &my_locale_typelib_day_names_ar_BH, - &my_locale_typelib_ab_day_names_ar_BH + &my_locale_typelib_ab_day_names_ar_BH, + 6, + 8 ); /***** LOCALE END ar_YE *****/ @@ -1925,7 +2065,9 @@ MY_LOCALE my_locale_de_BE &my_locale_typelib_month_names_de_DE, &my_locale_typelib_ab_month_names_de_DE, &my_locale_typelib_day_names_de_DE, - &my_locale_typelib_ab_day_names_de_DE + &my_locale_typelib_ab_day_names_de_DE, + 9, + 10 ); /***** LOCALE END de_BE *****/ @@ -1939,7 +2081,9 @@ MY_LOCALE my_locale_de_CH &my_locale_typelib_month_names_de_DE, &my_locale_typelib_ab_month_names_de_DE, &my_locale_typelib_day_names_de_DE, - &my_locale_typelib_ab_day_names_de_DE + &my_locale_typelib_ab_day_names_de_DE, + 9, + 10 ); /***** LOCALE END de_CH *****/ @@ -1953,7 +2097,9 @@ MY_LOCALE my_locale_de_LU &my_locale_typelib_month_names_de_DE, &my_locale_typelib_ab_month_names_de_DE, &my_locale_typelib_day_names_de_DE, - &my_locale_typelib_ab_day_names_de_DE + &my_locale_typelib_ab_day_names_de_DE, + 9, + 10 ); /***** LOCALE END de_LU *****/ @@ -1967,7 +2113,9 @@ MY_LOCALE my_locale_en_AU &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, - &my_locale_typelib_ab_day_names_en_US + &my_locale_typelib_ab_day_names_en_US, + 9, + 9 ); /***** LOCALE END en_AU *****/ @@ -1981,7 +2129,9 @@ MY_LOCALE my_locale_en_CA &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, - &my_locale_typelib_ab_day_names_en_US + &my_locale_typelib_ab_day_names_en_US, + 9, + 9 ); /***** LOCALE END en_CA *****/ @@ -1995,7 +2145,9 @@ MY_LOCALE my_locale_en_GB &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, - &my_locale_typelib_ab_day_names_en_US + &my_locale_typelib_ab_day_names_en_US, + 9, + 9 ); /***** LOCALE END en_GB *****/ @@ -2009,7 +2161,9 @@ MY_LOCALE my_locale_en_IN &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, - &my_locale_typelib_ab_day_names_en_US + &my_locale_typelib_ab_day_names_en_US, + 9, + 9 ); /***** LOCALE END en_IN *****/ @@ -2023,7 +2177,9 @@ MY_LOCALE my_locale_en_NZ &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, - &my_locale_typelib_ab_day_names_en_US + &my_locale_typelib_ab_day_names_en_US, + 9, + 9 ); /***** LOCALE END en_NZ *****/ @@ -2037,7 +2193,9 @@ MY_LOCALE my_locale_en_PH &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, - &my_locale_typelib_ab_day_names_en_US + &my_locale_typelib_ab_day_names_en_US, + 9, + 9 ); /***** LOCALE END en_PH *****/ @@ -2051,7 +2209,9 @@ MY_LOCALE my_locale_en_ZA &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, - &my_locale_typelib_ab_day_names_en_US + &my_locale_typelib_ab_day_names_en_US, + 9, + 9 ); /***** LOCALE END en_ZA *****/ @@ -2065,7 +2225,9 @@ MY_LOCALE my_locale_en_ZW &my_locale_typelib_month_names_en_US, &my_locale_typelib_ab_month_names_en_US, &my_locale_typelib_day_names_en_US, - &my_locale_typelib_ab_day_names_en_US + &my_locale_typelib_ab_day_names_en_US, + 9, + 9 ); /***** LOCALE END en_ZW *****/ @@ -2079,7 +2241,9 @@ MY_LOCALE my_locale_es_AR &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_AR *****/ @@ -2093,7 +2257,9 @@ MY_LOCALE my_locale_es_BO &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_BO *****/ @@ -2107,7 +2273,9 @@ MY_LOCALE my_locale_es_CL &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_CL *****/ @@ -2121,7 +2289,9 @@ MY_LOCALE my_locale_es_CO &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_CO *****/ @@ -2135,7 +2305,9 @@ MY_LOCALE my_locale_es_CR &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_CR *****/ @@ -2149,7 +2321,9 @@ MY_LOCALE my_locale_es_DO &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_DO *****/ @@ -2163,7 +2337,9 @@ MY_LOCALE my_locale_es_EC &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_EC *****/ @@ -2177,7 +2353,9 @@ MY_LOCALE my_locale_es_GT &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_GT *****/ @@ -2191,7 +2369,9 @@ MY_LOCALE my_locale_es_HN &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_HN *****/ @@ -2205,7 +2385,9 @@ MY_LOCALE my_locale_es_MX &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_MX *****/ @@ -2219,7 +2401,9 @@ MY_LOCALE my_locale_es_NI &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_NI *****/ @@ -2233,7 +2417,9 @@ MY_LOCALE my_locale_es_PA &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_PA *****/ @@ -2247,7 +2433,9 @@ MY_LOCALE my_locale_es_PE &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_PE *****/ @@ -2261,7 +2449,9 @@ MY_LOCALE my_locale_es_PR &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_PR *****/ @@ -2275,7 +2465,9 @@ MY_LOCALE my_locale_es_PY &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_PY *****/ @@ -2289,7 +2481,9 @@ MY_LOCALE my_locale_es_SV &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_SV *****/ @@ -2303,7 +2497,9 @@ MY_LOCALE my_locale_es_US &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_US *****/ @@ -2317,7 +2513,9 @@ MY_LOCALE my_locale_es_UY &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_UY *****/ @@ -2331,7 +2529,9 @@ MY_LOCALE my_locale_es_VE &my_locale_typelib_month_names_es_ES, &my_locale_typelib_ab_month_names_es_ES, &my_locale_typelib_day_names_es_ES, - &my_locale_typelib_ab_day_names_es_ES + &my_locale_typelib_ab_day_names_es_ES, + 10, + 9 ); /***** LOCALE END es_VE *****/ @@ -2345,7 +2545,9 @@ MY_LOCALE my_locale_fr_BE &my_locale_typelib_month_names_fr_FR, &my_locale_typelib_ab_month_names_fr_FR, &my_locale_typelib_day_names_fr_FR, - &my_locale_typelib_ab_day_names_fr_FR + &my_locale_typelib_ab_day_names_fr_FR, + 9, + 8 ); /***** LOCALE END fr_BE *****/ @@ -2359,7 +2561,9 @@ MY_LOCALE my_locale_fr_CA &my_locale_typelib_month_names_fr_FR, &my_locale_typelib_ab_month_names_fr_FR, &my_locale_typelib_day_names_fr_FR, - &my_locale_typelib_ab_day_names_fr_FR + &my_locale_typelib_ab_day_names_fr_FR, + 9, + 8 ); /***** LOCALE END fr_CA *****/ @@ -2373,7 +2577,9 @@ MY_LOCALE my_locale_fr_CH &my_locale_typelib_month_names_fr_FR, &my_locale_typelib_ab_month_names_fr_FR, &my_locale_typelib_day_names_fr_FR, - &my_locale_typelib_ab_day_names_fr_FR + &my_locale_typelib_ab_day_names_fr_FR, + 9, + 8 ); /***** LOCALE END fr_CH *****/ @@ -2387,7 +2593,9 @@ MY_LOCALE my_locale_fr_LU &my_locale_typelib_month_names_fr_FR, &my_locale_typelib_ab_month_names_fr_FR, &my_locale_typelib_day_names_fr_FR, - &my_locale_typelib_ab_day_names_fr_FR + &my_locale_typelib_ab_day_names_fr_FR, + 9, + 8 ); /***** LOCALE END fr_LU *****/ @@ -2401,7 +2609,9 @@ MY_LOCALE my_locale_it_IT &my_locale_typelib_month_names_it_CH, &my_locale_typelib_ab_month_names_it_CH, &my_locale_typelib_day_names_it_CH, - &my_locale_typelib_ab_day_names_it_CH + &my_locale_typelib_ab_day_names_it_CH, + 9, + 9 ); /***** LOCALE END it_IT *****/ @@ -2415,7 +2625,9 @@ MY_LOCALE my_locale_nl_BE &my_locale_typelib_month_names_nl_NL, &my_locale_typelib_ab_month_names_nl_NL, &my_locale_typelib_day_names_nl_NL, - &my_locale_typelib_ab_day_names_nl_NL + &my_locale_typelib_ab_day_names_nl_NL, + 9, + 9 ); /***** LOCALE END nl_BE *****/ @@ -2429,7 +2641,9 @@ MY_LOCALE my_locale_no_NO &my_locale_typelib_month_names_nb_NO, &my_locale_typelib_ab_month_names_nb_NO, &my_locale_typelib_day_names_nb_NO, - &my_locale_typelib_ab_day_names_nb_NO + &my_locale_typelib_ab_day_names_nb_NO, + 9, + 7 ); /***** LOCALE END no_NO *****/ @@ -2443,7 +2657,9 @@ MY_LOCALE my_locale_sv_FI &my_locale_typelib_month_names_sv_SE, &my_locale_typelib_ab_month_names_sv_SE, &my_locale_typelib_day_names_sv_SE, - &my_locale_typelib_ab_day_names_sv_SE + &my_locale_typelib_ab_day_names_sv_SE, + 9, + 7 ); /***** LOCALE END sv_FI *****/ @@ -2457,7 +2673,9 @@ MY_LOCALE my_locale_zh_HK &my_locale_typelib_month_names_zh_CN, &my_locale_typelib_ab_month_names_zh_CN, &my_locale_typelib_day_names_zh_CN, - &my_locale_typelib_ab_day_names_zh_CN + &my_locale_typelib_ab_day_names_zh_CN, + 3, + 3 ); /***** LOCALE END zh_HK *****/ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 91c5cacc4d0..dafe4baa9e5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2333,8 +2333,9 @@ void log_slow_statement(THD *thd) { thd->proc_info="logging slow query"; - if ((ulong) (thd->start_time - thd->time_after_lock) > - thd->variables.long_query_time || + if ((thd->start_time > thd->time_after_lock && + (ulong) (thd->start_time - thd->time_after_lock) > + thd->variables.long_query_time) || (thd->server_status & (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && opt_log_queries_not_using_indexes && @@ -2583,6 +2584,10 @@ mysql_execute_command(THD *thd) TABLE_LIST *all_tables; /* most outer SELECT_LEX_UNIT of query */ SELECT_LEX_UNIT *unit= &lex->unit; +#ifdef HAVE_REPLICATION + /* have table map for update for multi-update statement (BUG#37051) */ + bool have_table_map_for_update= FALSE; +#endif /* Saved variable value */ DBUG_ENTER("mysql_execute_command"); thd->net.no_send_error= 0; @@ -2662,6 +2667,48 @@ mysql_execute_command(THD *thd) // force searching in slave.cc:tables_ok() all_tables->updating= 1; } + + /* + For fix of BUG#37051, the master stores the table map for update + in the Query_log_event, and the value is assigned to + thd->variables.table_map_for_update before executing the update + query. + + If thd->variables.table_map_for_update is set, then we are + replicating from a new master, we can use this value to apply + filter rules without opening all the tables. However If + thd->variables.table_map_for_update is not set, then we are + replicating from an old master, so we just skip this and + continue with the old method. And of course, the bug would still + exist for old masters. + */ + if (lex->sql_command == SQLCOM_UPDATE_MULTI && + thd->table_map_for_update) + { + have_table_map_for_update= TRUE; + table_map table_map_for_update= thd->table_map_for_update; + uint nr= 0; + TABLE_LIST *table; + for (table=all_tables; table; table=table->next_global, nr++) + { + if (table_map_for_update & ((table_map)1 << nr)) + table->updating= TRUE; + else + table->updating= FALSE; + } + + if (all_tables_not_ok(thd, all_tables)) + { + /* we warn the slave SQL thread */ + my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); + if (thd->one_shot_set) + reset_one_shot_variables(thd); + DBUG_RETURN(0); + } + + for (table=all_tables; table; table=table->next_global) + table->updating= TRUE; + } /* Check if statment should be skipped because of slave filtering @@ -3607,7 +3654,7 @@ end_with_restore_list: #ifdef HAVE_REPLICATION /* Check slave filtering rules */ - if (unlikely(thd->slave_thread)) + if (unlikely(thd->slave_thread && !have_table_map_for_update)) { if (all_tables_not_ok(thd, all_tables)) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 428d1709f94..a820e9966dc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -78,7 +78,6 @@ static store_key *get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables, KEY_PART_INFO *key_part, char *key_buff, uint maybe_null); -static bool make_simple_join(JOIN *join,TABLE *tmp_table); static void make_outerjoin_info(JOIN *join); static bool make_join_select(JOIN *join,SQL_SELECT *select,COND *item); static void make_join_readinfo(JOIN *join, ulonglong options); @@ -100,7 +99,7 @@ static COND* substitute_for_best_equal_field(COND *cond, void *table_join_idx); static COND *simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top); -static bool check_interleaving_with_nj(JOIN_TAB *last, JOIN_TAB *next); +static bool check_interleaving_with_nj(JOIN_TAB *next); static void restore_prev_nj_state(JOIN_TAB *last); static void reset_nj_counters(List<TABLE_LIST> *join_list); static uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list, @@ -390,11 +389,21 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array, { int res; nesting_map save_allow_sum_func=thd->lex->allow_sum_func ; + /* + Need to save the value, so we can turn off only the new NON_AGG_FIELD + additions coming from the WHERE + */ + uint8 saved_flag= thd->lex->current_select->full_group_by_flag; DBUG_ENTER("setup_without_group"); thd->lex->allow_sum_func&= ~(1 << thd->lex->current_select->nest_level); res= setup_conds(thd, tables, leaves, conds); + /* it's not wrong to have non-aggregated columns in a WHERE */ + if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) + thd->lex->current_select->full_group_by_flag= saved_flag | + (thd->lex->current_select->full_group_by_flag & ~NON_AGG_FIELD_USED); + thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level; res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields, order); @@ -1589,14 +1598,22 @@ JOIN::exec() (zero_result_cause?zero_result_cause:"No tables used")); else { - result->send_fields(*columns_list, - Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); + if (result->send_fields(*columns_list, + Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) + { + DBUG_VOID_RETURN; + } /* We have to test for 'conds' here as the WHERE may not be constant even if we don't have any tables for prepared statements or if conds uses something like 'rand()'. + If the HAVING clause is either impossible or always true, then + JOIN::having is set to NULL by optimize_cond. + In this case JOIN::exec must check for JOIN::having_value, in the + same way it checks for JOIN::cond_value. */ if (cond_value != Item::COND_FALSE && + having_value != Item::COND_FALSE && (!conds || conds->val_int()) && (!having || having->val_int())) { @@ -1791,7 +1808,7 @@ JOIN::exec() /* Free first data from old join */ curr_join->join_free(); - if (make_simple_join(curr_join, curr_tmp_table)) + if (curr_join->make_simple_join(this, curr_tmp_table)) DBUG_VOID_RETURN; calc_group_buffer(curr_join, group_list); count_field_types(select_lex, &curr_join->tmp_table_param, @@ -1911,7 +1928,7 @@ JOIN::exec() curr_join->select_distinct=0; } curr_tmp_table->reginfo.lock_type= TL_UNLOCK; - if (make_simple_join(curr_join, curr_tmp_table)) + if (curr_join->make_simple_join(this, curr_tmp_table)) DBUG_VOID_RETURN; calc_group_buffer(curr_join, curr_join->group_list); count_field_types(select_lex, &curr_join->tmp_table_param, @@ -2356,11 +2373,12 @@ typedef struct st_sargable_param */ static bool -make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, +make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, DYNAMIC_ARRAY *keyuse_array) { int error; TABLE *table; + TABLE_LIST *tables= tables_arg; uint i,table_count,const_count,key; table_map found_const_table_map, all_table_map, found_ref, refs; key_map const_ref, eq_part; @@ -2398,10 +2416,10 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, table_vector[i]=s->table=table=tables->table; table->pos_in_table_list= tables; error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); - if(error) + if (error) { - table->file->print_error(error, MYF(0)); - DBUG_RETURN(1); + table->file->print_error(error, MYF(0)); + goto error; } table->quick_keys.clear_all(); table->reginfo.join_tab=s; @@ -2476,7 +2494,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, if (s->dependent & table->map) s->dependent |= table->reginfo.join_tab->dependent; } - if (s->dependent) + if (outer_join & s->table->map) s->table->maybe_null= 1; } /* Catch illegal cross references for outer joins */ @@ -2486,7 +2504,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, { join->tables=0; // Don't use join->table my_message(ER_WRONG_OUTER_JOIN, ER(ER_WRONG_OUTER_JOIN), MYF(0)); - DBUG_RETURN(1); + goto error; } s->key_dependent= s->dependent; } @@ -2496,7 +2514,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, if (update_ref_and_keys(join->thd, keyuse_array, stat, join->tables, conds, join->cond_equal, ~outer_join, join->select_lex, &sargables)) - DBUG_RETURN(1); + goto error; /* Read tables with 0 or 1 rows (system tables) */ join->const_table_map= 0; @@ -2512,7 +2530,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, if ((tmp=join_read_const_table(s, p_pos))) { if (tmp > 0) - DBUG_RETURN(1); // Fatal error + goto error; // Fatal error } else found_const_table_map|= s->table->map; @@ -2584,7 +2602,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, if ((tmp= join_read_const_table(s, join->positions+const_count-1))) { if (tmp > 0) - DBUG_RETURN(1); // Fatal error + goto error; // Fatal error } else found_const_table_map|= table->map; @@ -2633,12 +2651,12 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, set_position(join,const_count++,s,start_keyuse); if (create_ref_for_key(join, s, start_keyuse, found_const_table_map)) - DBUG_RETURN(1); + goto error; if ((tmp=join_read_const_table(s, join->positions+const_count-1))) { if (tmp > 0) - DBUG_RETURN(1); // Fatal error + goto error; // Fatal error } else found_const_table_map|= table->map; @@ -2715,7 +2733,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, *s->on_expr_ref ? *s->on_expr_ref : conds, 1, &error); if (!select) - DBUG_RETURN(1); + goto error; records= get_quick_record_count(join->thd, select, s->table, &s->const_keys, join->row_limit); s->quick=select->quick; @@ -2761,7 +2779,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, { optimize_keyuse(join, keyuse_array); if (choose_plan(join, all_table_map & ~join->const_table_map)) - DBUG_RETURN(TRUE); + goto error; } else { @@ -2771,6 +2789,17 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, } /* Generate an execution plan from the found optimal join order. */ DBUG_RETURN(join->thd->killed || get_best_combination(join)); + +error: + /* + Need to clean up join_tab from TABLEs in case of error. + They won't get cleaned up by JOIN::cleanup() because JOIN::join_tab + may not be assigned yet by this function (which is building join_tab). + Dangling TABLE::reginfo.join_tab may cause part_of_refkey to choke. + */ + for (tables= tables_arg; tables; tables= tables->next_leaf) + tables->table->reginfo.join_tab= NULL; + DBUG_RETURN (1); } @@ -4705,6 +4734,18 @@ greedy_search(JOIN *join, */ join->positions[idx]= best_pos; + /* + Update the interleaving state after extending the current partial plan + with a new table. + We are doing this here because best_extension_by_limited_search reverts + the interleaving state to the one of the non-extended partial plan + on exit. + */ + IF_DBUG(bool is_interleave_error= ) + check_interleaving_with_nj (best_table); + /* This has been already checked by best_extension_by_limited_search */ + DBUG_ASSERT(!is_interleave_error); + /* find the position of 'best_table' in 'join->best_ref' */ best_idx= idx; JOIN_TAB *pos= join->best_ref[best_idx]; @@ -4722,7 +4763,7 @@ greedy_search(JOIN *join, --size_remain; ++idx; - DBUG_EXECUTE("opt", print_plan(join, join->tables, + DBUG_EXECUTE("opt", print_plan(join, idx, record_count, read_time, read_time, "extended");); } while (TRUE); @@ -4873,7 +4914,7 @@ best_extension_by_limited_search(JOIN *join, table_map real_table_bit= s->table->map; if ((remaining_tables & real_table_bit) && !(remaining_tables & s->dependent) && - (!idx || !check_interleaving_with_nj(join->positions[idx-1].table, s))) + (!idx || !check_interleaving_with_nj(s))) { double current_record_count, current_read_time; @@ -5018,7 +5059,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, { table_map real_table_bit=s->table->map; if ((rest_tables & real_table_bit) && !(rest_tables & s->dependent) && - (!idx|| !check_interleaving_with_nj(join->positions[idx-1].table, s))) + (!idx|| !check_interleaving_with_nj(s))) { double records, best; best_access_path(join, s, thd, rest_tables, idx, record_count, @@ -5401,48 +5442,42 @@ store_val_in_field(Field *field, Item *item, enum_check_fields check_flag) } -static bool -make_simple_join(JOIN *join,TABLE *tmp_table) +/** + @details Initialize a JOIN as a query execution plan + that accesses a single table via a table scan. + + @param parent contains JOIN_TAB and TABLE object buffers for this join + @param tmp_table temporary table + + @retval FALSE success + @retval TRUE error occurred +*/ +bool +JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table) { - TABLE **tableptr; - JOIN_TAB *join_tab; - DBUG_ENTER("make_simple_join"); + DBUG_ENTER("JOIN::make_simple_join"); /* Reuse TABLE * and JOIN_TAB if already allocated by a previous call to this function through JOIN::exec (may happen for sub-queries). */ - if (!join->table_reexec) - { - if (!(join->table_reexec= (TABLE**) join->thd->alloc(sizeof(TABLE*)))) - DBUG_RETURN(TRUE); /* purecov: inspected */ - if (join->tmp_join) - join->tmp_join->table_reexec= join->table_reexec; - } - if (!join->join_tab_reexec) - { - if (!(join->join_tab_reexec= - (JOIN_TAB*) join->thd->alloc(sizeof(JOIN_TAB)))) - DBUG_RETURN(TRUE); /* purecov: inspected */ - if (join->tmp_join) - join->tmp_join->join_tab_reexec= join->join_tab_reexec; - } - tableptr= join->table_reexec; - join_tab= join->join_tab_reexec; - - join->join_tab=join_tab; - join->table=tableptr; tableptr[0]=tmp_table; - join->tables=1; - join->const_tables=0; - join->const_table_map=0; - join->tmp_table_param.field_count= join->tmp_table_param.sum_func_count= - join->tmp_table_param.func_count=0; - join->tmp_table_param.copy_field=join->tmp_table_param.copy_field_end=0; - join->first_record=join->sort_and_group=0; - join->send_records=(ha_rows) 0; - join->group=0; - join->row_limit=join->unit->select_limit_cnt; - join->do_send_rows = (join->row_limit) ? 1 : 0; + if (!parent->join_tab_reexec && + !(parent->join_tab_reexec= (JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB)))) + DBUG_RETURN(TRUE); /* purecov: inspected */ + + join_tab= parent->join_tab_reexec; + table= &parent->table_reexec[0]; parent->table_reexec[0]= tmp_table; + tables= 1; + const_tables= 0; + const_table_map= 0; + tmp_table_param.field_count= tmp_table_param.sum_func_count= + tmp_table_param.func_count= 0; + tmp_table_param.copy_field= tmp_table_param.copy_field_end=0; + first_record= sort_and_group=0; + send_records= (ha_rows) 0; + group= 0; + row_limit= unit->select_limit_cnt; + do_send_rows= row_limit ? 1 : 0; join_tab->cache.buff=0; /* No caching */ join_tab->table=tmp_table; @@ -5459,7 +5494,7 @@ make_simple_join(JOIN *join,TABLE *tmp_table) join_tab->ref.key = -1; join_tab->not_used_in_distinct=0; join_tab->read_first_record= join_init_read_record; - join_tab->join=join; + join_tab->join= this; join_tab->ref.key_parts= 0; bzero((char*) &join_tab->read_record,sizeof(join_tab->read_record)); tmp_table->status=0; @@ -8390,9 +8425,6 @@ static void reset_nj_counters(List<TABLE_LIST> *join_list) SYNOPSIS check_interleaving_with_nj() - join Join being processed - last_tab Last table in current partial join order (this function is - not called for empty partial join orders) next_tab Table we're going to extend the current partial join with DESCRIPTION @@ -8477,10 +8509,10 @@ static void reset_nj_counters(List<TABLE_LIST> *join_list) TRUE Requested join order extension not allowed. */ -static bool check_interleaving_with_nj(JOIN_TAB *last_tab, JOIN_TAB *next_tab) +static bool check_interleaving_with_nj(JOIN_TAB *next_tab) { TABLE_LIST *next_emb= next_tab->table->pos_in_table_list->embedding; - JOIN *join= last_tab->join; + JOIN *join= next_tab->join; if (join->cur_embedding_map & ~next_tab->embedding_map) { @@ -9434,11 +9466,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, } if (type == Item::SUM_FUNC_ITEM && !group && !save_sum_fields) { /* Can't calc group yet */ - ((Item_sum*) item)->result_field=0; - for (i=0 ; i < ((Item_sum*) item)->arg_count ; i++) + Item_sum *sum_item= (Item_sum *) item; + sum_item->result_field=0; + for (i=0 ; i < sum_item->get_arg_count() ; i++) { - Item **argp= ((Item_sum*) item)->args + i; - Item *arg= *argp; + Item *arg= sum_item->get_arg(i); if (!arg->const_item()) { uint field_index= (uint) (reg_field - table->field); @@ -9468,7 +9500,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, string_total_length+= new_field->pack_length(); } thd->mem_root= mem_root_save; - thd->change_item_tree(argp, new Item_field(new_field)); + arg= sum_item->set_arg(i, thd, new Item_field(new_field)); thd->mem_root= &table->mem_root; if (!(new_field->flags & NOT_NULL_FLAG)) { @@ -9477,7 +9509,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, new_field->maybe_null() is still false, it will be changed below. But we have to setup Item_field correctly */ - (*argp)->maybe_null=1; + arg->maybe_null=1; } new_field->query_id= thd->query_id; } @@ -13223,6 +13255,7 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count) length=0; for (i=0 ; i < table_count ; i++) { + bool have_bit_fields= FALSE; uint null_fields=0,used_fields; Field **f_ptr,*field; @@ -13237,13 +13270,16 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count) length+=field->fill_cache_field(copy); if (copy->blob_field) (*blob_ptr++)=copy; - if (field->maybe_null()) + if (field->real_maybe_null()) null_fields++; + if (field->type() == MYSQL_TYPE_BIT && + ((Field_bit*)field)->bit_len) + have_bit_fields= TRUE; copy++; } } /* Copy null bits from table */ - if (null_fields && tables[i].table->s->null_fields) + if (null_fields || have_bit_fields) { /* must copy null bits */ copy->str=(char*) tables[i].table->null_flags; copy->length= tables[i].table->s->null_bytes; @@ -13908,9 +13944,9 @@ count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param, param->quick_group=0; // UDF SUM function param->sum_func_count++; - for (uint i=0 ; i < sum_item->arg_count ; i++) + for (uint i=0 ; i < sum_item->get_arg_count() ; i++) { - if (sum_item->args[0]->real_item()->type() == Item::FIELD_ITEM) + if (sum_item->get_arg(i)->real_item()->type() == Item::FIELD_ITEM) param->field_count++; else param->func_count++; diff --git a/sql/sql_select.h b/sql/sql_select.h index c2f0780f5be..75a905043d2 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -235,7 +235,11 @@ public: fetching data from a cursor */ bool resume_nested_loop; - table_map const_table_map,found_const_table_map,outer_join; + table_map const_table_map,found_const_table_map; + /* + Bitmap of all inner tables from outer joins + */ + table_map outer_join; ha_rows send_records,found_records,examined_rows,row_limit, select_limit; /* Used to fetch no more than given amount of rows per one @@ -348,9 +352,12 @@ public: cleared only at the end of the execution of the whole query and not caching allocations that occur in repetition at execution time will result in excessive memory usage. + Note: make_simple_join always creates an execution plan that accesses + a single table, thus it is sufficient to have a one-element array for + table_reexec. */ SORT_FIELD *sortorder; // make_unireg_sortorder() - TABLE **table_reexec; // make_simple_join() + TABLE *table_reexec[1]; // make_simple_join() JOIN_TAB *join_tab_reexec; // make_simple_join() /* end of allocation caching storage */ @@ -380,7 +387,7 @@ public: exec_tmp_table1= 0; exec_tmp_table2= 0; sortorder= 0; - table_reexec= 0; + table_reexec[0]= 0; join_tab_reexec= 0; thd= thd_arg; sum_funcs= sum_funcs2= 0; @@ -472,6 +479,8 @@ public: return (unit == &thd->lex->unit && (unit->fake_select_lex == 0 || select_lex == unit->fake_select_lex)); } +private: + bool make_simple_join(JOIN *join, TABLE *tmp_table); }; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5a4772e9847..a3ccf770a3c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -44,7 +44,7 @@ static void append_algorithm(TABLE_LIST *table, String *buff); static int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff); -static bool schema_table_store_record(THD *thd, TABLE *table); +bool schema_table_store_record(THD *thd, TABLE *table); /*************************************************************************** @@ -106,7 +106,7 @@ static struct show_privileges_st sys_privileges[]= {"Alter", "Tables", "To alter the table"}, {"Alter routine", "Functions,Procedures", "To alter or drop stored functions/procedures"}, {"Create", "Databases,Tables,Indexes", "To create new databases and tables"}, - {"Create routine","Functions,Procedures","To use CREATE FUNCTION/PROCEDURE"}, + {"Create routine","Databases","To use CREATE FUNCTION/PROCEDURE"}, {"Create temporary tables","Databases","To use CREATE TEMPORARY TABLE"}, {"Create view", "Tables", "To create new views"}, {"Create user", "Server Admin", "To create new users"}, @@ -287,11 +287,18 @@ find_files(THD *thd, List<char> *files, const char *db, #ifndef NO_EMBEDDED_ACCESS_CHECKS uint col_access=thd->col_access; #endif + uint wild_length= 0; TABLE_LIST table_list; DBUG_ENTER("find_files"); - if (wild && !wild[0]) - wild=0; + if (wild) + { + if (!wild[0]) + wild= 0; + else + wild_length= strlen(wild); + } + bzero((char*) &table_list,sizeof(table_list)); @@ -340,8 +347,11 @@ find_files(THD *thd, List<char> *files, const char *db, { if (lower_case_table_names) { - if (wild_case_compare(files_charset_info, file->name, wild)) - continue; + if (my_wildcmp(files_charset_info, + file->name, file->name + strlen(file->name), + wild, wild + wild_length, + wild_prefix, wild_one,wild_many)) + continue; } else if (wild_compare(file->name,wild,0)) continue; @@ -798,7 +808,7 @@ static bool get_field_default_value(THD *thd, TABLE *table, { bool has_default; bool has_now_default; - + enum enum_field_types field_type= field->type(); /* We are using CURRENT_TIMESTAMP instead of NOW because it is more standard @@ -806,7 +816,7 @@ static bool get_field_default_value(THD *thd, TABLE *table, has_now_default= table->timestamp_field == field && field->unireg_check != Field::TIMESTAMP_UN_FIELD; - has_default= (field->type() != FIELD_TYPE_BLOB && + has_default= (field_type != FIELD_TYPE_BLOB && !(field->flags & NO_DEFAULT_VALUE_FLAG) && field->unireg_check != Field::NEXT_NUMBER && !((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) @@ -821,7 +831,19 @@ static bool get_field_default_value(THD *thd, TABLE *table, { // Not null by default char tmp[MAX_FIELD_WIDTH]; String type(tmp, sizeof(tmp), field->charset()); - field->val_str(&type); + if (field_type == MYSQL_TYPE_BIT) + { + longlong dec= field->val_int(); + char *ptr= longlong2str(dec, tmp + 2, 2); + uint32 length= (uint32) (ptr - tmp); + tmp[0]= 'b'; + tmp[1]= '\''; + tmp[length]= '\''; + type.length(length + 1); + quoted= 0; + } + else + field->val_str(&type); if (type.length()) { String def_val; @@ -1210,21 +1232,25 @@ void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user, static int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) { + my_bool compact_view_name= TRUE; my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL | MODE_ORACLE | MODE_MSSQL | MODE_DB2 | MODE_MAXDB | MODE_ANSI)) != 0; - /* - Compact output format for view can be used - - if user has db of this view as current db - - if this view only references table inside it's own db - */ + if (!thd->db || strcmp(thd->db, table->view_db.str)) - table->compact_view_format= FALSE; + /* + print compact view name if the view belongs to the current database + */ + compact_view_name= table->compact_view_format= FALSE; else { + /* + Compact output format for view body can be used + if this view only references table inside it's own db + */ TABLE_LIST *tbl; table->compact_view_format= TRUE; for (tbl= thd->lex->query_tables; @@ -1245,7 +1271,7 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) view_store_options(thd, table, buff); } buff->append(STRING_WITH_LEN("VIEW ")); - if (!table->compact_view_format) + if (!compact_view_name) { append_identifier(thd, buff, table->view_db.str, table->view_db.length); buff->append('.'); @@ -1441,6 +1467,7 @@ static bool show_status_array(THD *thd, const char *wild, char name_buffer[80]; int len; LEX_STRING null_lex_str; + CHARSET_INFO *charset= system_charset_info; DBUG_ENTER("show_status_array"); null_lex_str.str= 0; // For sys_var->value_ptr() @@ -1469,9 +1496,10 @@ static bool show_status_array(THD *thd, const char *wild, long nr; if (show_type == SHOW_SYS) { - show_type= ((sys_var*) value)->show_type(); - value= (char*) ((sys_var*) value)->value_ptr(thd, value_type, - &null_lex_str); + sys_var *var= ((sys_var *) value); + show_type= var->show_type(); + value= (char*) var->value_ptr(thd, value_type, &null_lex_str); + charset= var->charset(thd); } pos= end= buff; @@ -1520,6 +1548,9 @@ static bool show_status_array(THD *thd, const char *wild, nr= (long) (thd->query_start() - server_start_time); end= int10_to_str(nr, buff, 10); break; + case SHOW_QUERIES: + end= int10_to_str((long) thd->query_id, buff, 10); + break; #ifdef HAVE_REPLICATION case SHOW_RPL_STATUS: end= strmov(buff, rpl_status_type[(int)rpl_status]); @@ -1794,7 +1825,7 @@ static bool show_status_array(THD *thd, const char *wild, restore_record(table, s->default_values); table->field[0]->store(name_buffer, strlen(name_buffer), system_charset_info); - table->field[1]->store(pos, (uint32) (end - pos), system_charset_info); + table->field[1]->store(pos, (uint32) (end - pos), charset); if (schema_table_store_record(thd, table)) DBUG_RETURN(TRUE); } @@ -1870,7 +1901,7 @@ typedef struct st_index_field_values 1 error */ -static bool schema_table_store_record(THD *thd, TABLE *table) +bool schema_table_store_record(THD *thd, TABLE *table) { int error; if ((error= table->file->write_row(table->record[0]))) diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 75e47dd0c8e..6bf624a73a2 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -71,25 +71,22 @@ bool String::realloc(uint32 alloc_length) char *new_ptr; if (alloced) { - if ((new_ptr= (char*) my_realloc(Ptr,len,MYF(MY_WME)))) - { - Ptr=new_ptr; - Alloced_length=len; - } - else - return TRUE; // Signal error + if (!(new_ptr= (char*) my_realloc(Ptr,len,MYF(MY_WME)))) + return TRUE; // Signal error } else if ((new_ptr= (char*) my_malloc(len,MYF(MY_WME)))) { + if (str_length > len - 1) + str_length= 0; if (str_length) // Avoid bugs in memcpy on AIX memcpy(new_ptr,Ptr,str_length); new_ptr[str_length]=0; - Ptr=new_ptr; - Alloced_length=len; alloced=1; } else return TRUE; // Signal error + Ptr= new_ptr; + Alloced_length= len; } Ptr[alloc_length]=0; // This make other funcs shorter return FALSE; @@ -125,7 +122,7 @@ bool String::set(double num,uint decimals, CHARSET_INFO *cs) str_charset=cs; if (decimals >= NOT_FIXED_DEC) { - uint32 len= my_sprintf(buff,(buff, "%.14g",num));// Enough for a DATETIME + uint32 len= my_sprintf(buff,(buff, "%.15g",num));// Enough for a DATETIME return copy(buff, len, &my_charset_latin1, cs, &dummy_errors); } #ifdef HAVE_FCONVERT @@ -677,7 +674,7 @@ void String::qs_append(const char *str, uint32 len) void String::qs_append(double d) { char *buff = Ptr + str_length; - str_length+= my_sprintf(buff, (buff, "%.14g", d)); + str_length+= my_sprintf(buff, (buff, "%.15g", d)); } void String::qs_append(double *d) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 1724513eb8f..ff7f874ffcb 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1535,7 +1535,9 @@ static bool prepare_blob_field(THD *thd, create_field *sql_field) if ((sql_field->flags & BLOB_FLAG) && sql_field->length) { - if (sql_field->sql_type == FIELD_TYPE_BLOB) + if (sql_field->sql_type == FIELD_TYPE_BLOB || + sql_field->sql_type == FIELD_TYPE_TINY_BLOB || + sql_field->sql_type == FIELD_TYPE_MEDIUM_BLOB) { /* The user has given a length to the blob column */ sql_field->sql_type= get_blob_type_from_length(sql_field->length); @@ -2312,7 +2314,12 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, view_checksum(thd, table) == HA_ADMIN_WRONG_CHECKSUM) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, ER_VIEW_CHECKSUM, ER(ER_VIEW_CHECKSUM)); - result_code= HA_ADMIN_CORRUPT; + if (thd->net.last_errno == ER_NO_SUCH_TABLE) + /* A missing table is just issued as a failed command */ + result_code= HA_ADMIN_FAILED; + else + /* Default failure code is corrupt table */ + result_code= HA_ADMIN_CORRUPT; goto send_result; } @@ -2322,6 +2329,12 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, goto send_result; } + if (table->schema_table) + { + result_code= HA_ADMIN_NOT_IMPLEMENTED; + goto send_result; + } + if ((table->table->db_stat & HA_READ_ONLY) && open_for_modify) { char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE]; diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index bead50e1da8..d3b5289cd68 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -479,7 +479,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, trigname.trigger_table.length= tables->table_name_length; if (sql_create_definition_file(&dir, &trigname_file, &trigname_file_type, - (gptr)&trigname, trigname_file_parameters, 0)) + (gptr)&trigname, trigname_file_parameters)) return 1; /* @@ -569,7 +569,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, /* Create trigger definition file. */ if (!sql_create_definition_file(&dir, &file, &triggers_file_type, - (gptr)this, triggers_file_parameters, 0)) + (gptr)this, triggers_file_parameters)) return 0; err_with_cleanup: @@ -656,7 +656,7 @@ static bool save_trigger_file(Table_triggers_list *triggers, const char *db, file.str= file_buff; return sql_create_definition_file(&dir, &file, &triggers_file_type, - (gptr)triggers, triggers_file_parameters, 0); + (gptr)triggers, triggers_file_parameters); } @@ -1427,7 +1427,7 @@ Table_triggers_list::change_table_name_in_trignames(const char *db_name, trigname.trigger_table= *new_table_name; if (sql_create_definition_file(&dir, &trigname_file, &trigname_file_type, - (gptr)&trigname, trigname_file_parameters, 0)) + (gptr)&trigname, trigname_file_parameters)) return trigger; } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index eb4e9b7ed73..8a3f5bcdc26 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -775,7 +775,7 @@ reopen_tables: DBUG_RETURN(TRUE); } - tables_for_update= get_table_map(fields); + thd->table_map_for_update= tables_for_update= get_table_map(fields); /* Setup timestamp handling and locking mode @@ -1249,6 +1249,32 @@ multi_update::initialize_tables(JOIN *join) } } + /* + enable uncacheable flag if we update a view with check option + and check option has a subselect, otherwise, the check option + can be evaluated after the subselect was freed as independent + (See full_local in JOIN::join_free()). + */ + if (table_ref->check_option && !join->select_lex->uncacheable) + { + SELECT_LEX_UNIT *tmp_unit; + SELECT_LEX *sl; + for (tmp_unit= join->select_lex->first_inner_unit(); + tmp_unit; + tmp_unit= tmp_unit->next_unit()) + { + for (sl= tmp_unit->first_select(); sl; sl= sl->next_select()) + { + if (sl->master_unit()->item) + { + join->select_lex->uncacheable|= UNCACHEABLE_CHECKOPTION; + goto loop_end; + } + } + } + } +loop_end: + if (table == first_table_for_update && table_ref->check_option) { table_map unupdated_tables= table_ref->check_option->used_tables() & diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 8e6d3ed583a..41a638b2618 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -660,7 +660,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, } VOID(pthread_mutex_unlock(&LOCK_open)); - if (view->revision != 1) + if (mode != VIEW_CREATE_NEW) query_cache_invalidate3(thd, view, 0); start_waiting_global_read_lock(thd); if (res) @@ -678,12 +678,8 @@ err: } -/* index of revision number in following table */ -static const int revision_number_position= 8; -/* index of last required parameter for making view */ -static const int required_view_parameters= 10; -/* number of backups */ -static const int num_view_backups= 3; +/* number of required parameters for making view */ +static const int required_view_parameters= 9; /* table of VIEW .frm field descriptors @@ -716,9 +712,6 @@ static File_option view_parameters[]= {{(char*) STRING_WITH_LEN("with_check_option")}, my_offsetof(TABLE_LIST, with_check), FILE_OPTIONS_ULONGLONG}, - {{(char*) STRING_WITH_LEN("revision")}, - my_offsetof(TABLE_LIST, revision), - FILE_OPTIONS_REV}, {{(char*) STRING_WITH_LEN("timestamp")}, my_offsetof(TABLE_LIST, timestamp), FILE_OPTIONS_TIMESTAMP}, @@ -880,18 +873,9 @@ loop_out: } /* - read revision number - TODO: read dependence list, too, to process cascade/restrict TODO: special cascade/restrict procedure for alter? */ - if (parser->parse((gptr)view, thd->mem_root, - view_parameters + revision_number_position, 1, - &file_parser_dummy_hook)) - { - error= thd->net.report_error? -1 : 0; - goto err; - } } else { @@ -933,7 +917,7 @@ loop_out: } if (sql_create_definition_file(&dir, &file, view_file_type, - (gptr)view, view_parameters, num_view_backups)) + (gptr)view, view_parameters)) { error= thd->net.report_error? -1 : 1; goto err; @@ -996,13 +980,14 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, DBUG_RETURN(0); } - if (table->use_index || table->ignore_index) + List<String> *index_list= table->use_index ? table->use_index + : table->ignore_index; + if (index_list) { - my_error(ER_WRONG_USAGE, MYF(0), - table->ignore_index ? "IGNORE INDEX" : - (table->force_index ? "FORCE INDEX" : "USE INDEX"), - "VIEW"); - DBUG_RETURN(TRUE); + DBUG_ASSERT(index_list->head()); // should never fail + my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), index_list->head()->c_ptr(), + table->table_name); + DBUG_RETURN(TRUE); } /* check loop via view definition */ @@ -1868,8 +1853,7 @@ mysql_rename_view(THD *thd, goto err; /* rename view and it's backups */ - if (rename_in_schema_file(thd, view->db, view->table_name, new_name, - view_def.revision - 1, num_view_backups)) + if (rename_in_schema_file(thd, view->db, view->table_name, new_name)) goto err; strxnmov(dir_buff, FN_REFLEN, mysql_data_home, "/", view->db, "/", NullS); @@ -1883,12 +1867,10 @@ mysql_rename_view(THD *thd, - file_buff); if (sql_create_definition_file(&pathstr, &file, view_file_type, - (gptr)&view_def, view_parameters, - num_view_backups)) + (gptr)&view_def, view_parameters)) { /* restore renamed view in case of error */ - rename_in_schema_file(thd, view->db, new_name, view->table_name, - view_def.revision - 1, num_view_backups); + rename_in_schema_file(thd, view->db, new_name, view->table_name); goto err; } } else diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0eefe782354..51fb5dbdfe4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7512,6 +7512,11 @@ drop: THD *thd= YYTHD; LEX *lex= thd->lex; sp_name *spname; + if ($4.str && check_db_name($4.str)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), $4.str); + MYSQL_YYABORT; + } if (lex->sphead) { my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"); diff --git a/sql/structs.h b/sql/structs.h index ab8537612fa..9882119b7c5 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -170,7 +170,7 @@ enum SHOW_TYPE SHOW_UNDEF, SHOW_LONG, SHOW_LONGLONG, SHOW_INT, SHOW_CHAR, SHOW_CHAR_PTR, SHOW_DOUBLE_STATUS, - SHOW_BOOL, SHOW_MY_BOOL, SHOW_OPENTABLES, SHOW_STARTTIME, + SHOW_BOOL, SHOW_MY_BOOL, SHOW_OPENTABLES, SHOW_STARTTIME, SHOW_QUERIES, SHOW_LONG_CONST, SHOW_INT_CONST, SHOW_HAVE, SHOW_SYS, SHOW_HA_ROWS, SHOW_VARS, #ifdef HAVE_OPENSSL diff --git a/sql/table.h b/sql/table.h index 08326e2fbe0..0884f5ba3d2 100644 --- a/sql/table.h +++ b/sql/table.h @@ -657,7 +657,6 @@ struct TABLE_LIST st_lex_user definer; /* definer of view */ ulonglong file_version; /* version of file's field set */ ulonglong updatable_view; /* VIEW can be updated */ - ulonglong revision; /* revision control number */ ulonglong algorithm; /* 0 any, 1 tmp tables , 2 merging */ ulonglong view_suid; /* view is suid (TRUE dy default) */ ulonglong with_check; /* WITH CHECK OPTION */ diff --git a/sql/tztime.cc b/sql/tztime.cc index 709e3b64752..d3d952e3c1e 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1073,6 +1073,7 @@ Time_zone_system::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const localtime_r(&tmp_t, &tmp_tm); localtime_to_TIME(tmp, &tmp_tm); tmp->time_type= MYSQL_TIMESTAMP_DATETIME; + adjust_leap_second(tmp); } @@ -1157,6 +1158,7 @@ Time_zone_utc::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const gmtime_r(&tmp_t, &tmp_tm); localtime_to_TIME(tmp, &tmp_tm); tmp->time_type= MYSQL_TIMESTAMP_DATETIME; + adjust_leap_second(tmp); } @@ -1260,6 +1262,7 @@ void Time_zone_db::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const { ::gmt_sec_to_TIME(tmp, t, tz_info); + adjust_leap_second(tmp); } @@ -2373,6 +2376,25 @@ Time_zone *my_tz_find_with_opening_tz_tables(THD *thd, const String *name) DBUG_RETURN(tz); } + +/** + Convert leap seconds into non-leap + + This function will convert the leap seconds added by the OS to + non-leap seconds, e.g. 23:59:59, 23:59:60 -> 23:59:59, 00:00:01 ... + This check is not checking for years on purpose : although it's not a + complete check this way it doesn't require looking (and having installed) + the leap seconds table. + + @param[in,out] broken down time structure as filled in by the OS +*/ + +void Time_zone::adjust_leap_second(MYSQL_TIME *t) +{ + if (t->second == 60 || t->second == 61) + t->second= 59; +} + #endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */ diff --git a/sql/tztime.h b/sql/tztime.h index 32a942a26e1..750b8dacbe1 100644 --- a/sql/tztime.h +++ b/sql/tztime.h @@ -55,6 +55,9 @@ public: allocated on MEM_ROOT and should not require destruction. */ virtual ~Time_zone() {}; + +protected: + static inline void adjust_leap_second(MYSQL_TIME *t); }; extern Time_zone * my_tz_UTC; diff --git a/sql/unireg.cc b/sql/unireg.cc index b581ad4655a..d37bb09d0e8 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -63,8 +63,8 @@ static bool make_empty_rec(THD *thd, int file, enum db_type table_type, db_file Handler to use. May be zero, in which case we use create_info->db_type RETURN - 0 ok - 1 error + false ok + true error */ bool mysql_create_frm(THD *thd, my_string file_name, @@ -143,6 +143,24 @@ bool mysql_create_frm(THD *thd, my_string file_name, (create_info->min_rows == 1) && (keys == 0)); int2store(fileinfo+28,key_info_length); + /* + This gives us the byte-position of the character at + (character-position, not byte-position) TABLE_COMMENT_MAXLEN. + The trick here is that character-positions start at 0, so the last + character in a maximum-allowed length string would be at char-pos + MAXLEN-1; charpos MAXLEN will be the position of the terminator. + Consequently, bytepos(charpos(MAXLEN)) should be equal to + comment[length] (which should also be the terminator, or at least + the first byte after the payload in the strict sense). If this is + not so (bytepos(charpos(MAXLEN)) comes /before/ the end of the + string), the string is too long. + + For additional credit, realise that UTF-8 has 1-3 bytes before 6.0, + and 1-4 bytes in 6.0 (6.0 also has UTF-32). This means that the + inlined COMMENT supposedly does not exceed 60 character plus + terminator, vulgo, 181 bytes. + */ + tmp_len= system_charset_info->cset->charpos(system_charset_info, create_info->comment.str, create_info->comment.str + @@ -165,14 +183,6 @@ bool mysql_create_frm(THD *thd, my_string file_name, strmake((char*) forminfo+47, create_info->comment.str ? create_info->comment.str : "", create_info->comment.length); forminfo[46]=(uchar) create_info->comment.length; -#ifdef EXTRA_DEBUG - /* - EXTRA_DEBUG causes strmake() to initialize its buffer behind the - payload with a magic value to detect wrong buffer-sizes. We - explicitly zero that segment again. - */ - memset((char*) forminfo+47 + forminfo[46], 0, 61 - forminfo[46]); -#endif if (my_pwrite(file,(byte*) fileinfo,64,0L,MYF_RW) || my_pwrite(file,(byte*) keybuff,key_info_length, (ulong) uint2korr(fileinfo+6),MYF_RW)) |