diff options
author | Martin Hansson <martin.hansson@sun.com> | 2010-09-07 12:17:12 +0200 |
---|---|---|
committer | Martin Hansson <martin.hansson@sun.com> | 2010-09-07 12:17:12 +0200 |
commit | 06b70326ce0ee59c8d143a9b584d51fff0355050 (patch) | |
tree | 896e32212b838de9457c673076ba3ffb75e45829 /sql/item_cmpfunc.cc | |
parent | 417092560c3c7275a9ccf50909b3eb65466f15f2 (diff) | |
parent | babebf9cebd2218fcc29e7d0cdbecb501f6fec30 (diff) | |
download | mariadb-git-06b70326ce0ee59c8d143a9b584d51fff0355050.tar.gz |
Merge of fix for Bug#51070.
Diffstat (limited to 'sql/item_cmpfunc.cc')
-rw-r--r-- | sql/item_cmpfunc.cc | 79 |
1 files changed, 76 insertions, 3 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 641d3726aca..adecc19a122 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1763,6 +1763,76 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref) } +/** + The implementation of optimized \<outer expression\> [NOT] IN \<subquery\> + predicates. The implementation works as follows. + + For the current value of the outer expression + + - If it contains only NULL values, the original (before rewrite by the + Item_in_subselect rewrite methods) inner subquery is non-correlated and + was previously executed, there is no need to re-execute it, and the + previous return value is returned. + + - If it contains NULL values, check if there is a partial match for the + inner query block by evaluating it. For clarity we repeat here the + transformation previously performed on the sub-query. The expression + + <tt> + ( oc_1, ..., oc_n ) + \<in predicate\> + ( SELECT ic_1, ..., ic_n + FROM \<table\> + WHERE \<inner where\> + ) + </tt> + + was transformed into + + <tt> + ( oc_1, ..., oc_n ) + \<in predicate\> + ( SELECT ic_1, ..., ic_n + FROM \<table\> + WHERE \<inner where\> AND ... ( ic_k = oc_k OR ic_k IS NULL ) + HAVING ... NOT ic_k IS NULL + ) + </tt> + + The evaluation will now proceed according to special rules set up + elsewhere. These rules include: + + - The HAVING NOT \<inner column\> IS NULL conditions added by the + aforementioned rewrite methods will detect whether they evaluated (and + rejected) a NULL value and if so, will cause the subquery to evaluate + to NULL. + + - The added WHERE and HAVING conditions are present only for those inner + columns that correspond to outer column that are not NULL at the moment. + + - If there is an eligible index for executing the subquery, the special + access method "Full scan on NULL key" is employed which ensures that + the inner query will detect if there are NULL values resulting from the + inner query. This access method will quietly resort to table scan if it + needs to find NULL values as well. + + - Under these conditions, the sub-query need only be evaluated in order to + find out whether it produced any rows. + + - If it did, we know that there was a partial match since there are + NULL values in the outer row expression. + + - If it did not, the result is FALSE or UNKNOWN. If at least one of the + HAVING sub-predicates rejected a NULL value corresponding to an outer + non-NULL, and hence the inner query block returns UNKNOWN upon + evaluation, there was a partial match and the result is UNKNOWN. + + - If it contains no NULL values, the call is forwarded to the inner query + block. + + @see Item_in_subselect::val_bool() + @see Item_is_not_null_test::val_int() + */ longlong Item_in_optimizer::val_int() { bool tmp; @@ -1816,7 +1886,7 @@ longlong Item_in_optimizer::val_int() all_left_cols_null= false; } - if (!((Item_in_subselect*)args[1])->is_correlated && + if (!item_subs->is_correlated && all_left_cols_null && result_for_null_param != UNKNOWN) { /* @@ -1830,8 +1900,11 @@ longlong Item_in_optimizer::val_int() else { /* The subquery has to be evaluated */ - (void) args[1]->val_bool_result(); - null_value= !item_subs->engine->no_rows(); + (void) item_subs->val_bool_result(); + if (item_subs->engine->no_rows()) + null_value= item_subs->null_value; + else + null_value= TRUE; if (all_left_cols_null) result_for_null_param= null_value; } |