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
|
||||||
0
|
0
|
||||||
DROP TABLE t1,t2,t3;
|
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;
|
FROM t1;
|
||||||
|
|
||||||
DROP TABLE t1,t2,t3;
|
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())
|
if (exec())
|
||||||
{
|
{
|
||||||
reset();
|
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;
|
null_value= 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1979,10 +1984,38 @@ int subselect_uniquesubquery_engine::scan_table()
|
|||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
Copy ref key and check for null parts in it.
|
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
|
RETURN
|
||||||
FALSE - ok, index lookup key without keys copied.
|
FALSE - The value of the IN predicate is not known. Proceed to find the
|
||||||
TRUE - an error occured while copying the key
|
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()
|
bool subselect_uniquesubquery_engine::copy_ref_key()
|
||||||
@ -2002,13 +2035,37 @@ bool subselect_uniquesubquery_engine::copy_ref_key()
|
|||||||
function.
|
function.
|
||||||
*/
|
*/
|
||||||
null_keypart= (*copy)->null_key;
|
null_keypart= (*copy)->null_key;
|
||||||
bool top_level= ((Item_in_subselect *) item)->is_top_level_item();
|
if (null_keypart)
|
||||||
if (null_keypart && !top_level)
|
|
||||||
break;
|
|
||||||
if ((tab->ref.key_err) & 1 || (null_keypart && top_level))
|
|
||||||
{
|
{
|
||||||
|
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;
|
tab->table->status= STATUS_NOT_FOUND;
|
||||||
DBUG_RETURN(1);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
@ -2051,10 +2108,20 @@ int subselect_uniquesubquery_engine::exec()
|
|||||||
int error;
|
int error;
|
||||||
TABLE *table= tab->table;
|
TABLE *table= tab->table;
|
||||||
empty_result_set= TRUE;
|
empty_result_set= TRUE;
|
||||||
|
table->status= 0;
|
||||||
|
|
||||||
/* TODO: change to use of 'full_scan' here? */
|
/* TODO: change to use of 'full_scan' here? */
|
||||||
if (copy_ref_key())
|
if (copy_ref_key())
|
||||||
DBUG_RETURN(1);
|
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)
|
if (null_keypart)
|
||||||
DBUG_RETURN(scan_table());
|
DBUG_RETURN(scan_table());
|
||||||
|
Reference in New Issue
Block a user