summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/subselect_cache.result38
-rw-r--r--mysql-test/t/subselect_cache.test45
-rw-r--r--sql/item.cc104
-rw-r--r--storage/myisam/mi_open.c26
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;