List:Commits« Previous MessageNext Message »
From:Roy Lyseng Date:November 9 2010 3:29pm
Subject:bzr commit into mysql-next-mr-bugfixing branch (roy.lyseng:3280) Bug#56080
View as plain text  
#At file:///home/rl136806/mysql/repo/mysql-work3/ based on revid:olav.sandstaa@stripped

 3280 Roy Lyseng	2010-11-09
      Bug#56080: Assertion 'inited=INDEX in sql/handler.h
      
      The problem occurs because some TABLE objects are associated with
      the optimizer execution structures even after close_thread_tables()
      has been called. In turn, this means that final cleanup of some
      TABLE objects is done from within THD::cleanup_after_query().
      At this point in time, the TABLE objects may already have been
      given to another session, meaning that we may end another session's
      index or table scan.
      
      The safest solution seems to be to always perform a thorough cleanup
      of all execution data structures, including releasing the TABLE
      objects, before close_thread_tables() is called. In other words,
      this will have to be done at the end of each execution.
      
      However, this is currently not possible in the implementation of
      subquery materialization. This part of the optimizer assigns some
      objects, including a TABLE object, for the lifetime of the
      statement object, and not for each execution. This gives an odd
      situation, where some parts of the data structures are set up for
      reuse and others are not. Combine this with the fact that the
      user may decide to use another strategy for a subsequent
      subquery execution, the "permanent" data structures may not even
      be used later.
      
      It is therefore reasonable to allocate materialization execution
      structures for the lifetime of one execution. It means that the
      functions init_permanent() and init_runtime() of class
      subselect_hash_sj_engine are combined into one setup() function.
      In addition, the function Item_subselect::cleanup() will be called
      when the cleanup() function for the underlying query expression
      is called, and this function will cleanup and destroy the
      materialization data structures, so that the subquery item object
      is ready for a new optimization process in the next round of
      execution.
      
      However, the EXPLAIN functionality relies on these data
      structures being present when explaining a query containing
      a materialized subquery. Thus, we have two conflicting
      requirements for query cleanup:
       - For maximum efficiency we should release resources as early as
         possible after execution.
       - We cannot release resources that are needed for EXPLAIN queries.
      
      One solution to this problem is to split resource cleanup in two:
      1. Delete JOIN objects as soon as possible - this makes sense 
         because TABLE objects are associated with them through JOIN_TAB.
         But notice that JOIN objects may be needed for EXPLAIN queries...
      2. Cleanup query expression objects (ie st_select_lex and
         st_select_lex_unit) later (in practice at end of query execution).
      
      Because this bug was caused by a race condition, no simple test case
      has been made.
      
      mysql-test/r/union.result
        Change in EXPLAIN EXTENDED output that shows an optimized predicate
        in the two query specifications within a UNION in a subquery.
        AFAIK, this is similar to how a non-subquery is reported, so the
        change is an improvement.
      
      sql/ha_partition.cc
        Comment change.
      
      sql/item_subselect.cc
        In Item_subselect::cleanup(), "new" engine is always deleted after
        an execution.
        Item_in_subselect::setup_engine() now builds the materialization
        engine for one execution only. Specific arena is no longer needed.
        In subselect_union_engine::cleanup(), call to
        unit->reinit_exec_mechanism is deleted because it is redundant.
        Implementation of cleanup() functions for subclasses of
        subselect_engine has been refactored.
        subselect_hash_sj_engine::setup() replaces init_permanent() and
        init_runtime().
        For class subselect_hash_sj_engine, freeing of the temporary
        result table is moved from the destructor to ::cleanup().
        Some changes necessary because of interface changes.
      
      sql/item_subselect.h
        Some cleanup of the subselect_engine classes:
         - All virtual functions now marked virtual in all derived classes.
         - Functions that returned bool result are now declared accordingly.
         - Slight cleanup of private/protected/public performed.
         - Improved constructors.
      
      sql/sql_lex.h
        Change in friend declaration.
      
      sql/sql_select.cc
        Function JOIN::reinit() is renamed to JOIN::reset().
        JOIN::destroy() will now delete connection to associated tables.
        The st_select_lex_unit object is no longer cleaned up as early as
        before, but instead relying on the general cleanup of lex->unit
        in mysql_execute_command().
      
      sql/sql_select.h
        A few small interface changes.
      
      sql/sql_union.cc
        Cleaned up some confusing error handling in st_select_lex_unit::exec()
        and st_select_lex::cleanup().

    modified:
      mysql-test/r/union.result
      sql/ha_partition.cc
      sql/item_subselect.cc
      sql/item_subselect.h
      sql/sql_lex.h
      sql/sql_parse.cc
      sql/sql_plugin.cc
      sql/sql_plugin.h
      sql/sql_select.cc
      sql/sql_select.h
      sql/sql_union.cc
