List:Commits« Previous MessageNext Message »
From:Gleb Shchepa Date:January 29 2009 5:05pm
Subject:bzr commit into mysql-5.0-bugteam branch (gshchepa:2728) Bug#42037
View as plain text  
#At file:///work/bzr/5.0-42037/ based on revid:azundris@stripped

 2728 Gleb Shchepa	2009-01-29
      Bug #42037: Queries containing a subquery with DISTINCT and
                  ORDER BY could cause a server crash
      
      Dependent subqueries like
      
        SELECT COUNT(*) FROM t1, t2 WHERE t2.b
         IN (SELECT DISTINCT t2.b FROM t2 WHERE t2.b = t1.a)
      
      hogged memory or even caused server crash on tables with
      significant number of rows (for example, this query failed
      on 1000 of records in every table and 50M of free
      virtual memory).
      
      Subselect engine resets JOIN structure of dependent inner
      query on every row of outer table. In this case restore_tmp()
      reset tmp_join->join_tab_reexec and tmp_join->table_reexec
      methods to NULL pointers and the next call to make_simple_join()
      reallocated them again and again.
      
      The make_simple_join() function has been modified to
      JOIN class method to store join_tab_reexec and
      table_reexec values in the parent join only
      (make_simple_join of tmp_join may access these values
      via 'this' pointer of the parent JOIN).
      
      NOTE: this patch doesn't include standard test case (this is
      "out of memory" bug). See bug #42037 page for test cases.
modified:
  sql/sql_select.cc
  sql/sql_select.h

per-file messages:
  sql/sql_select.cc
    Bug #42037: Queries containing a subquery with DISTINCT and
                ORDER BY could cause a server crash
    
    The make_simple_join() function has been modified to
    JOIN class method to store join_tab_reexec and
    table_reexec values in the parent join only
    (make_simple_join of tmp_join may access these values
    via 'this' pointer of the parent JOIN).
  sql/sql_select.h
    Bug #42037: Queries containing a subquery with DISTINCT and
                ORDER BY could cause a server crash
    
    The make_simple_join() function has been modified to
    JOIN class method.
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2008-12-24 15:24:11 +0000
+++ b/sql/sql_select.cc	2009-01-29 17:05:03 +0000
@@ -78,7 +78,6 @@ static store_key *get_store_key(THD *thd
 				KEYUSE *keyuse, table_map used_tables,
 				KEY_PART_INFO *key_part, char *key_buff,
 				uint maybe_null);
-static bool make_simple_join(JOIN *join,TABLE *tmp_table);
 static void make_outerjoin_info(JOIN *join);
 static bool make_join_select(JOIN *join,SQL_SELECT *select,COND *item);
 static void make_join_readinfo(JOIN *join, ulonglong options);
@@ -5414,37 +5413,33 @@ store_val_in_field(Field *field, Item *i
 }
 
 
-static bool
-make_simple_join(JOIN *join,TABLE *tmp_table)
+/**
+  @brief Make simple join
+
+  @param  join        'this' or this->tmp_join, to build simple join there
+  @param  tmp_table   temporary table
+
+  @retval FALSE       success
+  @retval TRUE        error occurred
+*/
+bool
+JOIN::make_simple_join(JOIN *join, TABLE *tmp_table)
 {
-  TABLE **tableptr;
-  JOIN_TAB *join_tab;
-  DBUG_ENTER("make_simple_join");
+  DBUG_ENTER("JOIN::make_simple_join");
 
   /*
     Reuse TABLE * and JOIN_TAB if already allocated by a previous call
     to this function through JOIN::exec (may happen for sub-queries).
   */
-  if (!join->table_reexec)
-  {
-    if (!(join->table_reexec= (TABLE**) join->thd->alloc(sizeof(TABLE*))))
-      DBUG_RETURN(TRUE);                        /* purecov: inspected */
-    if (join->tmp_join)
-      join->tmp_join->table_reexec= join->table_reexec;
-  }
-  if (!join->join_tab_reexec)
-  {
-    if (!(join->join_tab_reexec=
-          (JOIN_TAB*) join->thd->alloc(sizeof(JOIN_TAB))))
-      DBUG_RETURN(TRUE);                        /* purecov: inspected */
-    if (join->tmp_join)
-      join->tmp_join->join_tab_reexec= join->join_tab_reexec;
-  }
-  tableptr= join->table_reexec;
-  join_tab= join->join_tab_reexec;
+  if (!table_reexec &&
+      !(table_reexec= (TABLE**) thd->alloc(sizeof(TABLE*))))
+    DBUG_RETURN(TRUE);                        /* purecov: inspected */
+  if (!join_tab_reexec &&
+      !(join_tab_reexec= (JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB))))
+    DBUG_RETURN(TRUE);                        /* purecov: inspected */
 
-  join->join_tab=join_tab;
-  join->table=tableptr; tableptr[0]=tmp_table;
+  join->join_tab= join_tab_reexec;
+  join->table=table_reexec; table_reexec[0]=tmp_table;
   join->tables=1;
   join->const_tables=0;
   join->const_table_map=0;
@@ -5457,24 +5452,25 @@ make_simple_join(JOIN *join,TABLE *tmp_t
   join->row_limit=join->unit->select_limit_cnt;
   join->do_send_rows = (join->row_limit) ? 1 : 0;
 
-  join_tab->cache.buff=0;			/* No caching */
-  join_tab->table=tmp_table;
-  join_tab->select=0;
-  join_tab->select_cond=0;
-  join_tab->quick=0;
-  join_tab->type= JT_ALL;			/* Map through all records */
-  join_tab->keys.init();
-  join_tab->keys.set_all();                     /* test everything in quick */
-  join_tab->info=0;
-  join_tab->on_expr_ref=0;
-  join_tab->last_inner= 0;
-  join_tab->first_unmatched= 0;
-  join_tab->ref.key = -1;
-  join_tab->not_used_in_distinct=0;
-  join_tab->read_first_record= join_init_read_record;
-  join_tab->join=join;
-  join_tab->ref.key_parts= 0;
-  bzero((char*) &join_tab->read_record,sizeof(join_tab->read_record));
+  join_tab_reexec->cache.buff=0;                        /* No caching */
+  join_tab_reexec->table=tmp_table;
+  join_tab_reexec->select=0;
+  join_tab_reexec->select_cond=0;
+  join_tab_reexec->quick=0;
+  join_tab_reexec->type= JT_ALL;                   /* Map through all records */
+  join_tab_reexec->keys.init();
+  join_tab_reexec->keys.set_all();                /* test everything in quick */
+  join_tab_reexec->info=0;
+  join_tab_reexec->on_expr_ref=0;
+  join_tab_reexec->last_inner= 0;
+  join_tab_reexec->first_unmatched= 0;
+  join_tab_reexec->ref.key = -1;
+  join_tab_reexec->not_used_in_distinct=0;
+  join_tab_reexec->read_first_record= join_init_read_record;
+  join_tab_reexec->join=join;
+  join_tab_reexec->ref.key_parts= 0;
+  bzero((char*) &join_tab_reexec->read_record,
+        sizeof(join_tab_reexec->read_record));
   tmp_table->status=0;
   tmp_table->null_row=0;
   DBUG_RETURN(FALSE);

=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h	2008-12-24 15:24:11 +0000
+++ b/sql/sql_select.h	2009-01-29 17:05:03 +0000
@@ -476,6 +476,8 @@ public:
     return (unit == &thd->lex->unit && (unit->fake_select_lex == 0 ||
                                         select_lex == unit->fake_select_lex));
   }
+private:
+  bool make_simple_join(JOIN *join, TABLE *tmp_table);
 };
 
 

Thread
bzr commit into mysql-5.0-bugteam branch (gshchepa:2728) Bug#42037Gleb Shchepa29 Jan