MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Sergey Petrunia Date:May 15 2006 10:18am
Subject:bk commit into 5.0 tree (sergefp:1.2137) BUG#19618
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of psergey. When psergey does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.2137 06/05/15 14:18:23 sergefp@stripped +3 -0
  BUG#19618: Crash for unsigned_col NOT IN (-1, ... ) 
  - When manually constructing a SEL_TREE for "t.key NOT IN(...)", take into account that 
    get_mm_parts may return a tree with type SEL_TREE::IMPOSSIBLE
  - Added missing OOM checks
  - Added comments

  sql/opt_range.cc
    1.211 06/05/15 14:18:17 sergefp@stripped +51 -18
    BUG#19618: Crash for unsigned_col NOT IN (-1, ... ) 
    - When manually constructing a SEL_TREE for "t.key NOT IN(...)", take into account that 
      get_mm_parts may return a tree with type SEL_TREE::IMPOSSIBLE
    - Added missing OOM checks
    - Added comments

  mysql-test/t/func_in.test
    1.20 06/05/15 14:18:17 sergefp@stripped +12 -0
    Testcase for BUG#19618

  mysql-test/r/func_in.result
    1.25 06/05/15 14:18:17 sergefp@stripped +17 -0
    Testcase for BUG#19618

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	sergefp
# Host:	newbox.mylan
# Root:	/home/psergey/mysql-5.0-bug19618

--- 1.210/sql/opt_range.cc	2006-05-10 17:40:15 +04:00
+++ 1.211/sql/opt_range.cc	2006-05-15 14:18:17 +04:00
@@ -3530,17 +3530,38 @@
         if (!value_item)
           break;
         
-        /* Get a SEL_TREE for "-inf < X < c_0" interval */
-        func->array->value_to_item(0, value_item);
-        tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC,
-                           value_item, cmp_type);
-        if (!tree)
+        /* 
+          Get a SEL_TREE for "(-inf|NULL) < X < c_0" interval.
+          Note: for partially-covering keys the returned tree may represent
+          a half-closed interval (-inf < X <= c_0). In that case the for the
+          whole NOT IN statement the (-inf < X < +inf) interval will be
+          constructed. It doesn't make sense to consider range access over
+          such intervals, but we don't eliminate them here as 1) they are 
+          handled correctly by all parts of the code, and 2) the case where
+          such intervals are constructed is rare.
+        */
+        uint i=0;
+        do 
+        {
+          func->array->value_to_item(i, value_item);
+          tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC,
+                             value_item, cmp_type);
+          if (!tree)
+            break;
+          i++;
+        } while (i < func->array->count && tree->type == SEL_TREE::IMPOSSIBLE);
+
+        if (!tree || tree->type == SEL_TREE::IMPOSSIBLE)
+        {
+          /* We get here in cases like "t.unsigned NOT IN (-1,-2,-3) */
+          tree= NULL;
           break;
+        }
 #define NOT_IN_IGNORE_THRESHOLD 1000        
         SEL_TREE *tree2;
         if (func->array->count < NOT_IN_IGNORE_THRESHOLD)
         {
-          for (uint i=1; i < func->array->count; i++)
+          for (; i < func->array->count; i++)
           {
             if (func->array->compare_elems(i, i-1))
             {
@@ -3548,32 +3569,44 @@
               func->array->value_to_item(i, value_item);
               tree2= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC,
                                   value_item, cmp_type);
-              
+              if (!tree2)
+              {
+                tree= NULL;
+                break;
+              }
+
               /* Change all intervals to be "c_{i-1} < X < c_i" */
               for (uint idx= 0; idx < param->keys; idx++)
               {
-                SEL_ARG *new_interval;
-                if ((new_interval=  tree2->keys[idx]))
+                SEL_ARG *new_interval, *last_val;
+                if (((new_interval= tree2->keys[idx])) && 
+                    ((last_val= tree->keys[idx]->last())))
                 {
-                  SEL_ARG *last_val= tree->keys[idx]->last();
                   new_interval->min_value= last_val->max_value;
                   new_interval->min_flag= NEAR_MIN;
                 }
               }
+              /* 
+                The following doesn't try to allocate memory so no need to
+                check for NULL.
+              */
               tree= tree_or(param, tree, tree2);
             }
           }
         }
         else
           func->array->value_to_item(func->array->count - 1, value_item);
-
-        /* 
-          Get the SEL_TREE for the last "c_last < X < +inf" interval 
-          (value_item cotains c_last already)
-        */
-        tree2= get_mm_parts(param, cond_func, field, Item_func::GT_FUNC,
-                            value_item, cmp_type);
-        tree= tree_or(param, tree, tree2);
+        
+        if (tree && tree->type != SEL_TREE::IMPOSSIBLE)
+        {
+          /* 
+            Get the SEL_TREE for the last "c_last < X < +inf" interval 
+            (value_item cotains c_last already)
+          */
+          tree2= get_mm_parts(param, cond_func, field, Item_func::GT_FUNC,
+                              value_item, cmp_type);
+          tree= tree_or(param, tree, tree2);
+        }
       }
       else
       {

--- 1.24/mysql-test/r/func_in.result	2006-04-25 23:33:26 +04:00
+++ 1.25/mysql-test/r/func_in.result	2006-05-15 14:18:17 +04:00
@@ -326,3 +326,20 @@
 set @str=NULL;
 drop table t2;
 drop table t1;
+create table t1 (
+some_id smallint(5) unsigned,
+key (some_id)
+);
+insert into t1 values (1),(2);
+select some_id from t1 where some_id not in(2,-1);
+some_id
+1
+select some_id from t1 where some_id not in(-4,-1,-4);
+some_id
+1
+2
+select some_id from t1 where some_id not in(-4,-1,3423534,2342342);
+some_id
+1
+2
+drop table t1;

--- 1.19/mysql-test/t/func_in.test	2006-04-25 23:33:26 +04:00
+++ 1.20/mysql-test/t/func_in.test	2006-05-15 14:18:17 +04:00
@@ -220,3 +220,15 @@
 drop table t2;
 drop table t1;
 
+# BUG#19618: Crash in range optimizer for 
+#   "unsigned_keypart NOT IN(negative_number,...)" 
+#   (introduced in fix BUG#15872) 
+create table t1 (
+  some_id smallint(5) unsigned,
+  key (some_id)
+);
+insert into t1 values (1),(2);
+select some_id from t1 where some_id not in(2,-1);
+select some_id from t1 where some_id not in(-4,-1,-4);
+select some_id from t1 where some_id not in(-4,-1,3423534,2342342);
+drop table t1;
Thread
bk commit into 5.0 tree (sergefp:1.2137) BUG#19618Sergey Petrunia15 May