diff options
-rw-r--r-- | mysql-test/r/subselect_cache.result | 38 | ||||
-rw-r--r-- | mysql-test/t/subselect_cache.test | 45 | ||||
-rw-r--r-- | sql/item.cc | 104 | ||||
-rw-r--r-- | storage/myisam/mi_open.c | 26 |
4 files changed, 177 insertions, 36 deletions
diff --git a/mysql-test/r/subselect_cache.result b/mysql-test/r/subselect_cache.result index 7d9e2bb7150..7b9dc3c943f 100644 --- a/mysql-test/r/subselect_cache.result +++ b/mysql-test/r/subselect_cache.result @@ -3272,3 +3272,41 @@ FROM t2 ) AND table1 .`col_varchar_key` OR table1 .`pk` ; col_varchar_nokey drop table t1,t2; set @@optimizer_switch= default; +# LP BUG#615378 (incorrect NULL result returning in Item_cache) +CREATE TABLE `t1` ( +`pk` int(11) NOT NULL AUTO_INCREMENT, +`col_varchar_key` varchar(1) DEFAULT NULL, +PRIMARY KEY (`pk`), +KEY `col_varchar_key` (`col_varchar_key`) +) DEFAULT CHARSET=latin1; +INSERT INTO `t1` VALUES (10,'v'); +INSERT INTO `t1` VALUES (11,'r'); +CREATE TABLE `t2` ( +`pk` int(11) NOT NULL AUTO_INCREMENT, +`col_varchar_key` varchar(1) DEFAULT NULL, +PRIMARY KEY (`pk`), +KEY `col_varchar_key` (`col_varchar_key`) +) DEFAULT CHARSET=latin1; +INSERT INTO `t2` VALUES (1,'r'); +INSERT INTO `t2` VALUES (2,'c'); +CREATE TABLE `t3` ( +`pk` int(11) NOT NULL AUTO_INCREMENT, +`col_varchar_key` varchar(1) DEFAULT NULL, +PRIMARY KEY (`pk`), +KEY `col_varchar_key` (`col_varchar_key`) +) DEFAULT CHARSET=latin1; +INSERT INTO `t3` VALUES (1,'w'); +SELECT SUM( DISTINCT table2 . `pk` ) AS field2 , +(SELECT SUM( SUBQUERY1_t2 . `pk` ) AS SUBQUERY1_field1 +FROM t2 AS SUBQUERY1_t2 STRAIGHT_JOIN +t3 AS SUBQUERY1_t3 ON (SUBQUERY1_t3 . `pk` = SUBQUERY1_t2 . `pk` ) +WHERE table1 . `col_varchar_key` ) AS field3 +FROM ( t1 AS table1 LEFT JOIN +( t2 AS table2 STRAIGHT_JOIN +t3 AS table3 ON (table3 . `pk` = table2 . `pk` ) ) +ON (table3 . `col_varchar_key` = table1 . `col_varchar_key` ) ) +WHERE ( table1 . `pk` < 5 ) OR ( table1 . `col_varchar_key` IS NOT NULL) +GROUP BY field3 +HAVING (field3 <= 'h' AND field2 != 4) ; +field2 field3 +drop tables t1, t2, t3; diff --git a/mysql-test/t/subselect_cache.test b/mysql-test/t/subselect_cache.test index 9045c7f0e14..e8dd256b20b 100644 --- a/mysql-test/t/subselect_cache.test +++ b/mysql-test/t/subselect_cache.test @@ -1566,3 +1566,48 @@ FROM t2 ) AND table1 .`col_varchar_key` OR table1 .`pk` ; drop table t1,t2; set @@optimizer_switch= default; + +# +--echo # LP BUG#615378 (incorrect NULL result returning in Item_cache) +# +# if bug present here will be valgrind warnings (due to attempt to process +# uninialized decimal value) but the result will be correct (due to +# Item::null_value) + +CREATE TABLE `t1` ( + `pk` int(11) NOT NULL AUTO_INCREMENT, + `col_varchar_key` varchar(1) DEFAULT NULL, + PRIMARY KEY (`pk`), + KEY `col_varchar_key` (`col_varchar_key`) +) DEFAULT CHARSET=latin1; +INSERT INTO `t1` VALUES (10,'v'); +INSERT INTO `t1` VALUES (11,'r'); +CREATE TABLE `t2` ( + `pk` int(11) NOT NULL AUTO_INCREMENT, + `col_varchar_key` varchar(1) DEFAULT NULL, + PRIMARY KEY (`pk`), + KEY `col_varchar_key` (`col_varchar_key`) +) DEFAULT CHARSET=latin1; +INSERT INTO `t2` VALUES (1,'r'); +INSERT INTO `t2` VALUES (2,'c'); +CREATE TABLE `t3` ( + `pk` int(11) NOT NULL AUTO_INCREMENT, + `col_varchar_key` varchar(1) DEFAULT NULL, + PRIMARY KEY (`pk`), + KEY `col_varchar_key` (`col_varchar_key`) +) DEFAULT CHARSET=latin1; +INSERT INTO `t3` VALUES (1,'w'); + +SELECT SUM( DISTINCT table2 . `pk` ) AS field2 , +(SELECT SUM( SUBQUERY1_t2 . `pk` ) AS SUBQUERY1_field1 + FROM t2 AS SUBQUERY1_t2 STRAIGHT_JOIN + t3 AS SUBQUERY1_t3 ON (SUBQUERY1_t3 . `pk` = SUBQUERY1_t2 . `pk` ) + WHERE table1 . `col_varchar_key` ) AS field3 +FROM ( t1 AS table1 LEFT JOIN + ( t2 AS table2 STRAIGHT_JOIN + t3 AS table3 ON (table3 . `pk` = table2 . `pk` ) ) + ON (table3 . `col_varchar_key` = table1 . `col_varchar_key` ) ) +WHERE ( table1 . `pk` < 5 ) OR ( table1 . `col_varchar_key` IS NOT NULL) +GROUP BY field3 +HAVING (field3 <= 'h' AND field2 != 4) ; +drop tables t1, t2, t3; diff --git a/sql/item.cc b/sql/item.cc index 2f04b765c19..1419c9c3e6e 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -7750,8 +7750,11 @@ void Item_cache_int::store_longlong(Item *item, longlong val_arg) String *Item_cache_int::val_str(String *str) { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return NULL; + } str->set(value, default_charset()); return str; } @@ -7760,8 +7763,11 @@ String *Item_cache_int::val_str(String *str) my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return NULL; + } int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val); return decimal_val; } @@ -7769,16 +7775,22 @@ my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val) double Item_cache_int::val_real() { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return 0.0; + } return (double) value; } longlong Item_cache_int::val_int() { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return 0; + } return value; } @@ -7796,16 +7808,22 @@ bool Item_cache_real::cache_value() double Item_cache_real::val_real() { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return 0.0; + } return value; } longlong Item_cache_real::val_int() { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return 0; + } return (longlong) rint(value); } @@ -7813,8 +7831,11 @@ longlong Item_cache_real::val_int() String* Item_cache_real::val_str(String *str) { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return NULL; + } str->set_real(value, decimals, default_charset()); return str; } @@ -7823,8 +7844,11 @@ String* Item_cache_real::val_str(String *str) my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return NULL; + } double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); return decimal_val; } @@ -7845,8 +7869,11 @@ double Item_cache_decimal::val_real() { DBUG_ASSERT(fixed); double res; - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return 0.0; + } my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res); return res; } @@ -7855,8 +7882,11 @@ longlong Item_cache_decimal::val_int() { DBUG_ASSERT(fixed); longlong res; - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return 0; + } my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res); return res; } @@ -7864,8 +7894,11 @@ longlong Item_cache_decimal::val_int() String* Item_cache_decimal::val_str(String *str) { DBUG_ASSERT(fixed); - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return NULL; + } my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE, &decimal_value); my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, str); @@ -7875,8 +7908,11 @@ String* Item_cache_decimal::val_str(String *str) my_decimal *Item_cache_decimal::val_decimal(my_decimal *val) { DBUG_ASSERT(fixed); - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return NULL; + } return &decimal_value; } @@ -7911,12 +7947,13 @@ double Item_cache_str::val_real() DBUG_ASSERT(fixed == 1); int err_not_used; char *end_not_used; - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return 0.0; - if (value) - return my_strntod(value->charset(), (char*) value->ptr(), - value->length(), &end_not_used, &err_not_used); - return (double) 0; + } + return my_strntod(value->charset(), (char*) value->ptr(), + value->length(), &end_not_used, &err_not_used); } @@ -7924,21 +7961,24 @@ longlong Item_cache_str::val_int() { DBUG_ASSERT(fixed == 1); int err; - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return 0; - if (value) - return my_strntoll(value->charset(), value->ptr(), - value->length(), 10, (char**) 0, &err); - else - return (longlong)0; + } + return my_strntoll(value->charset(), value->ptr(), + value->length(), 10, (char**) 0, &err); } String* Item_cache_str::val_str(String *str) { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return 0; + } return value; } @@ -7946,20 +7986,24 @@ String* Item_cache_str::val_str(String *str) my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + null_value= TRUE; return NULL; - if (value) - string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); - else - decimal_val= 0; + } + string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); return decimal_val; } int Item_cache_str::save_in_field(Field *field, bool no_conversions) { - if (!value_cached && !cache_value()) + if ((!value_cached && !cache_value()) || null_value) + { + field->set_notnull(); + null_value= TRUE; return 0; + } int res= Item_cache::save_in_field(field, no_conversions); return (is_varbinary && field->type() == MYSQL_TYPE_STRING && value->length() < field->field_length) ? 1 : res; diff --git a/storage/myisam/mi_open.c b/storage/myisam/mi_open.c index 9fc82846e91..c40f894b14d 100644 --- a/storage/myisam/mi_open.c +++ b/storage/myisam/mi_open.c @@ -85,8 +85,8 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) uchar *disk_cache, *disk_pos, *end_pos; MI_INFO info,*m_info,*old_info; MYISAM_SHARE share_buff,*share; - ulong rec_per_key_part[HA_MAX_POSSIBLE_KEY*HA_MAX_KEY_SEG]; - my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE]; + ulong *rec_per_key_part= 0; + my_off_t *key_root, *key_del; ulonglong max_key_file_length, max_data_file_length; DBUG_ENTER("mi_open"); @@ -111,9 +111,6 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) { share= &share_buff; bzero((uchar*) &share_buff,sizeof(share_buff)); - share_buff.state.rec_per_key_part=rec_per_key_part; - share_buff.state.key_root=key_root; - share_buff.state.key_del=key_del; share_buff.key_cache= multi_key_cache_search((uchar*) name_buff, strlen(name_buff), dflt_key_cache); @@ -213,7 +210,12 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) } share->state_diff_length=len-MI_STATE_INFO_SIZE; - mi_state_info_read(disk_cache, &share->state); + if (!mi_state_info_read(disk_cache, &share->state)) + goto err; + rec_per_key_part= share->state.rec_per_key_part; + key_root= share->state.key_root; + key_del= share->state.key_del; + len= mi_uint2korr(share->state.header.base_info_length); if (len != MI_BASE_INFO_SIZE) { @@ -666,6 +668,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) pthread_mutex_unlock(&THR_LOCK_myisam); bzero(info.buff, share->base.max_key_block_length * 2); + my_free(rec_per_key_part, MYF(MY_ALLOW_ZERO_PTR)); if (myisam_log_file >= 0) { @@ -695,6 +698,7 @@ err: case 3: if (! lock_error) VOID(my_lock(kfile, F_UNLCK, 0L, F_TO_EOF, MYF(MY_SEEK_NOT_DONE))); + my_free(rec_per_key_part, MYF(MY_ALLOW_ZERO_PTR)); /* fall through */ case 2: my_afree(disk_cache); @@ -982,6 +986,16 @@ uchar *mi_state_info_read(uchar *ptr, MI_STATE_INFO *state) ptr+= state->state_diff_length; + if (!state->rec_per_key_part) + { + if (!my_multi_malloc(MY_WME, + &state->rec_per_key_part,sizeof(long)*key_parts, + &state->key_root, keys*sizeof(my_off_t), + &state->key_del, key_blocks*sizeof(my_off_t), + NullS)) + return(0); + } + for (i=0; i < keys; i++) { state->key_root[i]= mi_sizekorr(ptr); ptr +=8; |