summaryrefslogtreecommitdiff
path: root/sql/item_subselect.cc
diff options
context:
space:
mode:
authorunknown <gkodinov/kgeorge@magare.gmz>2007-05-21 10:21:55 +0300
committerunknown <gkodinov/kgeorge@magare.gmz>2007-05-21 10:21:55 +0300
commit330a82f0663d7079aab924dcdb12a37a27ecc750 (patch)
treed9360beced4f5bfb397f6cb9bfad7678db6c2193 /sql/item_subselect.cc
parent59a7e066e3a86bb4371ce5027b4ad6b79ac91ce2 (diff)
parent455352b0b892252fdb060a1da71bd008da36f4ac (diff)
downloadmariadb-git-330a82f0663d7079aab924dcdb12a37a27ecc750.tar.gz
Merge macbook:mysql/work/B22855-5.0-opt
into magare.gmz:/home/kgeorge/mysql/work/B22855-5.0-opt sql/item_subselect.cc: Auto merged mysql-test/r/subselect3.result: manual merge mysql-test/t/subselect3.test: manual merge
Diffstat (limited to 'sql/item_subselect.cc')
-rw-r--r--sql/item_subselect.cc81
1 files changed, 74 insertions, 7 deletions
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 48b82e3cde6..3f4ba16a18d 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -775,6 +775,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;
}
@@ -1936,10 +1941,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()
@@ -1959,13 +1992,37 @@ 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)
+ {
+ 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;
- DBUG_RETURN(1);
+ break;
}
}
DBUG_RETURN(0);
@@ -2008,10 +2065,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());