List:Commits« Previous MessageNext Message »
From:Georgi Kodinov Date:August 31 2009 11:16am
Subject:bzr commit into mysql-5.0-bugteam branch (joro:2794) Bug#46749
View as plain text  
#At file:///home/kgeorge/mysql/work/B46749-5.0-bugteam/ based on revid:anurag.shekhar@stripped

 2794 Georgi Kodinov	2009-08-27
      Bug #46749: Segfault in add_key_fields() with outer subquery level 
        field references
      
      This error requires a combination of factors : 
      1. An "impossible where" in the outermost SELECT
      2. An aggregate in the outermost SELECT
      3. A correlated subquery with a WHERE clause that includes an outer 
      field reference as a top level WHERE sargable predicate
      
      When JOIN::optimize detects an "impossible WHERE" it will bail out
      without doing the rest of the work and initializations. It will not
      call make_join_statistics() as well.  And make_join_statistics fills 
      in various structures for each table referenced.
      When processing the result of the "impossible WHERE" the query must
      send a single row of data if there are aggregate functions in it.
      In this case the server marks all the aggregates as having received 
      no rows and calls the relevant Item::val_xxx() method on the SELECT
      list. However if this SELECT list happens to contain a correlated 
      subquery this subquery is evaluated in a normal evaluation mode.
      And if this correlated subquery has a reference to a field from the 
      outermost "impossible where" SELECT the add_key_fields will mistakenly
      consider the outer field reference as a "local" field reference when 
      looking for sargable predicates.
      But since the SELECT where the outer field reference refers to is not
      completely initialized due to the "impossible WHERE" in this level
      we'll get a NULL pointer reference.
      Fixed by making a better condition for discovering if a field is "local"
      to the SELECT level being processed. 
      It's not enough to look for OUTER_REF_TABLE_BIT in this case since 
      for outer references to constant tables the Item_field::used_tables() 
      will return 0 regardless of whether the field reference is from the 
      local SELECT or not.

    modified:
      mysql-test/r/subselect.result
      mysql-test/t/subselect.test
      sql/sql_select.cc
=== modified file 'mysql-test/r/subselect.result'
--- a/mysql-test/r/subselect.result	2009-08-27 10:22:19 +0000
+++ b/mysql-test/r/subselect.result	2009-08-27 11:40:42 +0000
@@ -4474,4 +4474,32 @@ id	select_type	table	type	possible_keys	
 1	PRIMARY	C	ALL	NULL	NULL	NULL	NULL	20	Using where
 DROP TABLE C;
 # End of test for bug#45061.
+#
+# Bug #46749: Segfault in add_key_fields() with outer subquery level 
+#   field references
+#
+CREATE TABLE t1 (
+a int,
+b int,
+UNIQUE (a), KEY (b)
+);
+INSERT INTO t1 VALUES (1,1), (2,1);
+CREATE TABLE st1 like t1;
+INSERT INTO st1 VALUES (1,1), (2,1);
+CREATE TABLE st2 like t1;
+INSERT INTO st2 VALUES (1,1), (2,1);
+EXPLAIN
+SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
+FROM t1 
+WHERE a = 230;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE noticed after reading const tables
+2	DEPENDENT SUBQUERY	st1	index	NULL	a	5	NULL	2	Using index
+2	DEPENDENT SUBQUERY	st2	index	b	b	5	NULL	2	Using where; Using index
+SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
+FROM t1 
+WHERE a = 230;
+MAX(b)	(SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
+NULL	0
+DROP TABLE t1, st1, st2;
 End of 5.0 tests.

=== modified file 'mysql-test/t/subselect.test'
--- a/mysql-test/t/subselect.test	2009-08-27 10:22:19 +0000
+++ b/mysql-test/t/subselect.test	2009-08-27 11:40:42 +0000
@@ -3450,4 +3450,35 @@ DROP TABLE C;
 --echo # End of test for bug#45061.
 
 
+--echo #
+--echo # Bug #46749: Segfault in add_key_fields() with outer subquery level 
+--echo #   field references
+--echo #
+
+CREATE TABLE t1 (
+  a int,
+  b int,
+  UNIQUE (a), KEY (b)
+);
+INSERT INTO t1 VALUES (1,1), (2,1);
+
+CREATE TABLE st1 like t1;
+INSERT INTO st1 VALUES (1,1), (2,1);
+
+CREATE TABLE st2 like t1;
+INSERT INTO st2 VALUES (1,1), (2,1);
+
+# should have "impossible where"
+EXPLAIN
+SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
+FROM t1 
+WHERE a = 230;
+
+# should not crash
+SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
+FROM t1 
+WHERE a = 230;
+
+DROP TABLE t1, st1, st2;
+
 --echo End of 5.0 tests.

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2009-08-10 18:53:26 +0000
+++ b/sql/sql_select.cc	2009-08-27 11:40:42 +0000
@@ -3207,6 +3207,28 @@ add_key_equal_fields(KEY_FIELD **key_fie
   }
 }
 
