summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorIgnacio Galarza <iggy@mysql.com>2009-03-19 09:44:58 -0400
committerIgnacio Galarza <iggy@mysql.com>2009-03-19 09:44:58 -0400
commit675c3ce2bbe7f033930822dd0ef9126ebb25d44b (patch)
tree0d1697348f5ffacdf22ddce0537910d41d6482f0 /sql
parent54fbbf9591e21cda9f7b26c2d795d88f51827f07 (diff)
parent0d18d930aed47ed97ef3309f9510cfd7a366202e (diff)
downloadmariadb-git-675c3ce2bbe7f033930822dd0ef9126ebb25d44b.tar.gz
auto-merge
Diffstat (limited to 'sql')
-rw-r--r--sql/ha_innodb.cc17
-rw-r--r--sql/item.cc77
-rw-r--r--sql/item.h2
-rw-r--r--sql/item_cmpfunc.cc13
-rw-r--r--sql/item_func.cc5
-rw-r--r--sql/item_strfunc.cc5
-rw-r--r--sql/item_sum.cc3
-rw-r--r--sql/log_event.cc49
-rw-r--r--sql/log_event.h22
-rw-r--r--sql/mysqld.cc48
-rw-r--r--sql/opt_range.cc57
-rw-r--r--sql/protocol.cc23
-rw-r--r--sql/sql_acl.cc28
-rw-r--r--sql/sql_base.cc2
-rw-r--r--sql/sql_cache.cc47
-rw-r--r--sql/sql_class.cc17
-rw-r--r--sql/sql_class.h7
-rw-r--r--sql/sql_handler.cc15
-rw-r--r--sql/sql_parse.cc48
-rw-r--r--sql/sql_select.cc36
-rw-r--r--sql/sql_show.cc43
-rw-r--r--sql/sql_string.cc19
-rw-r--r--sql/sql_table.cc7
-rw-r--r--sql/sql_update.cc2
-rw-r--r--sql/sql_yacc.yy5
-rw-r--r--sql/table.cc5
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],