Looks good. Approved.
--
Øystein
Jorgen Loland wrote:
> #At file:///localhome/jl208045/mysql/mysql-next-mr-bugfixing/ based on
> revid:vvaintroub@stripped
>
> 3119 Jorgen Loland 2010-03-09
> Bug#50257 "Missing info in REF column of the EXPLAIN
> lines for subselects"
>
> In create_ref_for_key(): When executing a query where a key
> lookup is compared to a constant value, the value can be stored
> in ref.key_buff of the join_tab. The store_key object created for
> this key will not be used after this, so the object will not be
> pointed to by the join_tab.
>
> If the store_key object needs to be referenced later, the object
> is pointed to by ref.key_copy of the join_tab instead of just
> storing the value in ref.key_buff. Key lookups of non-constant
> values and EXPLAIN queries both use this object.
>
> The bug was that for EXPLAIN queries with constant key lookup in
> subqueries, it was not detected that the query was an EXPLAIN.
> The reason was that it was checked whether the call stack came
> from select_describe() ("join->select_options &
> SELECT_DESCRIBE"). This check is correct for queries that are not
> nested, but for subselects create_ref_for_key() may be called as
> part of JOIN::optimize() of the parent select. The fix is to
> check for "thd->lex->describe" instead of "join->select_options".
> This variable will have a non-zero value if and only if we're
> executing an EXPLAIN query.
> @ mysql-test/r/subselect.result
> Updated result file with missing info in ref column of EXPLAIN after fixing
> BUG#50257
> @ mysql-test/r/subselect4.result
> Added test for BUG#50257
> @ mysql-test/t/subselect4.test
> Added test for BUG#50257
> @ sql/sql_lex.cc
> Initialize lex->describe to DESCRIBE_NONE instead of 0.
> @ sql/sql_lex.h
> Added #define DESCRIBE_NONE, a lex->describe type indicating that the
> query is not an EXPLAIN.
> @ sql/sql_select.cc
> create_ref_for_key() must detect that the query is an EXPLAIN and point
> ref->key_copy to the store_key object also in the case of constant lookups in
> subselects.
>
> modified:
> mysql-test/r/subselect.result
> mysql-test/r/subselect4.result
> mysql-test/t/subselect4.test
> sql/sql_lex.cc
> sql/sql_lex.h
> sql/sql_select.cc
> === modified file 'mysql-test/r/subselect.result'
> --- a/mysql-test/r/subselect.result 2010-03-01 09:45:36 +0000
> +++ b/mysql-test/r/subselect.result 2010-03-09 12:13:25 +0000
> @@ -363,9 +363,9 @@ INSERT INTO t8 (pseudo,email) VALUES ('2
> EXPLAIN EXTENDED SELECT pseudo,(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo
> FROM t8 WHERE pseudo='joce')) FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE
> pseudo='joce');
> id select_type table type possible_keys key key_len ref rows filtered Extra
> 1 PRIMARY t8 const PRIMARY PRIMARY 37 const 1 100.00 Using index
> -4 SUBQUERY t8 const PRIMARY PRIMARY 37 1 100.00 Using index
> +4 SUBQUERY t8 const PRIMARY PRIMARY 37 const 1 100.00 Using index
> 2 SUBQUERY t8 const PRIMARY PRIMARY 37 const 1 100.00
> -3 SUBQUERY t8 const PRIMARY PRIMARY 37 1 100.00 Using index
> +3 SUBQUERY t8 const PRIMARY PRIMARY 37 const 1 100.00 Using index
> Warnings:
> Note 1003 select 'joce' AS `pseudo`,(select 'test' AS `email` from `test`.`t8` where
> 1) AS `(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'))`
> from `test`.`t8` where 1
> SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo,email FROM
>
> === modified file 'mysql-test/r/subselect4.result'
> --- a/mysql-test/r/subselect4.result 2009-09-28 13:48:40 +0000
> +++ b/mysql-test/r/subselect4.result 2010-03-09 12:13:25 +0000
> @@ -59,3 +59,22 @@ FROM t3 WHERE 1 = 0 GROUP BY 1;
> (SELECT 1 FROM t1,t2 WHERE t2.b > t3.b)
> DROP TABLE t1,t2,t3;
> End of 5.0 tests.
> +#
> +# BUG#50257: Missing info in REF column of the EXPLAIN
> +# lines for subselects
> +#
> +CREATE TABLE t1 (a INT, b INT, INDEX (a));
> +INSERT INTO t1 VALUES (3, 10), (2, 20), (7, 10), (5, 20);
> +
> +EXPLAIN SELECT * FROM (SELECT * FROM t1 WHERE a=7) t;
> +id select_type table type possible_keys key key_len ref rows Extra
> +1 PRIMARY <derived2> system NULL NULL NULL NULL 1
> +2 DERIVED t1 ref a a 5 const 1 Using where
> +
> +EXPLAIN SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t1 WHERE a=7);
> +id select_type table type possible_keys key key_len ref rows Extra
> +1 PRIMARY t1 ALL NULL NULL NULL NULL 4
> +2 SUBQUERY t1 ref a a 5 const 1 Using where; Using index
> +
> +DROP TABLE t1;
> +End of 5.5 tests.
>
> === modified file 'mysql-test/t/subselect4.test'
> --- a/mysql-test/t/subselect4.test 2009-09-18 09:34:08 +0000
> +++ b/mysql-test/t/subselect4.test 2010-03-09 12:13:25 +0000
> @@ -62,3 +62,21 @@ FROM t3 WHERE 1 = 0 GROUP BY 1;
> DROP TABLE t1,t2,t3;
>
> --echo End of 5.0 tests.
> +
> +--echo #
> +--echo # BUG#50257: Missing info in REF column of the EXPLAIN
> +--echo # lines for subselects
> +--echo #
> +
> +CREATE TABLE t1 (a INT, b INT, INDEX (a));
> +INSERT INTO t1 VALUES (3, 10), (2, 20), (7, 10), (5, 20);
> +
> +--echo
> +EXPLAIN SELECT * FROM (SELECT * FROM t1 WHERE a=7) t;
> +--echo
> +EXPLAIN SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t1 WHERE a=7);
> +
> +--echo
> +DROP TABLE t1;
> +
> +--echo End of 5.5 tests.
>
> === modified file 'sql/sql_lex.cc'
> --- a/sql/sql_lex.cc 2010-02-24 13:52:27 +0000
> +++ b/sql/sql_lex.cc 2010-03-09 12:13:25 +0000
> @@ -340,7 +340,7 @@ void lex_start(THD *thd)
> lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
> lex->select_lex.init_order();
> lex->select_lex.group_list.empty();
> - lex->describe= 0;
> + lex->describe= DESCRIBE_NONE;
> lex->subqueries= FALSE;
> lex->view_prepare_mode= FALSE;
> lex->derived_tables= 0;
>
> === modified file 'sql/sql_lex.h'
> --- a/sql/sql_lex.h 2010-02-24 13:52:27 +0000
> +++ b/sql/sql_lex.h 2010-03-09 12:13:25 +0000
> @@ -140,6 +140,7 @@ enum enum_sql_command {
> };
>
> // describe/explain types
> +#define DESCRIBE_NONE 0 // Not explain query
> #define DESCRIBE_NORMAL 1
> #define DESCRIBE_EXTENDED 2
> /*
>
> === modified file 'sql/sql_select.cc'
> --- a/sql/sql_select.cc 2010-03-01 09:45:36 +0000
> +++ b/sql/sql_select.cc 2010-03-09 12:13:25 +0000
> @@ -5814,22 +5814,31 @@ static bool create_ref_for_key(JOIN *joi
> if (keyuse->null_rejecting)
> j->ref.null_rejecting |= 1 << i;
> keyuse_uses_no_tables= keyuse_uses_no_tables &&
> !keyuse->used_tables;
> - if (!keyuse->used_tables &&
> - !(join->select_options & SELECT_DESCRIBE))
> - { // Compare against constant
> - store_key_item tmp(thd, keyinfo->key_part[i].field,
> +
> + if (keyuse->used_tables || thd->lex->describe)
> + /*
> + Comparing against a non-constant or executing an EXPLAIN
> + query (which refers to this info when printing the 'ref'
> + column of the query plan)
> + */
> + *ref_key++= get_store_key(thd,
> + keyuse,join->const_table_map,
> + &keyinfo->key_part[i],
> + key_buff, maybe_null);
> + else
> + { // Compare against constant
> + store_key_item tmp(thd, keyinfo->key_part[i].field,
> key_buff + maybe_null,
> maybe_null ? key_buff : 0,
> keyinfo->key_part[i].length, keyuse->val);
> - if (thd->is_fatal_error)
> - DBUG_RETURN(TRUE);
> - tmp.copy();
> + if (thd->is_fatal_error)
> + DBUG_RETURN(TRUE);
> + /*
> + The constant is the value to look for with this key. Copy
> + the value to ref->key_buff
> + */
> + tmp.copy();
> }
> - else
> - *ref_key++= get_store_key(thd,
> - keyuse,join->const_table_map,
> - &keyinfo->key_part[i],
> - key_buff, maybe_null);
> /*
> Remember if we are going to use REF_OR_NULL
> But only if field _really_ can be null i.e. we force JT_REF
>
>
>
> ------------------------------------------------------------------------
>
>