diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item_func.cc | 5 | ||||
-rw-r--r-- | sql/item_sum.h | 2 | ||||
-rw-r--r-- | sql/lock.cc | 56 | ||||
-rw-r--r-- | sql/sql_select.cc | 19 |
4 files changed, 72 insertions, 10 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc index 4bdb62c6e7a..56409a329f1 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -380,7 +380,10 @@ Field *Item_func::tmp_table_field(TABLE *t_arg) res= new Field_double(max_length, maybe_null, name, t_arg, decimals); break; case STRING_RESULT: - res= make_string_field(t_arg); + if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB) + res= new Field_blob(max_length, maybe_null, name, t_arg, collation.collation); + else + res= new Field_string(max_length, maybe_null, name, t_arg, collation.collation); break; case DECIMAL_RESULT: res= new Field_new_decimal(my_decimal_precision_to_length(decimal_precision(), diff --git a/sql/item_sum.h b/sql/item_sum.h index 328f8dd8400..77b6ac57e79 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1124,7 +1124,7 @@ public: if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB) return FIELD_TYPE_BLOB; else - return MYSQL_TYPE_VARCHAR; + return MYSQL_TYPE_VAR_STRING; } void clear(); bool add(); diff --git a/sql/lock.cc b/sql/lock.cc index a584b063a0b..8ea13b2117c 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -78,6 +78,7 @@ extern HASH open_cache; static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count, uint flags, TABLE **write_locked); +static void reset_lock_data(MYSQL_LOCK *sql_lock); static int lock_external(THD *thd, TABLE **table,uint count); static int unlock_external(THD *thd, TABLE **table,uint count); static void print_lock_error(int error, const char *); @@ -135,12 +136,16 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, */ if (wait_if_global_read_lock(thd, 1, 1)) { + /* Clear the lock type of all lock data to avoid reusage. */ + reset_lock_data(sql_lock); my_free((gptr) sql_lock,MYF(0)); sql_lock=0; break; - } + } if (thd->version != refresh_version) { + /* Clear the lock type of all lock data to avoid reusage. */ + reset_lock_data(sql_lock); my_free((gptr) sql_lock,MYF(0)); goto retry; } @@ -149,6 +154,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, thd->proc_info="System lock"; if (lock_external(thd, tables, count)) { + /* Clear the lock type of all lock data to avoid reusage. */ + reset_lock_data(sql_lock); my_free((gptr) sql_lock,MYF(0)); sql_lock=0; break; @@ -699,7 +706,10 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, *write_lock_used=table; if (table->db_stat & HA_READ_ONLY) { - my_error(ER_OPEN_AS_READONLY, MYF(0), table->alias); + my_error(ER_OPEN_AS_READONLY,MYF(0),table->alias); + /* Clear the lock type of the lock data that are stored already. */ + sql_lock->lock_count= locks - sql_lock->locks; + reset_lock_data(sql_lock); my_free((gptr) sql_lock,MYF(0)); DBUG_RETURN(0); } @@ -724,6 +734,48 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, } +/* + Reset lock type in lock data. + + SYNOPSIS + reset_lock_data() + sql_lock The MySQL lock. + + DESCRIPTION + + After a locking error we want to quit the locking of the table(s). + The test case in the bug report for Bug #18544 has the following + cases: 1. Locking error in lock_external() due to InnoDB timeout. + 2. Locking error in get_lock_data() due to missing write permission. + 3. Locking error in wait_if_global_read_lock() due to lock conflict. + + In all these cases we have already set the lock type into the lock + data of the open table(s). If the table(s) are in the open table + cache, they could be reused with the non-zero lock type set. This + could lead to ignoring a different lock type with the next lock. + + Clear the lock type of all lock data. This ensures that the next + lock request will set its lock type properly. + + RETURN + void +*/ + +static void reset_lock_data(MYSQL_LOCK *sql_lock) +{ + THR_LOCK_DATA **ldata; + THR_LOCK_DATA **ldata_end; + + for (ldata= sql_lock->locks, ldata_end= ldata + sql_lock->lock_count; + ldata < ldata_end; + ldata++) + { + /* Reset lock type. */ + (*ldata)->type= TL_UNLOCK; + } +} + + /***************************************************************************** Lock table based on the name. This is used when we need total access to a closed, not open table diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0211539e784..5b796aeb4c1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8245,13 +8245,20 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, if ((type= item->field_type()) == MYSQL_TYPE_DATETIME || type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE) new_field= item->tmp_table_field_from_field_type(table); - else if (item->max_length/item->collation.collation->mbmaxlen > 255 && - convert_blob_length) - new_field= new Field_varstring(convert_blob_length, maybe_null, - item->name, table, - item->collation.collation); + else if (item->max_length/item->collation.collation->mbmaxlen > + CONVERT_IF_BIGGER_TO_BLOB) + { + if (convert_blob_length) + new_field= new Field_varstring(convert_blob_length, maybe_null, + item->name, table, + item->collation.collation); + else + new_field= new Field_blob(item->max_length, maybe_null, item->name, + table, item->collation.collation); + } else - new_field= item->make_string_field(table); + new_field= new Field_string(item->max_length, maybe_null, item->name, + table, item->collation.collation); break; case DECIMAL_RESULT: new_field= new Field_new_decimal(item->max_length, maybe_null, item->name, |