Commit f2aee237 authored by Sergey Glukhov's avatar Sergey Glukhov

Bug#45195 valgrind warnings about uninitialized values in store_record_in_cache()

The problem becomes apparent only if HAVE_purify is undefined.
It related to the part of code placed in open_table_from_share() fuction
where we initialize record buffer only if HAVE_purify is enabled.
So in case of HAVE_purify=OFF record buffer is not initialized
on open table stage.
Next we read key, find NULL value and update appropriate null bit
but do not update record buffer. After that the record is stored
in the join cache(store_record_in_cache). For CHAR fields we
strip trailing spaces and in our case this procedure uses
uninitialized record buffer.
The fix is to skip stripping space procedure in case of null values
for CHAR fields(partially based on 6.0 JOIN_CACHE implementation).


mysql-test/r/join.result:
  test case
mysql-test/t/join.test:
  test case
sql/field.cc:
  code updated according to new CACHE_FIELD struct
sql/sql_select.cc:
  code updated according to new CACHE_FIELD struct
sql/sql_select.h:
  CACHE_FIELD struct:
  added new fields: Field *field, uint type;
  removed fields: Field_blob *blob_field, bool strip;
parent f2c5870f
......@@ -1128,3 +1128,20 @@ EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DROP VIEW v1;
DROP TABLE t1, t2;
CREATE TABLE t1(a CHAR(9),b INT,KEY(b),KEY(a)) ENGINE=MYISAM;
CREATE TABLE t2(a CHAR(9),b INT,KEY(b),KEY(a)) ENGINE=MYISAM;
INSERT INTO t1 VALUES ('1',null),(null,null);
INSERT INTO t2 VALUES ('1',null),(null,null);
CREATE TABLE mm1(a CHAR(9),b INT,KEY(b),KEY(a))
ENGINE=MERGE UNION=(t1,t2);
SELECT t1.a FROM mm1,t1;
a
NULL
1
NULL
1
NULL
1
NULL
1
DROP TABLE t1, t2, mm1;
......@@ -804,3 +804,15 @@ DEALLOCATE PREPARE stmt;
DROP VIEW v1;
DROP TABLE t1, t2;
#
# Bug#45195 valgrind warnings about uninitialized values in store_record_in_cache()
#
CREATE TABLE t1(a CHAR(9),b INT,KEY(b),KEY(a)) ENGINE=MYISAM;
CREATE TABLE t2(a CHAR(9),b INT,KEY(b),KEY(a)) ENGINE=MYISAM;
INSERT INTO t1 VALUES ('1',null),(null,null);
INSERT INTO t2 VALUES ('1',null),(null,null);
CREATE TABLE mm1(a CHAR(9),b INT,KEY(b),KEY(a))
ENGINE=MERGE UNION=(t1,t2);
SELECT t1.a FROM mm1,t1;
DROP TABLE t1, t2, mm1;
......@@ -1705,11 +1705,10 @@ uint Field::fill_cache_field(CACHE_FIELD *copy)
uint store_length;
copy->str=ptr;
copy->length=pack_length();
copy->blob_field=0;
copy->field= this;
if (flags & BLOB_FLAG)
{
copy->blob_field=(Field_blob*) this;
copy->strip=0;
copy->type= CACHE_BLOB;
copy->length-= table->s->blob_ptr_size;
return copy->length;
}
......@@ -1717,15 +1716,15 @@ uint Field::fill_cache_field(CACHE_FIELD *copy)
(type() == MYSQL_TYPE_STRING && copy->length >= 4 &&
copy->length < 256))
{
copy->strip=1; /* Remove end space */
copy->type= CACHE_STRIPPED;
store_length= 2;
}
else
{
copy->strip=0;
copy->type= 0;
store_length= 0;
}
return copy->length+ store_length;
return copy->length + store_length;
}
......
......@@ -14149,7 +14149,7 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
{
used_fields--;
length+=field->fill_cache_field(copy);
if (copy->blob_field)
if (copy->type == CACHE_BLOB)
(*blob_ptr++)=copy;
if (field->real_maybe_null())
null_fields++;
......@@ -14164,8 +14164,8 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
{ /* must copy null bits */
copy->str= tables[i].table->null_flags;
copy->length= tables[i].table->s->null_bytes;
copy->strip=0;
copy->blob_field=0;
copy->type=0;
copy->field=0;
length+=copy->length;
copy++;
cache->fields++;
......@@ -14175,8 +14175,8 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
{
copy->str= (uchar*) &tables[i].table->null_row;
copy->length=sizeof(tables[i].table->null_row);
copy->strip=0;
copy->blob_field=0;
copy->type=0;
copy->field=0;
length+=copy->length;
copy++;
cache->fields++;
......@@ -14201,9 +14201,10 @@ used_blob_length(CACHE_FIELD **ptr)
uint length,blob_length;
for (length=0 ; *ptr ; ptr++)
{
(*ptr)->blob_length=blob_length=(*ptr)->blob_field->get_length();
Field_blob *field_blob= (Field_blob *) (*ptr)->field;
(*ptr)->blob_length=blob_length= field_blob->get_length();
length+=blob_length;
(*ptr)->blob_field->get_ptr(&(*ptr)->str);
field_blob->get_ptr(&(*ptr)->str);
}
return length;
}
......@@ -14232,27 +14233,32 @@ store_record_in_cache(JOIN_CACHE *cache)
cache->records++;
for (copy=cache->field ; copy < end_field; copy++)
{
if (copy->blob_field)
if (copy->type == CACHE_BLOB)
{
Field_blob *blob_field= (Field_blob *) copy->field;
if (last_record)
{
copy->blob_field->get_image(pos, copy->length+sizeof(char*),
copy->blob_field->charset());
blob_field->get_image(pos, copy->length+sizeof(char*),
blob_field->charset());
pos+=copy->length+sizeof(char*);
}
else
{
copy->blob_field->get_image(pos, copy->length, // blob length
copy->blob_field->charset());
blob_field->get_image(pos, copy->length, // blob length
blob_field->charset());
memcpy(pos+copy->length,copy->str,copy->blob_length); // Blob data
pos+=copy->length+copy->blob_length;
}
}
else
{
if (copy->strip)
if (copy->type == CACHE_STRIPPED)
{
uchar *str,*end;
Field *field= copy->field;
if (field && field->maybe_null() && field->is_null())
end= str= copy->str;
else
for (str=copy->str,end= str+copy->length;
end > str && end[-1] == ' ' ;
end--) ;
......@@ -14304,23 +14310,24 @@ read_cached_record(JOIN_TAB *tab)
copy < end_field;
copy++)
{
if (copy->blob_field)
if (copy->type == CACHE_BLOB)
{
Field_blob *blob_field= (Field_blob *) copy->field;
if (last_record)
{
copy->blob_field->set_image(pos, copy->length+sizeof(char*),
copy->blob_field->charset());
blob_field->set_image(pos, copy->length+sizeof(char*),
blob_field->charset());
pos+=copy->length+sizeof(char*);
}
else
{
copy->blob_field->set_ptr(pos, pos+copy->length);
pos+=copy->length+copy->blob_field->get_length();
blob_field->set_ptr(pos, pos+copy->length);
pos+=copy->length + blob_field->get_length();
}
}
else
{
if (copy->strip)
if (copy->type == CACHE_STRIPPED)
{
length= uint2korr(pos);
memcpy(copy->str, pos+2, length);
......
......@@ -95,6 +95,10 @@ typedef struct st_table_ref
} TABLE_REF;
#define CACHE_BLOB 1 /* blob field */
#define CACHE_STRIPPED 2 /* field stripped of trailing spaces */
/**
CACHE_FIELD and JOIN_CACHE is used on full join to cache records in outer
table
......@@ -103,8 +107,8 @@ typedef struct st_table_ref
typedef struct st_cache_field {
uchar *str;
uint length, blob_length;
Field_blob *blob_field;
bool strip;
Field *field;
uint type; /**< category of the of the copied field (CACHE_BLOB et al.) */
} CACHE_FIELD;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment