mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Merge magare.gmz:/home/kgeorge/mysql/work/B22855-5.0-opt
into magare.gmz:/home/kgeorge/mysql/work/B22855-5.1-opt mysql-test/r/subselect3.result: Auto merged sql/item_subselect.cc: Auto merged
This commit is contained in:
@ -742,3 +742,21 @@ x
|
||||
0
|
||||
0
|
||||
DROP TABLE t1,t2,t3;
|
||||
CREATE TABLE t1 (a INT NOT NULL);
|
||||
INSERT INTO t1 VALUES (1),(-1), (65),(66);
|
||||
CREATE TABLE t2 (a INT UNSIGNED NOT NULL PRIMARY KEY);
|
||||
INSERT INTO t2 VALUES (65),(66);
|
||||
SELECT a FROM t1 WHERE a NOT IN (65,66);
|
||||
a
|
||||
1
|
||||
-1
|
||||
SELECT a FROM t1 WHERE a NOT IN (SELECT a FROM t2);
|
||||
a
|
||||
1
|
||||
-1
|
||||
EXPLAIN SELECT a FROM t1 WHERE a NOT IN (SELECT a FROM t2);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
|
||||
2 DEPENDENT SUBQUERY t2 unique_subquery PRIMARY PRIMARY 4 func 1 Using index
|
||||
DROP TABLE t1;
|
||||
End of 5.0 tests
|
||||
|
@ -571,3 +571,21 @@ SELECT (t1.id IN (SELECT t2.id FROM t2,t3
|
||||
FROM t1;
|
||||
|
||||
DROP TABLE t1,t2,t3;
|
||||
|
||||
#
|
||||
# Bug #22855: Optimizer doesn't rewrite NOT IN subselects to a correlated
|
||||
# subquery
|
||||
#
|
||||
CREATE TABLE t1 (a INT NOT NULL);
|
||||
INSERT INTO t1 VALUES (1),(-1), (65),(66);
|
||||
|
||||
CREATE TABLE t2 (a INT UNSIGNED NOT NULL PRIMARY KEY);
|
||||
INSERT INTO t2 VALUES (65),(66);
|
||||
|
||||
SELECT a FROM t1 WHERE a NOT IN (65,66);
|
||||
SELECT a FROM t1 WHERE a NOT IN (SELECT a FROM t2);
|
||||
EXPLAIN SELECT a FROM t1 WHERE a NOT IN (SELECT a FROM t2);
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo End of 5.0 tests
|
||||
|
@ -818,6 +818,11 @@ bool Item_in_subselect::val_bool()
|
||||
if (exec())
|
||||
{
|
||||
reset();
|
||||
/*
|
||||
Must mark the IN predicate as NULL so as to make sure an enclosing NOT
|
||||
predicate will return FALSE. See the comments in
|
||||
subselect_uniquesubquery_engine::copy_ref_key for further details.
|
||||
*/
|
||||
null_value= 1;
|
||||
return 0;
|
||||
}
|
||||
@ -1979,10 +1984,38 @@ int subselect_uniquesubquery_engine::scan_table()
|
||||
|
||||
DESCRIPTION
|
||||
Copy ref key and check for null parts in it.
|
||||
Depending on the nullability and conversion problems this function
|
||||
recognizes and processes the following states :
|
||||
1. Partial match on top level. This means IN has a value of FALSE
|
||||
regardless of the data in the subquery table.
|
||||
Detected by finding a NULL in the left IN operand of a top level
|
||||
expression.
|
||||
We may actually skip reading the subquery, so return TRUE to skip
|
||||
the table scan in subselect_uniquesubquery_engine::exec and make
|
||||
the value of the IN predicate a NULL (that is equal to FALSE on
|
||||
top level).
|
||||
2. No exact match when IN is nested inside another predicate.
|
||||
Detected by finding a NULL in the left IN operand when IN is not
|
||||
a top level predicate.
|
||||
We cannot have an exact match. But we must proceed further with a
|
||||
table scan to find out if it's a partial match (and IN has a value
|
||||
of NULL) or no match (and IN has a value of FALSE).
|
||||
So we return FALSE to continue with the scan and see if there are
|
||||
any record that would constitute a partial match (as we cannot
|
||||
determine that from the index).
|
||||
3. Error converting the left IN operand to the column type of the
|
||||
right IN operand. This counts as no match (and IN has the value of
|
||||
FALSE). We mark the subquery table cursor as having no more rows
|
||||
(to ensure that the processing that follows will not find a match)
|
||||
and return FALSE, so IN is not treated as returning NULL.
|
||||
|
||||
|
||||
RETURN
|
||||
FALSE - ok, index lookup key without keys copied.
|
||||
TRUE - an error occured while copying the key
|
||||
FALSE - The value of the IN predicate is not known. Proceed to find the
|
||||
value of the IN predicate using the determined values of
|
||||
null_keypart and table->status.
|
||||
TRUE - IN predicate has a value of NULL. Stop the processing right there
|
||||
and return NULL to the outer predicates.
|
||||
*/
|
||||
|
||||
bool subselect_uniquesubquery_engine::copy_ref_key()
|
||||
@ -2002,14 +2035,38 @@ bool subselect_uniquesubquery_engine::copy_ref_key()
|
||||
function.
|
||||
*/
|
||||
null_keypart= (*copy)->null_key;
|
||||
bool top_level= ((Item_in_subselect *) item)->is_top_level_item();
|
||||
if (null_keypart && !top_level)
|
||||
break;
|
||||
if ((tab->ref.key_err) & 1 || (null_keypart && top_level))
|
||||
if (null_keypart)
|
||||
{
|
||||
tab->table->status= STATUS_NOT_FOUND;
|
||||
bool top_level= ((Item_in_subselect *) item)->is_top_level_item();
|
||||
if (top_level)
|
||||
{
|
||||
/* Partial match on top level */
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No exact match when IN is nested inside another predicate */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Check if the error is equal to STORE_KEY_FATAL. This is not expressed
|
||||
using the store_key::store_key_result enum because ref.key_err is a
|
||||
boolean and we want to detect both TRUE and STORE_KEY_FATAL from the
|
||||
space of the union of the values of [TRUE, FALSE] and
|
||||
store_key::store_key_result.
|
||||
TODO: fix the variable an return types.
|
||||
*/
|
||||
if (tab->ref.key_err & 1)
|
||||
{
|
||||
/*
|
||||
Error converting the left IN operand to the column type of the right
|
||||
IN operand.
|
||||
*/
|
||||
tab->table->status= STATUS_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
@ -2051,10 +2108,20 @@ int subselect_uniquesubquery_engine::exec()
|
||||
int error;
|
||||
TABLE *table= tab->table;
|
||||
empty_result_set= TRUE;
|
||||
table->status= 0;
|
||||
|
||||
/* TODO: change to use of 'full_scan' here? */
|
||||
if (copy_ref_key())
|
||||
DBUG_RETURN(1);
|
||||
if (table->status)
|
||||
{
|
||||
/*
|
||||
We know that there will be no rows even if we scan.
|
||||
Can be set in copy_ref_key.
|
||||
*/
|
||||
((Item_in_subselect *) item)->value= 0;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
if (null_keypart)
|
||||
DBUG_RETURN(scan_table());
|
||||
|
Reference in New Issue
Block a user