=== modified file 'mysql-test/r/union.result'
--- a/mysql-test/r/union.result	2010-08-18 10:18:27 +0000
+++ b/mysql-test/r/union.result	2010-11-09 15:29:16 +0000
@@ -480,7 +480,7 @@ id	select_type	table	type	possible_keys	
 2	UNION	t2	const	PRIMARY	PRIMARY	4	const	1	100.00	
 NULL	UNION RESULT	<union1,2>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
 Warnings:
-Note	1003	(select '1' AS `a`,'1' AS `b` from `test`.`t1` where ('1' = 1)) union (select '1' AS `a`,'10' AS `b` from `test`.`t2` where ('1' = 1))
+Note	1003	(select '1' AS `a`,'1' AS `b` from `test`.`t1` where 1) union (select '1' AS `a`,'10' AS `b` from `test`.`t2` where 1)
 (select * from t1 where a=5) union (select * from t2 where a=1);
 a	b
 1	10

=== modified file 'sql/ha_partition.cc'
--- a/sql/ha_partition.cc	2010-10-21 11:34:17 +0000
+++ b/sql/ha_partition.cc	2010-11-09 15:29:16 +0000
@@ -3336,7 +3336,7 @@ int ha_partition::delete_row(const uchar
     Called from item_sum.cc by Item_func_group_concat::clear(),
     Item_sum_count_distinct::clear(), and Item_func_group_concat::clear().
     Called from sql_delete.cc by mysql_delete().
-    Called from sql_select.cc by JOIN::reinit().
+    Called from sql_select.cc by JOIN::reset().
     Called from sql_union.cc by st_select_lex_unit::exec().
 */
 

=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc	2010-10-27 10:28:09 +0000
+++ b/sql/item_subselect.cc	2010-11-09 15:29:16 +0000
@@ -120,7 +120,10 @@ void Item_subselect::cleanup()
   if (old_engine)
   {
     if (engine)
+    {
       engine->cleanup();
+      delete engine;
+    }
     engine= old_engine;
     old_engine= 0;
   }
@@ -293,8 +296,6 @@ bool Item_subselect::walk(Item_processor
 
 bool Item_subselect::exec()
 {
-  int res;
-
   /*
     Do not execute subselect in case of a fatal error
     or if the query has been killed.
@@ -308,7 +309,7 @@ bool Item_subselect::exec()
   */
   DBUG_EXECUTE_IF("subselect_exec_fail", return 1;);
 
-  res= engine->exec();
+  const bool res= engine->exec();
 
   if (engine_changed)
   {
@@ -1905,10 +1906,6 @@ void Item_in_subselect::fix_after_pullou
     of this Item's execution. The method creates a new engine for
     materialized execution, and initializes the engine.
 
-    The initialization of the new engine is divided in two parts - a permanent
-    one that lives across prepared statements, and one that is repeated for each
-    execution.
-
   @returns
     @retval TRUE  memory allocation error occurred, or was not able to create
                   temporary table
@@ -1917,43 +1914,30 @@ void Item_in_subselect::fix_after_pullou
 
 bool Item_in_subselect::setup_engine()
 {
-  subselect_hash_sj_engine *hash_engine;
   DBUG_ENTER("Item_in_subselect::setup_engine");
 
-  if (engine->engine_type() == subselect_engine::SINGLE_SELECT_ENGINE)
-  {
-    /* Create/initialize objects in permanent memory. */
-    Query_arena *arena= thd->stmt_arena;
-    Query_arena backup;
-    if (arena->is_conventional())
-      arena= 0;
-    else
-      thd->set_n_backup_active_arena(arena, &backup);
+  /* Currently, the decision whether to materialize is already taken. */
+  if (exec_method != Item_exists_subselect::EXEC_MATERIALIZATION)
+    DBUG_RETURN(FALSE);
 
-    subselect_single_select_engine *old_engine= 
-      static_cast<subselect_single_select_engine*>(engine);
-    if (!(hash_engine= new subselect_hash_sj_engine(thd, this,
-                                                    old_engine)) ||
-        hash_engine->init_permanent(unit->get_unit_column_types()))
-    {
-      /*
-        For some reason we cannot use materialization for this IN predicate.
-        Delete all materialization-related objects, and return error.
-      */
-      delete hash_engine;
-      if (arena)
-        thd->restore_active_arena(arena, &backup);
-      DBUG_RETURN(TRUE);
-    }
-    engine= hash_engine;
+  DBUG_ASSERT(engine->engine_type() == subselect_engine::SINGLE_SELECT_ENGINE);
 
-    if (arena)
-      thd->restore_active_arena(arena, &backup);
-  }
-  else
+  old_engine= engine;
+
+  if (!(engine= new subselect_hash_sj_engine(thd, this,
+                  static_cast<subselect_single_select_engine*>(old_engine))))
+    DBUG_RETURN(TRUE);
+  if (((subselect_hash_sj_engine *) engine)
+        ->setup(unit->get_unit_column_types()))
   {
-    DBUG_ASSERT(engine->engine_type() == subselect_engine::HASH_SJ_ENGINE);
-    hash_engine= static_cast<subselect_hash_sj_engine*>(engine);
+    /*
+      For some reason we cannot use materialization for this IN predicate.
+      Delete all materialization-related objects, and return error.
+    */
+    delete engine;
+    engine= old_engine;
+    old_engine= NULL;
+    DBUG_RETURN(TRUE);
   }
 
   /*
@@ -1966,10 +1950,7 @@ bool Item_in_subselect::setup_engine()
   */
   unit->global_parameters->select_limit= NULL;
 
-  /* Initializations done in runtime memory, repeated for each execution. */
-  const bool res= hash_engine->init_runtime();
-
-  DBUG_RETURN(res);
+  DBUG_RETURN(FALSE);
 }
 
 
@@ -2106,7 +2087,6 @@ void subselect_single_select_engine::cle
 void subselect_union_engine::cleanup()
 {
   DBUG_ENTER("subselect_union_engine::cleanup");
-  unit->reinit_exec_mechanism();
   result->cleanup();
   DBUG_VOID_RETURN;
 }
@@ -2140,16 +2120,6 @@ bool subselect_union_engine::no_rows()
 }
 
 
-void subselect_uniquesubquery_engine::cleanup()
-{
-  DBUG_ENTER("subselect_uniquesubquery_engine::cleanup");
-  /* Tell handler we don't need the index anymore */
-  if (tab->table->file->inited)
-    tab->table->file->ha_index_end();
-  DBUG_VOID_RETURN;
-}
-
-
 subselect_union_engine::subselect_union_engine(st_select_lex_unit *u,
 					       select_result_interceptor *result_arg,
 					       Item_subselect *item_arg)
@@ -2186,7 +2156,7 @@ subselect_union_engine::subselect_union_
   @retval 1  if error
 */
 
-int subselect_single_select_engine::prepare()
+bool subselect_single_select_engine::prepare()
 {
   if (prepared)
     return 0;
@@ -2213,12 +2183,14 @@ int subselect_single_select_engine::prep
   return 0;
 }
 
-int subselect_union_engine::prepare()
+
+bool subselect_union_engine::prepare()
 {
   return unit->prepare(thd, result, SELECT_NO_UNLOCK);
 }
 
-int subselect_uniquesubquery_engine::prepare()
+
+bool subselect_uniquesubquery_engine::prepare()
 {
   /* Should never be called. */
   DBUG_ASSERT(FALSE);
@@ -2311,7 +2283,7 @@ int rr_sequential(READ_RECORD *info);
 int join_read_always_key_or_null(JOIN_TAB *tab);
 int join_read_next_same_or_null(READ_RECORD *info);
 
-int subselect_single_select_engine::exec()
+bool subselect_single_select_engine::exec()
 {
   DBUG_ENTER("subselect_single_select_engine::exec");
   char const *save_where= thd->where;
@@ -2340,12 +2312,7 @@ int subselect_single_select_engine::exec
       select_lex->uncacheable != UNCACHEABLE_EXPLAIN
       && executed)
   {
-    if (join->reinit())
-    {
-      thd->where= save_where;
-      thd->lex->current_select= save_select;
-      DBUG_RETURN(1);
-    }
+    join->reset();
     item->reset();
     item->assigned((executed= 0));
   }
@@ -2410,10 +2377,10 @@ int subselect_single_select_engine::exec
   DBUG_RETURN(0);
 }
 
-int subselect_union_engine::exec()
+bool subselect_union_engine::exec()
 {
   char const *save_where= thd->where;
-  int res= unit->exec();
+  const bool res= unit->exec();
   thd->where= save_where;
   return res;
 }
@@ -2437,7 +2404,7 @@ int subselect_union_engine::exec()
     TRUE  - Error
 */
 
-int subselect_uniquesubquery_engine::scan_table()
+bool subselect_uniquesubquery_engine::scan_table()
 {
   int error;
   TABLE *table= tab->table;
@@ -2602,7 +2569,7 @@ bool subselect_uniquesubquery_engine::co
     TRUE  - an error occured while scanning
 */
 
-int subselect_uniquesubquery_engine::exec()
+bool subselect_uniquesubquery_engine::exec()
 {
   DBUG_ENTER("subselect_uniquesubquery_engine::exec");
   int error;
@@ -2705,7 +2672,7 @@ int subselect_uniquesubquery_engine::exe
     1
 */
 
-int subselect_indexsubquery_engine::exec()
+bool subselect_indexsubquery_engine::exec()
 {
   DBUG_ENTER("subselect_indexsubquery_engine::exec");
   int error;
@@ -3133,8 +3100,7 @@ bool subselect_uniquesubquery_engine::no
 
 
 /**
-  Create all structures needed for IN execution that can live between PS
-  reexecution.
+  Create all structures needed for subquery execution using hash semijoin.
 
   @detail
   - Create a temporary table to store the result of the IN subquery. The
@@ -3152,7 +3118,7 @@ bool subselect_uniquesubquery_engine::no
   @retval FALSE otherwise
 */
 
-bool subselect_hash_sj_engine::init_permanent(List<Item> *tmp_columns)
+bool subselect_hash_sj_engine::setup(List<Item> *tmp_columns)
 {
   /* The result sink where we will materialize the subquery result. */
   select_union  *tmp_result_sink;
@@ -3162,7 +3128,7 @@ bool subselect_hash_sj_engine::init_perm
   uint          tmp_key_parts; /* Number of keyparts in tmp_key. */
   Item_in_subselect *item_in= (Item_in_subselect *) item;
 
-  DBUG_ENTER("subselect_hash_sj_engine::init_permanent");
+  DBUG_ENTER("subselect_hash_sj_engine::setup");
 
   /* 1. Create/initialize materialization related objects. */
 
@@ -3208,8 +3174,8 @@ bool subselect_hash_sj_engine::init_perm
     Make sure there is only one index on the temp table, and it doesn't have
     the extra key part created when s->uniques > 0.
   */
-  DBUG_ASSERT(tmp_table->s->keys == 1 && tmp_columns->elements == tmp_key_parts);
-
+  DBUG_ASSERT(tmp_table->s->keys == 1 &&
+              tmp_columns->elements == tmp_key_parts);
 
   /* 2. Create/initialize execution related objects. */
 
@@ -3304,43 +3270,22 @@ bool subselect_hash_sj_engine::init_perm
   if (cond->fix_fields(thd, &cond))
     DBUG_RETURN(TRUE);
 
-  DBUG_RETURN(FALSE);
-}
-
-
-/**
-  Initialize members of the engine that need to be re-initilized at each
-  execution.
-
-  @retval TRUE  if a memory allocation error occurred
-  @retval FALSE if success
-*/
-
-bool subselect_hash_sj_engine::init_runtime()
-{
   /*
     Create and optimize the JOIN that will be used to materialize
     the subquery if not yet created.
   */
   materialize_engine->prepare();
-  /*
-    Repeat name resolution for 'cond' since cond is not part of any
-    clause of the query, and it is not 'fixed' during JOIN::prepare.
-  */
-  if (cond && !cond->fixed && cond->fix_fields(thd, &cond))
-    return TRUE;
   /* Let our engine reuse this query plan for materialization. */
-  materialize_join= materialize_engine->join;
-  materialize_join->change_result(result);
-  return FALSE;
+  materialize_engine->join->change_result(result);
+
+  DBUG_RETURN(FALSE);
 }
 
 
 subselect_hash_sj_engine::~subselect_hash_sj_engine()
 {
   delete result;
-  if (tab)
-    free_tmp_table(thd, tab->table);
+  DBUG_ASSERT(!tab);
 }
 
 
@@ -3353,10 +3298,15 @@ subselect_hash_sj_engine::~subselect_has
 
 void subselect_hash_sj_engine::cleanup()
 {
-  is_materialized= FALSE;
+  DBUG_ENTER("subselect_hash_sj_engine::cleanup");
+  is_materialized= false;
   result->cleanup(); /* Resets the temp table as well. */
+  if (tab->table->file->inited)
+    tab->table->file->ha_index_end();  // Close the scan over the index
+  free_tmp_table(thd, tab->table);
+  tab= NULL;
   materialize_engine->cleanup();
-  subselect_uniquesubquery_engine::cleanup();
+  DBUG_VOID_RETURN;
 }
 
 
@@ -3371,7 +3321,7 @@ void subselect_hash_sj_engine::cleanup()
   @retval FALSE otherwise
 */
 
-int subselect_hash_sj_engine::exec()
+bool subselect_hash_sj_engine::exec()
 {
   Item_in_subselect *item_in= (Item_in_subselect *) item;
 
@@ -3383,17 +3333,17 @@ int subselect_hash_sj_engine::exec()
   */
   if (!is_materialized)
   {
-    int res= 0;
+    bool res= false;
     SELECT_LEX *save_select= thd->lex->current_select;
     thd->lex->current_select= materialize_engine->select_lex;
-    if ((res= materialize_join->optimize()))
+    if ((res= materialize_engine->join->optimize()))
       goto err; /* purecov: inspected */
 
     if (materialize_engine->save_join_if_explain())
       goto err;
 
-    materialize_join->exec();
-    if ((res= test(materialize_join->error || thd->is_fatal_error)))
+    materialize_engine->join->exec();
+    if ((res= test(materialize_engine->join->error || thd->is_fatal_error)))
       goto err;
 
     /*

=== modified file 'sql/item_subselect.h'
--- a/sql/item_subselect.h	2010-10-15 10:32:50 +0000
+++ b/sql/item_subselect.h	2010-11-09 15:29:16 +0000
@@ -44,7 +44,8 @@ typedef Comp_creator* (*chooser_compare_
 
 class Item_subselect :public Item_result_field
 {
-  my_bool value_assigned; /* value already assigned to subselect */
+private:
+  bool value_assigned; /* value already assigned to subselect */
 public:
   /* thread handler, will be assigned in fix_fields only */
   THD *thd;
@@ -109,7 +110,7 @@ public:
 		     select_result_interceptor *result);
 
   ~Item_subselect();
-  void cleanup();
+  virtual void cleanup();
   virtual void reset()
   {
     null_value= 1;
@@ -191,10 +192,10 @@ public:
   Item_singlerow_subselect(st_select_lex *select_lex);
   Item_singlerow_subselect() :Item_subselect(), value(0), row (0) {}
 
-  void cleanup();
+  virtual void cleanup();
   subs_type substype() { return SINGLEROW_SUBS; }
 
-  void reset();
+  virtual void reset();
   trans_res select_transformer(JOIN *join);
   void store(uint i, Item* item);
   double val_real();
@@ -241,7 +242,7 @@ public:
   Item_maxmin_subselect(THD *thd, Item_subselect *parent,
 			st_select_lex *select_lex, bool max);
   virtual void print(String *str, enum_query_type query_type);
-  void cleanup();
+  virtual void cleanup();
   bool any_value() { return was_values; }
   void register_value() { was_values= TRUE; }
   void reset_value_registration() { was_values= FALSE; }
@@ -293,7 +294,7 @@ public:
     return RES_OK;
   }
   subs_type substype() { return EXISTS_SUBS; }
-  void reset() 
+  virtual void reset() 
   {
     value= 0;
   }
@@ -381,9 +382,9 @@ public:
     optimizer(NULL), was_null(FALSE), abort_on_null(FALSE),
     pushed_cond_guards(NULL), upper_item(NULL)
   {}
-  void cleanup();
+  virtual void cleanup();
   subs_type substype() { return IN_SUBS; }
-  void reset() 
+  virtual void reset() 
   {
     value= 0;
     null_value= 0;
@@ -456,15 +457,13 @@ public:
                          INDEXSUBQUERY_ENGINE, HASH_SJ_ENGINE};
 
   subselect_engine(Item_subselect *si, select_result_interceptor *res)
-    :thd(0)
-  {
-    result= res;
-    item= si;
-    res_type= STRING_RESULT;
-    res_field_type= MYSQL_TYPE_VAR_STRING;
-    maybe_null= 0;
-  }
+    :result(res), thd(NULL), item(si), res_type(STRING_RESULT),
+    res_field_type(MYSQL_TYPE_VAR_STRING), maybe_null(FALSE)
+  {}
   virtual ~subselect_engine() {}; // to satisfy compiler
+  /**
+    Cleanup engine after complete query execution, free all resources.
+  */
   virtual void cleanup()= 0;
 
   /*
@@ -472,8 +471,8 @@ public:
     Should be called before prepare().
   */
   void set_thd(THD *thd_arg);
-  THD * get_thd() { return thd; }
-  virtual int prepare()= 0;
+  THD * get_thd() const { return thd; }
+  virtual bool prepare()= 0;
   virtual void fix_length_and_dec(Item_cache** row)= 0;
   /*
     Execute the engine
@@ -495,11 +494,11 @@ public:
       1 - Either an execution error, or the engine was "changed", and the
           caller should call exec() again for the new engine.
   */
-  virtual int exec()= 0;
+  virtual bool exec()= 0;
   virtual uint cols()= 0; /* return number of columns in select */
   virtual uint8 uncacheable()= 0; /* query is uncacheable */
-  enum Item_result type() { return res_type; }
-  enum_field_types field_type() { return res_field_type; }
+  virtual const enum Item_result type() const { return res_type; }
+  virtual const enum_field_types field_type() const { return res_field_type; }
   virtual void exclude()= 0;
   virtual bool may_be_null() { return maybe_null; };
   virtual table_map upper_select_const_tables()= 0;
@@ -520,29 +519,30 @@ protected:
 
 class subselect_single_select_engine: public subselect_engine
 {
-  my_bool prepared; /* simple subselect is prepared */
-  my_bool optimized; /* simple subselect is optimized */
-  my_bool executed; /* simple subselect is executed */
+private:
+  bool prepared; /* simple subselect is prepared */
+  bool executed; /* simple subselect is executed */
   st_select_lex *select_lex; /* corresponding select_lex */
   JOIN * join; /* corresponding JOIN structure */
 public:
   subselect_single_select_engine(st_select_lex *select,
 				 select_result_interceptor *result,
 				 Item_subselect *item);
-  void cleanup();
-  int prepare();
-  void fix_length_and_dec(Item_cache** row);
-  int exec();
-  uint cols();
-  uint8 uncacheable();
-  void exclude();
-  table_map upper_select_const_tables();
+  virtual void cleanup();
+  virtual bool prepare();
+  virtual void fix_length_and_dec(Item_cache** row);
+  virtual bool exec();
+  virtual uint cols();
+  virtual uint8 uncacheable();
+  virtual void exclude();
+  virtual table_map upper_select_const_tables();
   virtual void print (String *str, enum_query_type query_type);
-  bool change_result(Item_subselect *si, select_result_interceptor *result);
-  bool no_tables();
-  bool may_be_null();
-  bool is_executed() const { return executed; }
-  bool no_rows();
+  virtual bool change_result(Item_subselect *si,
+                             select_result_interceptor *result);
+  virtual bool no_tables();
+  virtual bool may_be_null();
+  virtual bool is_executed() const { return executed; }
+  virtual bool no_rows();
   virtual enum_engine_type engine_type() { return SINGLE_SELECT_ENGINE; }
   bool save_join_if_explain(); 
 
@@ -553,24 +553,26 @@ public:
 
 class subselect_union_engine: public subselect_engine
 {
+private:
   st_select_lex_unit *unit;  /* corresponding unit structure */
 public:
   subselect_union_engine(st_select_lex_unit *u,
 			 select_result_interceptor *result,
 			 Item_subselect *item);
-  void cleanup();
-  int prepare();
-  void fix_length_and_dec(Item_cache** row);
-  int exec();
-  uint cols();
-  uint8 uncacheable();
-  void exclude();
-  table_map upper_select_const_tables();
+  virtual void cleanup();
+  virtual bool prepare();
+  virtual void fix_length_and_dec(Item_cache** row);
+  virtual bool exec();
+  virtual uint cols();
+  virtual uint8 uncacheable();
+  virtual void exclude();
+  virtual table_map upper_select_const_tables();
   virtual void print (String *str, enum_query_type query_type);
-  bool change_result(Item_subselect *si, select_result_interceptor *result);
-  bool no_tables();
-  bool is_executed() const;
-  bool no_rows();
+  virtual bool change_result(Item_subselect *si,
+                             select_result_interceptor *result);
+  virtual bool no_tables();
+  virtual bool is_executed() const;
+  virtual bool no_rows();
   virtual enum_engine_type engine_type() { return UNION_ENGINE; }
 };
 
@@ -615,26 +617,28 @@ public:
   {
     set_thd(thd_arg);
   }
-  void cleanup();
-  int prepare();
-  void fix_length_and_dec(Item_cache** row);
-  int exec();
-  uint cols() { return 1; }
-  uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; }
-  void exclude();
-  table_map upper_select_const_tables() { return 0; }
+  virtual void cleanup() {}
+  virtual bool prepare();
+  virtual void fix_length_and_dec(Item_cache** row);
+  virtual bool exec();
+  virtual uint cols() { return 1; }
+  virtual uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; }
+  virtual void exclude();
+  virtual table_map upper_select_const_tables() { return 0; }
   virtual void print (String *str, enum_query_type query_type);
-  bool change_result(Item_subselect *si, select_result_interceptor *result);
-  bool no_tables();
-  int scan_table();
+  virtual bool change_result(Item_subselect *si,
+                             select_result_interceptor *result);
+  virtual bool no_tables();
+  bool scan_table();
   bool copy_ref_key();
-  bool no_rows() { return empty_result_set; }
+  virtual bool no_rows() { return empty_result_set; }
   virtual enum_engine_type engine_type() { return UNIQUESUBQUERY_ENGINE; }
 };
 
 
 class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine
 {
+private:
   /* FALSE for 'ref', TRUE for 'ref-or-null'. */
   bool check_null;
   /* 
@@ -677,7 +681,7 @@ public:
      check_null(chk_null),
      having(having_arg)
   {}
-  int exec();
+  virtual bool exec();
   virtual void print (String *str, enum_query_type query_type);
   virtual enum_engine_type engine_type() { return INDEXSUBQUERY_ENGINE; }
 };
@@ -712,21 +716,17 @@ inline bool Item_subselect::is_uncacheab
 
 class subselect_hash_sj_engine: public subselect_uniquesubquery_engine
 {
-protected:
+private:
   /* TRUE if the subquery was materialized into a temp table. */
   bool is_materialized;
   /*
     The old engine already chosen at parse time and stored in permanent memory.
-    Through this member we can re-create and re-prepare materialize_join for
-    each execution of a prepared statement. We also reuse the functionality
-    of subselect_single_select_engine::[prepare | cols].
+    Through this member we can re-create and re-prepare the join object
+    used to materialize the subquery for each execution of a prepared
+    statement. We also reuse the functionality of
+    subselect_single_select_engine::[prepare | cols].
   */
   subselect_single_select_engine *materialize_engine;
-  /*
-    QEP to execute the subquery and materialize its result into a
-    temporary table. Created during the first call to exec().
-  */
-  JOIN *materialize_join;
   /* Temp table context of the outer select's JOIN. */
   TMP_TABLE_PARAM *tmp_param;
 
@@ -735,20 +735,19 @@ public:
                                subselect_single_select_engine *old_engine)
     :subselect_uniquesubquery_engine(thd, NULL, in_predicate, NULL),
     is_materialized(FALSE), materialize_engine(old_engine),
-    materialize_join(NULL), tmp_param(NULL)
+    tmp_param(NULL)
   {}
   ~subselect_hash_sj_engine();
 
-  bool init_permanent(List<Item> *tmp_columns);
-  bool init_runtime();
-  void cleanup();
-  int prepare() 
+  bool setup(List<Item> *tmp_columns);
+  virtual void cleanup();
+  virtual bool prepare() 
   { 
     return materialize_engine->prepare();
   }
-  int exec();
-  void print (String *str, enum_query_type query_type);
-  uint cols()
+  virtual bool exec();
+  virtual void print (String *str, enum_query_type query_type);
+  virtual uint cols()
   {
     return materialize_engine->cols();
   }

=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h	2010-10-25 16:07:05 +0000
+++ b/sql/sql_lex.h	2010-11-09 15:29:16 +0000
@@ -596,7 +596,7 @@ public:
   inline bool is_union (); 
 
   friend void lex_start(THD *thd);
-  friend int subselect_union_engine::exec();
+  friend bool subselect_union_engine::exec();
 
   List<Item> *get_unit_column_types();
 };

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-10-27 14:46:44 +0000
+++ b/sql/sql_parse.cc	2010-11-09 15:29:16 +0000
@@ -5551,6 +5551,8 @@ void mysql_parse(THD *thd, char *rawbuf,
     thd->end_statement();
     thd->cleanup_after_query();
     DBUG_ASSERT(thd->change_list.is_empty());
+    //sql_print_error("Query: %*s", length, rawbuf);
+    //report_memory_plugin();
   }
 
   DBUG_VOID_RETURN;

=== modified file 'sql/sql_plugin.cc'
--- a/sql/sql_plugin.cc	2010-11-05 22:14:29 +0000
+++ b/sql/sql_plugin.cc	2010-11-09 15:29:16 +0000
@@ -1554,6 +1554,19 @@ error:
   DBUG_RETURN(TRUE);
 }
 
+void report_memory_plugin()
+
+{
+  struct st_plugin_int *p;
+
+  for (uint i= 0; i < plugin_array.elements; i++)
+  {
+    p= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
+    if (!strcmp(p->name.str, "MEMORY"))
+      sql_print_error("Plugin '%s' has ref_count=%d",
+                      p->name.str, p->ref_count);
+  }
+}
 
 void plugin_shutdown(void)
 {

=== modified file 'sql/sql_plugin.h'
--- a/sql/sql_plugin.h	2010-10-07 17:34:38 +0000
+++ b/sql/sql_plugin.h	2010-11-09 15:29:16 +0000
@@ -160,4 +160,5 @@ typedef my_bool (plugin_foreach_func)(TH
 #define plugin_foreach(A,B,C,D) plugin_foreach_with_mask(A,B,C,PLUGIN_IS_READY,D)
 extern bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
                                      int type, uint state_mask, void *arg);
+void report_memory_plugin();
 #endif

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2010-11-05 22:19:41 +0000
+++ b/sql/sql_select.cc	2010-11-09 15:29:16 +0000
@@ -2626,10 +2626,14 @@ void JOIN::restore_tmp()
 }
 
 
-int
-JOIN::reinit()
+/**
+  Reset the state of this join object so that it is ready for a
+  new execution.
+*/
+
+void JOIN::reset()
 {
-  DBUG_ENTER("JOIN::reinit");
+  DBUG_ENTER("JOIN::reset");
 
   unit->offset_limit_cnt= (ha_rows)(select_lex->offset_limit ?
                                     select_lex->offset_limit->val_uint() :
@@ -2677,7 +2681,7 @@ JOIN::reinit()
       func->clear();
   }
 
-  DBUG_RETURN(0);
+  DBUG_VOID_RETURN;
 }
 
 /**
@@ -3309,14 +3313,12 @@ JOIN::exec()
 
 
 /**
-  Clean up join.
+  Clean up and destroy join object.
 
-  @return
-    Return error that hold JOIN.
+  @return false if previous execution was successful, and true otherwise
 */
 
-int
-JOIN::destroy()
+bool JOIN::destroy()
 {
   DBUG_ENTER("JOIN::destroy");
   select_lex->join= 0;
@@ -3342,6 +3344,11 @@ JOIN::destroy()
   cond_equal= 0;
 
   cleanup(1);
+  if (join_tab)
+  {
+    for (JOIN_TAB *tab= join_tab; tab < join_tab+tables; tab++)
+      tab->table= NULL;
+  }
  /* Cleanup items referencing temporary table columns */
   cleanup_item_list(tmp_all_fields1);
   cleanup_item_list(tmp_all_fields3);
@@ -3358,7 +3365,7 @@ JOIN::destroy()
 
   delete_dynamic(&keyuse);
   delete procedure;
-  DBUG_RETURN(error);
+  DBUG_RETURN(test(error));
 }
 
 
@@ -3500,6 +3507,8 @@ mysql_select(THD *thd, Item ***rref_poin
     select_lex->where= join->conds_history;
     select_lex->having= join->having_history;
   }
+  if (select_options & SELECT_DESCRIBE)
+    free_join= 0;
 
 err:
   if (free_join)
@@ -4133,9 +4142,7 @@ bool JOIN::setup_subquery_materializatio
           subquery_predicate->substype() == Item_subselect::IN_SUBS)
       {
         Item_in_subselect *in_subs= (Item_in_subselect*) subquery_predicate;
-        if (in_subs->exec_method ==
-              Item_exists_subselect::EXEC_MATERIALIZATION &&
-            in_subs->setup_engine())
+        if (in_subs->setup_engine())
           return TRUE;
       }
     }
@@ -11181,7 +11188,12 @@ bool error_if_full_join(JOIN *join)
 
 
 /**
-  cleanup JOIN_TAB.
+  Cleanup table of join operation.
+
+  @note
+    Notice that this is not a complete cleanup. In some situations, the
+    object may be reused after a cleanup operation, hence we cannot set
+    the table pointer to NULL in this function.
 */
 
 void JOIN_TAB::cleanup()
@@ -23029,7 +23041,6 @@ bool mysql_explain_union(THD *thd, SELEC
     unit->fake_select_lex->options|= SELECT_DESCRIBE;
     if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
       res= unit->exec();
-    res|= unit->cleanup();
   }
   else
   {

=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h	2010-11-05 22:19:41 +0000
+++ b/sql/sql_select.h	2010-11-09 15:29:16 +0000
@@ -1916,9 +1916,9 @@ public:
 	      Item *having, ORDER *proc_param, SELECT_LEX *select,
 	      SELECT_LEX_UNIT *unit);
   int optimize();
-  int reinit();
+  void reset();
   void exec();
-  int destroy();
+  bool destroy();
   void restore_tmp();
   bool alloc_func_list();
   bool flatten_subqueries();

=== modified file 'sql/sql_union.cc'
--- a/sql/sql_union.cc	2010-10-25 09:18:21 +0000
+++ b/sql/sql_union.cc	2010-11-09 15:29:16 +0000
@@ -223,7 +223,7 @@ bool st_select_lex_unit::prepare(THD *th
 	  DBUG_RETURN(TRUE);
 	}
 	sl->join->select_options|= SELECT_DESCRIBE;
-	sl->join->reinit();
+	sl->join->reset();
       }
     }
     DBUG_RETURN(FALSE);