+
+/**
+  Check if an expression is a non-outer field.
+
+  Checks if an expression is a field and belongs to the current select.
+
+  @param   field  Item expression to check
+
+  @return boolean
+     @retval TRUE   the expression is a local field
+     @retval FALSE  it's something else
+*/
+
+inline static bool
+is_local_field (Item *field)
+{
+  field= field->real_item();
+  return field->type() == Item::FIELD_ITEM && 
+    !((Item_field *)field)->depended_from;
+}
+
+
 static void
 add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
                COND *cond, table_map usable_tables,
@@ -3282,13 +3304,12 @@ add_key_fields(JOIN *join, KEY_FIELD **k
   {
     Item **values;
     // BETWEEN, IN, NE
-    if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM &&
+    if (is_local_field (cond_func->key_item()) &&
 	!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
     {
       values= cond_func->arguments()+1;
       if (cond_func->functype() == Item_func::NE_FUNC &&
-        cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
-	     !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT))
+        is_local_field (cond_func->arguments()[1]))
         values--;
       DBUG_ASSERT(cond_func->functype() != Item_func::IN_FUNC ||
                   cond_func->argument_count() != 2);
@@ -3304,9 +3325,7 @@ add_key_fields(JOIN *join, KEY_FIELD **k
       for (uint i= 1 ; i < cond_func->argument_count() ; i++)
       {
         Item_field *field_item;
-        if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM
-            &&
-            !(cond_func->arguments()[i]->used_tables() & OUTER_REF_TABLE_BIT))
+        if (is_local_field (cond_func->arguments()[i]))
         {
           field_item= (Item_field *) (cond_func->arguments()[i]->real_item());
           add_key_equal_fields(key_fields, *and_level, cond_func,
@@ -3322,8 +3341,7 @@ add_key_fields(JOIN *join, KEY_FIELD **k
     bool equal_func=(cond_func->functype() == Item_func::EQ_FUNC ||
 		     cond_func->functype() == Item_func::EQUAL_FUNC);
 
-    if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM &&
-	!(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT))
+    if (is_local_field (cond_func->arguments()[0]))
     {
       add_key_equal_fields(key_fields, *and_level, cond_func,
 	                (Item_field*) (cond_func->arguments()[0])->real_item(),
@@ -3331,9 +3349,8 @@ add_key_fields(JOIN *join, KEY_FIELD **k
                            cond_func->arguments()+1, 1, usable_tables,
                            sargables);
     }
-    if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
-	cond_func->functype() != Item_func::LIKE_FUNC &&
-	!(cond_func->arguments()[1]->used_tables() & OUTER_REF_TABLE_BIT))
+    if (is_local_field (cond_func->arguments()[1]) &&
+	cond_func->functype() != Item_func::LIKE_FUNC)
     {
       add_key_equal_fields(key_fields, *and_level, cond_func, 
                        (Item_field*) (cond_func->arguments()[1])->real_item(),
@@ -3345,7 +3362,7 @@ add_key_fields(JOIN *join, KEY_FIELD **k
   }
   case Item_func::OPTIMIZE_NULL:
     /* column_name IS [NOT] NULL */
-    if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM &&
+    if (is_local_field (cond_func->arguments()[0]) &&
 	!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
     {
       Item *tmp=new Item_null;


Attachment: [text/bzr-bundle] bzr/joro@sun.com-20090827114042-h55n7qp9990bl6ge.bundle
Thread
bzr commit into mysql-5.0-bugteam branch (joro:2794) Bug#46749Georgi Kodinov31 Aug