diff options
author | Sergey Glukhov <Sergey.Glukhov@sun.com> | 2010-02-10 18:56:47 +0400 |
---|---|---|
committer | Sergey Glukhov <Sergey.Glukhov@sun.com> | 2010-02-10 18:56:47 +0400 |
commit | f2aee2371ef3f9140fb4f812ca7dcdcf2f6720bb (patch) | |
tree | b7e6c83de86e7516dde1bd768b6ffe2800d3cfbe | |
parent | f2c5870f2a94fb818010a874d04f1c7ceac80282 (diff) | |
download | mariadb-git-f2aee2371ef3f9140fb4f812ca7dcdcf2f6720bb.tar.gz |
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;
-rw-r--r-- | mysql-test/r/join.result | 17 | ||||
-rw-r--r-- | mysql-test/t/join.test | 12 | ||||
-rw-r--r-- | sql/field.cc | 11 | ||||
-rw-r--r-- | sql/sql_select.cc | 51 | ||||
-rw-r--r-- | sql/sql_select.h | 8 |
5 files changed, 69 insertions, 30 deletions
diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index baabf48cb2f..8691eb27220 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -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; diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index dbf36dedec8..645321a3a5e 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -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; diff --git a/sql/field.cc b/sql/field.cc index d8db3fdbae4..15ee9c4a86c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -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; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b1efaf67b9b..a3ce50fe4ee 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -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,30 +14233,35 @@ 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; - for (str=copy->str,end= str+copy->length; - end > str && end[-1] == ' ' ; - 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--) ; length=(uint) (end-str); memcpy(pos+2, str, length); int2store(pos, length); @@ -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); diff --git a/sql/sql_select.h b/sql/sql_select.h index bfff0a0ffa2..ef43f9b049c 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -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; |