@@ -495,7 +495,10 @@ bool st_select_lex_unit::exec()
       thd->lex->current_select= sl;
 
       if (optimized)
-	saved_error= sl->join->reinit();
+      {
+	saved_error= false;
+        sl->join->reset();
+      }
       else
       {
         set_limit(sl);
@@ -642,7 +645,8 @@ bool st_select_lex_unit::exec()
         else
         {
           join->examined_rows= 0;
-          saved_error= join->reinit();
+          saved_error= false;
+          join->reset();
           join->exec();
         }
       }
@@ -664,16 +668,25 @@ bool st_select_lex_unit::exec()
 }
 
 
+/**
+  Cleanup this query expression object after preparation or one round
+  of execution. After the cleanup, the object can be reused for a
+  new round of execution, but a new optimization will be needed before
+  the execution.
+
+  @return false if previous execution was successful, and true otherwise
+*/
+
 bool st_select_lex_unit::cleanup()
 {
-  int error= 0;
+  bool error= false;
   DBUG_ENTER("st_select_lex_unit::cleanup");
 
   if (cleaned)
   {
     DBUG_RETURN(FALSE);
   }
-  cleaned= 1;
+  cleaned= true;
 
   if (union_result)
   {
@@ -811,6 +824,13 @@ List<Item> *st_select_lex_unit::get_unit
   return &sl->item_list;
 }
 
+
+/**
+  Cleanup after preparation or one round of execution.
+
+  @return false if previous execution was successful, and true otherwise
+*/
+
 bool st_select_lex::cleanup()
 {
   bool error= FALSE;
@@ -826,7 +846,7 @@ bool st_select_lex::cleanup()
   for (SELECT_LEX_UNIT *lex_unit= first_inner_unit(); lex_unit ;
        lex_unit= lex_unit->next_unit())
   {
-    error= (bool) ((uint) error | (uint) lex_unit->cleanup());
+    error|= lex_unit->cleanup();
   }
   non_agg_fields.empty();
   inner_refs_list.empty();


Attachment: [text/bzr-bundle] bzr/roy.lyseng@oracle.com-20101109152916-0vdj2ymr3ujnsuu3.bundle
Thread
bzr commit into mysql-next-mr-bugfixing branch (roy.lyseng:3280) Bug#56080Roy Lyseng9 Nov
  • Re: bzr commit into mysql-next-mr-bugfixing branch (roy.lyseng:3280)Bug#56080Øystein Grøvlen3 Jan
    • Re: bzr commit into mysql-next-mr-bugfixing branch (roy.lyseng:3280)Bug#56080Roy Lyseng4 Jan