From: Jorgen Loland Date: September 1 2010 1:04pm Subject: bzr commit into mysql-next-mr-bugfixing branch (jorgen.loland:3267) Bug#53562 List-Archive: http://lists.mysql.com/commits/117351 X-Bug: 53562 Message-Id: <20100901130405.5B32F1F26@atum21.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============4624839139469260633==" --===============4624839139469260633== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///export/home/jl208045/mysql/mysql-next-mr-bugfixing-53562/ based on revid:bar@stripped 3267 Jorgen Loland 2010-09-01 BUG#53562: EXPLAIN statement should hint when index is not used due to type conversion An index may not be used for ref or range access if a) a type conversion is needed to compare an indexed field to a value, or b) there is a collation mismatch between an indexed field and the value compared to Before, the index would not be used, but no hint was given that this was the case. With this patch, EXPLAIN EXTENDED will issue a warning for the cases above. Note that even if an index cannot be used for ref or range access, the index may still be scanned. @ mysql-test/r/explain.result Added test for BUG#53562 @ mysql-test/t/explain.test Added test for BUG#53562 @ sql/opt_range.cc Make EXPLAIN EXTENDED issue a warning if an index cannot be used for range access due to type conversion of collation mismatch. @ sql/share/errmsg-utf8.txt Added ER_WARN_INDEX_NOT_APPLICABLE for use when an index cannot be used for ref or range access due to type conversion or collation mismatch. @ sql/sql_select.cc Make EXPLAIN EXTENDED issue a warning if an index cannot be used for ref access due to type conversion of collation mismatch. modified: mysql-test/r/explain.result mysql-test/t/explain.test sql/opt_range.cc sql/share/errmsg-utf8.txt sql/sql_select.cc === modified file 'mysql-test/r/explain.result' --- a/mysql-test/r/explain.result 2010-08-26 12:02:59 +0000 +++ b/mysql-test/r/explain.result 2010-09-01 13:04:01 +0000 @@ -324,4 +324,77 @@ id select_type table type possible_keys 25 UNION NULL NULL NULL NULL NULL NULL NULL No tables used NULL UNION RESULT ALL NULL NULL NULL NULL NULL # End BUG#30597 +# +# BUG#53562: EXPLAIN statement should hint when +# index is not used due to type conversion +# +CREATE TABLE t1 (url char(1) PRIMARY KEY); +INSERT INTO t1 VALUES ('1'),('2'),('3'),('4'),('5'); + +# Normally, lookup access on primary key is done +EXPLAIN EXTENDED SELECT * FROM t1 WHERE url='1'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 const PRIMARY PRIMARY 1 const 1 100.00 Using index +Warnings: +Note 1003 select '1' AS `url` from `test`.`t1` where 1 + +# Test that index can't be used for lookup due to type conversion +# (comparing char and int) +SELECT * FROM t1 WHERE url=1; +url +1 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE url=1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index PRIMARY PRIMARY 1 NULL 5 100.00 Using where; Using index +Warnings: +Warning 1708 Cannot use ref access on index 'PRIMARY' due to type or collation conversion on field 'url' +Warning 1708 Cannot use range access on index 'PRIMARY' due to type or collation conversion on field 'url' +Note 1003 select `test`.`t1`.`url` AS `url` from `test`.`t1` where (`test`.`t1`.`url` = 1) + +# Test that index can't be used for lookup due to collation mismatch +SELECT * FROM t1 WHERE url='1' collate latin1_german2_ci; +url +1 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE url='1' collate latin1_german2_ci; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index PRIMARY PRIMARY 1 NULL 5 100.00 Using where; Using index +Warnings: +Warning 1708 Cannot use ref access on index 'PRIMARY' due to type or collation conversion on field 'url' +Warning 1708 Cannot use range access on index 'PRIMARY' due to type or collation conversion on field 'url' +Note 1003 select `test`.`t1`.`url` AS `url` from `test`.`t1` where (`test`.`t1`.`url` = (('1' collate latin1_german2_ci))) + +# Normally, range access on primary key is done +EXPLAIN EXTENDED SELECT * FROM t1 WHERE url>'3'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 range PRIMARY PRIMARY 1 NULL 3 100.00 Using where; Using index +Warnings: +Note 1003 select `test`.`t1`.`url` AS `url` from `test`.`t1` where (`test`.`t1`.`url` > '3') + +# Test that range access on index can't be done due to type conversion +# (comparing char and int) +SELECT * FROM t1 WHERE url>3; +url +4 +5 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE url>3; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index PRIMARY PRIMARY 1 NULL 5 100.00 Using where; Using index +Warnings: +Warning 1708 Cannot use range access on index 'PRIMARY' due to type or collation conversion on field 'url' +Note 1003 select `test`.`t1`.`url` AS `url` from `test`.`t1` where (`test`.`t1`.`url` > 3) + +# Test that range access on index can't be done due to collation mismatch +SELECT * FROM t1 WHERE url>'3' collate latin1_german2_ci; +url +4 +5 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE url>'3' collate latin1_german2_ci; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index PRIMARY PRIMARY 1 NULL 5 100.00 Using where; Using index +Warnings: +Warning 1708 Cannot use range access on index 'PRIMARY' due to type or collation conversion on field 'url' +Note 1003 select `test`.`t1`.`url` AS `url` from `test`.`t1` where (`test`.`t1`.`url` > (('3' collate latin1_german2_ci))) + +DROP TABLE t1; +# End BUG#53562 End of 6.0 tests. === modified file 'mysql-test/t/explain.test' --- a/mysql-test/t/explain.test 2010-08-26 12:02:59 +0000 +++ b/mysql-test/t/explain.test 2010-09-01 13:04:01 +0000 @@ -279,4 +279,43 @@ EXPLAIN --echo # End BUG#30597 +--echo # +--echo # BUG#53562: EXPLAIN statement should hint when +--echo # index is not used due to type conversion +--echo # + +CREATE TABLE t1 (url char(1) PRIMARY KEY); +INSERT INTO t1 VALUES ('1'),('2'),('3'),('4'),('5'); + +--echo +--echo # Normally, lookup access on primary key is done +EXPLAIN EXTENDED SELECT * FROM t1 WHERE url='1'; +--echo +--echo # Test that index can't be used for lookup due to type conversion +--echo # (comparing char and int) +SELECT * FROM t1 WHERE url=1; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE url=1; +--echo +--echo # Test that index can't be used for lookup due to collation mismatch +SELECT * FROM t1 WHERE url='1' collate latin1_german2_ci; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE url='1' collate latin1_german2_ci; + +--echo +--echo # Normally, range access on primary key is done +EXPLAIN EXTENDED SELECT * FROM t1 WHERE url>'3'; +--echo +--echo # Test that range access on index can't be done due to type conversion +--echo # (comparing char and int) +SELECT * FROM t1 WHERE url>3; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE url>3; +--echo +--echo # Test that range access on index can't be done due to collation mismatch +SELECT * FROM t1 WHERE url>'3' collate latin1_german2_ci; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE url>'3' collate latin1_german2_ci; + +--echo +DROP TABLE t1; + +--echo # End BUG#53562 + --echo End of 6.0 tests. === modified file 'sql/opt_range.cc' --- a/sql/opt_range.cc 2010-08-04 10:34:01 +0000 +++ b/sql/opt_range.cc 2010-09-01 13:04:01 +0000 @@ -5768,7 +5768,17 @@ get_mm_leaf(RANGE_OPT_PARAM *param, Item ((Field_str*)field)->charset() != conf_func->compare_collation() && !(conf_func->compare_collation()->state & MY_CS_BINSORT && (type == Item_func::EQUAL_FUNC || type == Item_func::EQ_FUNC))) + { + if (param->thd->lex->describe & DESCRIBE_EXTENDED) + push_warning_printf(param->thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_INDEX_NOT_APPLICABLE, + ER(ER_WARN_INDEX_NOT_APPLICABLE), + "range", + field->table->key_info[param->real_keynr[key_part->key]].name, + field->field_name); goto end; + } if (key_part->image_type == Field::itMBR) { @@ -5889,7 +5899,17 @@ get_mm_leaf(RANGE_OPT_PARAM *param, Item if (field->result_type() == STRING_RESULT && value->result_type() != STRING_RESULT && field->cmp_type() != value->result_type()) + { + if (param->thd->lex->describe & DESCRIBE_EXTENDED) + push_warning_printf(param->thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_INDEX_NOT_APPLICABLE, + ER(ER_WARN_INDEX_NOT_APPLICABLE), + "range", + field->table->key_info[param->real_keynr[key_part->key]].name, + field->field_name); goto end; + } /* For comparison purposes allow invalid dates like 2000-01-32 */ orig_sql_mode= field->table->in_use->variables.sql_mode; if (value->real_item()->type() == Item::STRING_ITEM && === modified file 'sql/share/errmsg-utf8.txt' --- a/sql/share/errmsg-utf8.txt 2010-07-29 14:15:38 +0000 +++ b/sql/share/errmsg-utf8.txt 2010-09-01 13:04:01 +0000 @@ -6387,3 +6387,5 @@ ER_TABLES_DIFFERENT_METADATA ER_ROW_DOES_NOT_MATCH_PARTITION eng "Found row that does not match the partition" swe "Hittade rad som inte passar i partitionen" +ER_WARN_INDEX_NOT_APPLICABLE + eng "Cannot use %-.64s access on index '%-.64s' due to type or collation conversion on field '%-.64s'" === modified file 'sql/sql_select.cc' --- a/sql/sql_select.cc 2010-08-26 13:54:59 +0000 +++ b/sql/sql_select.cc 2010-09-01 13:04:01 +0000 @@ -5159,6 +5159,41 @@ static uint get_semi_join_select_list_in } /** + If EXPLAIN EXTENDED, add a warning for each index that cannot be + used for ref access due to either type conversion or different + collations on the field used for comparison + + Example type conversion (char compared to int): + + CREATE TABLE t1 (url char(1) PRIMARY KEY); + SELECT * FROM t1 WHERE url=1; + + Example different collations (danish vs german2): + + CREATE TABLE t1 (url char(1) PRIMARY KEY) collate latin1_danish_ci; + SELECT * FROM t1 WHERE url='1' collate latin1_german2_ci; + + @param thd Thread for the connection that submitted the query + @param field Field used in comparision + @param cant_use_indexes Indexes that cannot be used for lookup + */ +static void +warn_index_not_applicable(THD *thd, const Field *field, + const key_map cant_use_index) +{ + if (thd->lex->describe & DESCRIBE_EXTENDED) + for (uint j=0 ; j < field->table->s->keys ; j++) + if (cant_use_index.is_set(j)) + push_warning_printf(thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_INDEX_NOT_APPLICABLE, + ER(ER_WARN_INDEX_NOT_APPLICABLE), + "ref", + field->table->key_info[j].name, + field->field_name); +} + +/** Add a possible key to array of possible keys if it's usable as a key @param key_fields Pointer to add key, if usable @@ -5183,6 +5218,7 @@ add_key_field(KEY_FIELD **key_fields,uin Field *field, bool eq_func, Item **value, uint num_values, table_map usable_tables, SARGABLE_PARAM **sargables) { + DBUG_PRINT("info",("add_key_field for field %s",field->field_name)); uint exists_optimize= 0; if (!(field->flags & PART_KEY_FLAG)) { @@ -5284,7 +5320,10 @@ add_key_field(KEY_FIELD **key_fields,uin if ((*value)->result_type() != STRING_RESULT) { if (field->cmp_type() != (*value)->result_type()) + { + warn_index_not_applicable(stat->join->thd, field, possible_keys); return; + } } else { @@ -5294,7 +5333,10 @@ add_key_field(KEY_FIELD **key_fields,uin */ if (field->cmp_type() == STRING_RESULT && ((Field_str*)field)->charset() != cond->compare_collation()) + { + warn_index_not_applicable(stat->join->thd, field, possible_keys); return; + } } } } --===============4624839139469260633== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/jorgen.loland@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: jorgen.loland@stripped\ # ibwxujp08qfybay9 # target_branch: file:///export/home/jl208045/mysql/mysql-next-mr-\ # bugfixing-53562/ # testament_sha1: 5c3a331453d9182f1bbf702c1237e7495b5d404c # timestamp: 2010-09-01 15:04:05 +0200 # base_revision_id: bar@stripped # # Begin bundle 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 vySKGAoSeKyKBEDCD/F3JFOFCQgmlrEw --===============4624839139469260633==--