summaryrefslogtreecommitdiff
path: root/sql/item_subselect.cc
diff options
context:
space:
mode:
authorunknown <gkodinov/kgeorge@magare.gmz>2007-05-21 10:22:44 +0300
committerunknown <gkodinov/kgeorge@magare.gmz>2007-05-21 10:22:44 +0300
commit6ee9dcd142a7f58c7e2534a28c862c5fbb1b4576 (patch)
treeeee41824f6020355809db8b18ef8ec45f2e0dc05 /sql/item_subselect.cc
parente553c0599a1f05597ba3b0f599a879c04d4d6564 (diff)
parentee01c5c205ea93cc9873bccad53ba2460fddeffd (diff)
downloadmariadb-git-6ee9dcd142a7f58c7e2534a28c862c5fbb1b4576.tar.gz
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
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 ab4b4eb6796..f6ea315cbb5 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -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,13 +2035,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);
@@ -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());