diff options
author | Ignacio Galarza <iggy@mysql.com> | 2009-03-19 09:44:58 -0400 |
---|---|---|
committer | Ignacio Galarza <iggy@mysql.com> | 2009-03-19 09:44:58 -0400 |
commit | 675c3ce2bbe7f033930822dd0ef9126ebb25d44b (patch) | |
tree | 0d1697348f5ffacdf22ddce0537910d41d6482f0 /sql | |
parent | 54fbbf9591e21cda9f7b26c2d795d88f51827f07 (diff) | |
parent | 0d18d930aed47ed97ef3309f9510cfd7a366202e (diff) | |
download | mariadb-git-675c3ce2bbe7f033930822dd0ef9126ebb25d44b.tar.gz |
auto-merge
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_innodb.cc | 17 | ||||
-rw-r--r-- | sql/item.cc | 77 | ||||
-rw-r--r-- | sql/item.h | 2 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 13 | ||||
-rw-r--r-- | sql/item_func.cc | 5 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 5 | ||||
-rw-r--r-- | sql/item_sum.cc | 3 | ||||
-rw-r--r-- | sql/log_event.cc | 49 | ||||
-rw-r--r-- | sql/log_event.h | 22 | ||||
-rw-r--r-- | sql/mysqld.cc | 48 | ||||
-rw-r--r-- | sql/opt_range.cc | 57 | ||||
-rw-r--r-- | sql/protocol.cc | 23 | ||||
-rw-r--r-- | sql/sql_acl.cc | 28 | ||||
-rw-r--r-- | sql/sql_base.cc | 2 | ||||
-rw-r--r-- | sql/sql_cache.cc | 47 | ||||
-rw-r--r-- | sql/sql_class.cc | 17 | ||||
-rw-r--r-- | sql/sql_class.h | 7 | ||||
-rw-r--r-- | sql/sql_handler.cc | 15 | ||||
-rw-r--r-- | sql/sql_parse.cc | 48 | ||||
-rw-r--r-- | sql/sql_select.cc | 36 | ||||
-rw-r--r-- | sql/sql_show.cc | 43 | ||||
-rw-r--r-- | sql/sql_string.cc | 19 | ||||
-rw-r--r-- | sql/sql_table.cc | 7 | ||||
-rw-r--r-- | sql/sql_update.cc | 2 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 5 | ||||
-rw-r--r-- | sql/table.cc | 5 |
26 files changed, 422 insertions, 180 deletions
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 088ef55134f..f71e891e88d 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); @@ -3731,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 @@ -5212,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/item.cc b/sql/item.cc index 4c2582e2c5c..263915644df 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1608,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. @@ -1724,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; @@ -3010,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 diff --git a/sql/item.h b/sql/item.h index 1058cc5dbb8..852b0fcc1ba 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1169,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); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 3b1d18b4252..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; } @@ -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); } diff --git a/sql/item_func.cc b/sql/item_func.cc index 8aa2565d928..47e16a1bcc3 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4961,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. diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index a43ad8d8137..7edc1a62307 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -101,13 +101,10 @@ String *Item_func_md5::val_str(String *str) str->set_charset(&my_charset_bin); if (sptr) { - my_MD5_CTX context; unsigned char digest[16]; null_value=0; - my_MD5Init (&context); - my_MD5Update (&context,(unsigned char *) sptr->ptr(), sptr->length()); - my_MD5Final (digest, &context); + MY_MD5_HASH(digest,(unsigned char *) sptr->ptr(), sptr->length()); if (str->alloc(32)) // Ensure that memory is free { null_value=1; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index d33d92a5238..57045f52825 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -440,7 +440,8 @@ void Item_sum::make_field(Send_field *tmp_field) void Item_sum::print(String *str) { - Item **pargs= orig_args; + /* orig_args is not filled with valid values until fix_fields() */ + Item **pargs= fixed ? orig_args : args; str->append(func_name()); for (uint i=0 ; i < arg_count ; i++) { diff --git a/sql/log_event.cc b/sql/log_event.cc index 2f4923c4b4f..c4cdfc27fa0 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/mysqld.cc b/sql/mysqld.cc index f43bc9ea1a6..ad3521e5dde 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 */ @@ -3279,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(); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 938254f9ce2..c3a43776429 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -7775,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; @@ -7879,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++)) { @@ -7890,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); } @@ -7908,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; } @@ -7958,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; } @@ -8010,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 ? (uint) + key_infix_parts= cur_key_infix_len ? (uint) (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) @@ -8024,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); @@ -8035,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; @@ -8045,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/protocol.cc b/sql/protocol.cc index 996ede5d6a2..728b9954f6a 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,22 @@ 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 : (uint32) max_length; + int4store(pos + 2, field_length); } pos[6]= field.type; int2store(pos+7,field.flags); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 44407691abb..b2d0304f007 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; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 812c060fe15..0cf3e023be9 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5479,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 fe3f0a09670..bd56994e216 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -363,6 +363,43 @@ TYPELIB query_cache_type_typelib= array_elements(query_cache_type_names)-1,"", query_cache_type_names, NULL }; + +/** + Helper function for determine if a SELECT statement has a SQL_NO_CACHE + directive. + + @param sql A pointer to the first white space character after SELECT + + @return + @retval TRUE The character string contains SQL_NO_CACHE + @retval FALSE No directive found. +*/ + +static bool has_no_cache_directive(char *sql) +{ + int i=0; + while (sql[i] == ' ') + ++i; + + if (my_toupper(system_charset_info, sql[i]) == 'S' && + my_toupper(system_charset_info, sql[i+1]) == 'Q' && + my_toupper(system_charset_info, sql[i+2]) == 'L' && + my_toupper(system_charset_info, sql[i+3]) == '_' && + my_toupper(system_charset_info, sql[i+4]) == 'N' && + my_toupper(system_charset_info, sql[i+5]) == 'O' && + my_toupper(system_charset_info, sql[i+6]) == '_' && + my_toupper(system_charset_info, sql[i+7]) == 'C' && + my_toupper(system_charset_info, sql[i+8]) == 'A' && + my_toupper(system_charset_info, sql[i+9]) == 'C' && + my_toupper(system_charset_info, sql[i+10]) == 'H' && + my_toupper(system_charset_info, sql[i+11]) == 'E' && + my_toupper(system_charset_info, sql[i+12]) == ' ') + return TRUE; + + return FALSE; +} + + /***************************************************************************** Query_cache_block_table method(s) *****************************************************************************/ @@ -1095,6 +1132,16 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached")); goto err; } + + if (query_length > 20 && has_no_cache_directive(&sql[i+6])) + { + /* + We do not increase 'refused' statistics here since it will be done + later when the query is parsed. + */ + DBUG_PRINT("qcache", ("The statement has a SQL_NO_CACHE directive")); + goto err; + } } #ifdef __WIN__ diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 91c0aa66761..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), @@ -341,6 +343,12 @@ void THD::init(void) if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES; options= thd_startup_options; + + if (variables.max_join_size == HA_POS_ERROR) + options |= OPTION_BIG_SELECTS; + else + options &= ~OPTION_BIG_SELECTS; + transaction.all.modified_non_trans_table= transaction.stmt.modified_non_trans_table= FALSE; open_options=ha_open_options; update_lock_default= (variables.low_priority_updates ? @@ -651,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; } @@ -1047,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 cc7ef7809d4..3e3dfcd08fa 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1358,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_handler.cc b/sql/sql_handler.cc index 67f9992499b..c376f1b3d1d 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) (uint) 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_parse.cc b/sql/sql_parse.cc index 8ee88cefd99..2297283c92d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2584,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; @@ -2663,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 @@ -3608,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 c797e25850a..3b4668a3925 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2373,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; @@ -2415,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; @@ -2503,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; } @@ -2513,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; @@ -2529,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; @@ -2601,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; @@ -2650,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; @@ -2732,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; @@ -2778,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 { @@ -2788,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); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5f4ece810b8..34e3193378f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -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; @@ -1222,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; @@ -1257,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('.'); @@ -1324,7 +1338,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) field_list.push_back(field=new Item_empty_string("db",NAME_LEN)); field->maybe_null=1; field_list.push_back(new Item_empty_string("Command",16)); - field_list.push_back(new Item_return_int("Time",7, FIELD_TYPE_LONG)); + field_list.push_back(field= new Item_return_int("Time",7, FIELD_TYPE_LONG)); + field->unsigned_flag= 0; field_list.push_back(field=new Item_empty_string("State",30)); field->maybe_null=1; field_list.push_back(field=new Item_empty_string("Info",max_query_length)); @@ -1425,7 +1440,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) else protocol->store(command_name[thd_info->command], system_charset_info); if (thd_info->start_time) - protocol->store((uint32) (now - thd_info->start_time)); + protocol->store_long ((longlong) (now - thd_info->start_time)); else protocol->store_null(); protocol->store(thd_info->state_info, system_charset_info); diff --git a/sql/sql_string.cc b/sql/sql_string.cc index e7051883d36..e536fc10d51 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 45707246f90..963a98cfb59 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2314,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; } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index f15db220a3b..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 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/table.cc b/sql/table.cc index b5126633469..c559b4bb7fd 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1792,11 +1792,8 @@ void st_table::reset_item_list(List<Item> *item_list) const void TABLE_LIST::calc_md5(char *buffer) { - my_MD5_CTX context; uchar digest[16]; - my_MD5Init(&context); - my_MD5Update(&context,(uchar *) query.str, query.length); - my_MD5Final(digest, &context); + MY_MD5_HASH(digest, (uchar *) query.str, query.length); sprintf((char *) buffer, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", digest[0], digest[1], digest[2], digest[3], |