List:Commits« Previous MessageNext Message »
From:Jorgen Loland Date:March 17 2011 7:40am
Subject:bzr push into mysql-trunk branch (jorgen.loland:3773 to 3774)
View as plain text  
 3774 Jorgen Loland	2011-03-17 [merge]
      Automerge opt-team -> trunk. No conflicts

    added:
      mysql-test/r/optimizer_debug_sync.result
      mysql-test/t/optimizer_debug_sync.test
    modified:
      mysql-test/r/union.result
      sql/ha_partition.cc
      sql/item_subselect.cc
      sql/item_subselect.h
      sql/sql_lex.h
      sql/sql_select.cc
      sql/sql_select.h
      sql/sql_union.cc
 3773 Kent Boortz	2011-03-16 [merge]
      Removed the "Third-Party Component Notices" part from README

    modified:
      README
=== added file 'mysql-test/r/optimizer_debug_sync.result'
--- a/mysql-test/r/optimizer_debug_sync.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/optimizer_debug_sync.result	2011-03-01 14:57:53 +0000
@@ -0,0 +1,23 @@
+
+BUG#11763382 Assertion 'inited==INDEX' on SELECT MAX(...)
+
+CREATE TABLE t(i INT NOT NULL PRIMARY KEY, f INT) ENGINE = InnoDB;
+INSERT INTO t VALUES (1,1),(2,2);
+BEGIN;
+UPDATE t SET f=100 WHERE i=2;
+set optimizer_switch='semijoin=off';
+SET DEBUG_SYNC='before_index_end_in_subselect WAIT_FOR callit';
+SELECT f FROM t WHERE i IN ( SELECT i FROM t );
+SELECT MAX(i) FROM t FOR UPDATE;
+SELECT MAX(i) FROM t FOR UPDATE;
+SET DEBUG_SYNC='now SIGNAL callit';
+COMMIT;
+f
+1
+2
+SET DEBUG_SYNC='RESET';
+MAX(i)
+2
+MAX(i)
+2
+DROP TABLE t;

=== modified file 'mysql-test/r/union.result'
--- a/mysql-test/r/union.result	2011-01-10 12:45:53 +0000
+++ b/mysql-test/r/union.result	2011-03-01 14:57:53 +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

=== added file 'mysql-test/t/optimizer_debug_sync.test'
--- a/mysql-test/t/optimizer_debug_sync.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/optimizer_debug_sync.test	2011-03-02 11:51:03 +0000
@@ -0,0 +1,61 @@
+# This test checks various optimizer-related functions using
+# the debug-sync facility.
+
+--source include/have_debug_sync.inc
+--source include/have_innodb.inc
+--source include/have_materialization.inc
+
+--echo
+--echo BUG#11763382 Assertion 'inited==INDEX' on SELECT MAX(...)
+--echo
+
+CREATE TABLE t(i INT NOT NULL PRIMARY KEY, f INT) ENGINE = InnoDB;
+INSERT INTO t VALUES (1,1),(2,2);
+
+BEGIN;
+UPDATE t SET f=100 WHERE i=2;
+
+--connect (con1,localhost,root,,)
+
+set optimizer_switch='semijoin=off';
+
+SET DEBUG_SYNC='before_index_end_in_subselect WAIT_FOR callit';
+--send SELECT f FROM t WHERE i IN ( SELECT i FROM t )
+
+--connection default
+let $show_statement= SHOW PROCESSLIST;
+let $field= State;
+let $condition= = 'debug sync point: before_index_end_in_subselect';
+--source include/wait_show_condition.inc
+
+--connect (con2,localhost,root,,)
+--send SELECT MAX(i) FROM t FOR UPDATE
+
+--connect (con3,localhost,root,,)
+--send SELECT MAX(i) FROM t FOR UPDATE
+
+--connection default
+
+let $wait_condition=
+  SELECT COUNT(*) = 2 FROM information_schema.processlist 
+  WHERE state = 'Optimizing' and info = 'SELECT MAX(i) FROM t FOR UPDATE';
+--source include/wait_condition.inc
+
+SET DEBUG_SYNC='now SIGNAL callit';
+COMMIT;
+
+--connection con1
+--reap
+SET DEBUG_SYNC='RESET';
+
+--connection con2
+--reap
+
+--connection con3
+--reap
+
+DROP TABLE t;
+
+--exit
+
+--echo # End of BUG#56080

=== modified file 'sql/ha_partition.cc'
--- a/sql/ha_partition.cc	2011-03-09 17:55:32 +0000
+++ b/sql/ha_partition.cc	2011-03-17 07:40:26 +0000
@@ -3523,7 +3523,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	2011-03-08 19:14:42 +0000
+++ b/sql/item_subselect.cc	2011-03-17 07:40:26 +0000
@@ -38,6 +38,7 @@
 #include "set_var.h"
 #include "sql_select.h"
 #include "sql_parse.h"                          // check_stack_overrun
+#include "debug_sync.h"
 
 inline Item * and_items(Item* cond, Item *item)
 {
@@ -120,7 +121,10 @@ void Item_subselect::cleanup()
   if (old_engine)
   {
     if (engine)
+    {
       engine->cleanup();
+      delete engine;
+    }
     engine= old_engine;
     old_engine= 0;
   }
@@ -279,8 +283,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.
@@ -295,7 +297,7 @@ bool Item_subselect::exec()
   */
   DBUG_EXECUTE_IF("subselect_exec_fail", return 1;);
 
-  res= engine->exec();
+  const bool res= engine->exec();
 
   if (engine_changed)
   {
@@ -1886,18 +1888,13 @@ void Item_in_subselect::fix_after_pullou
 
 
 /**
-  Try to create an engine to compute the subselect via materialization,
-  and if this fails, revert to execution via the IN=>EXISTS transformation.
+  Create an engine to compute the subquery via materialization.
 
   @details
     The purpose of this method is to hide the implementation details
     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
@@ -1906,43 +1903,29 @@ 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);
+  /* The decision whether to materialize is already taken. */
+  DBUG_ASSERT(exec_method == Item_exists_subselect::EXEC_MATERIALIZATION);
 
-    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);
   }
 
   /*
@@ -1955,10 +1938,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);
 }
 
 
@@ -2096,7 +2076,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;
 }
@@ -2123,23 +2102,13 @@ bool subselect_union_engine::is_executed
     FALSE - Otherwise
 */
 
-bool subselect_union_engine::no_rows()
+bool subselect_union_engine::no_rows() const
 {
   /* Check if we got any rows when reading UNION result from temp. table: */
   return test(!unit->fake_select_lex->join->send_records);
 }
 
 
-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)
@@ -2176,7 +2145,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;
@@ -2203,12 +2172,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);
@@ -2231,7 +2202,7 @@ int subselect_uniquesubquery_engine::pre
     FALSE - Otherwise
 */
 
-bool subselect_single_select_engine::no_rows()
+bool subselect_single_select_engine::no_rows() const
 { 
   return !item->assigned();
 }
@@ -2301,7 +2272,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");
   int rc= 0;
@@ -2334,11 +2305,7 @@ int subselect_single_select_engine::exec
       select_lex->uncacheable != UNCACHEABLE_EXPLAIN
       && executed)
   {
-    if (join->reinit())
-    {
-      rc= 1;
-      goto exit;
-    }
+    join->reset();
     item->reset();
     item->assigned((executed= 0));
   }
@@ -2404,10 +2371,10 @@ exit:
   DBUG_RETURN(rc);
 }
 
-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;
 }
@@ -2431,7 +2398,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;
@@ -2596,7 +2563,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;
@@ -2699,7 +2666,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;
@@ -2786,26 +2753,26 @@ int subselect_indexsubquery_engine::exec
 }
 
 
-uint subselect_single_select_engine::cols()
+uint subselect_single_select_engine::cols() const
 {
   return select_lex->item_list.elements;
 }
 
 
-uint subselect_union_engine::cols()
+uint subselect_union_engine::cols() const
 {
   DBUG_ASSERT(unit->is_prepared());  // should be called after fix_fields()
   return unit->types.elements;
 }
 
 
-uint8 subselect_single_select_engine::uncacheable()
+uint8 subselect_single_select_engine::uncacheable() const
 {
   return select_lex->uncacheable;
 }
 
 
-uint8 subselect_union_engine::uncacheable()
+uint8 subselect_union_engine::uncacheable() const
 {
   return unit->uncacheable;
 }
@@ -2892,13 +2859,13 @@ subselect_single_select_engine::save_joi
   return FALSE;
 }
 
-table_map subselect_single_select_engine::upper_select_const_tables()
+table_map subselect_single_select_engine::upper_select_const_tables() const
 {
   return calc_const_tables(select_lex->outer_select()->leaf_tables);
 }
 
 
-table_map subselect_union_engine::upper_select_const_tables()
+table_map subselect_union_engine::upper_select_const_tables() const
 {
   return calc_const_tables(unit->outer_select()->leaf_tables);
 }
@@ -3066,7 +3033,7 @@ bool subselect_uniquesubquery_engine::ch
   @retval
     FALSE there are some tables in subquery
 */
-bool subselect_single_select_engine::no_tables()
+bool subselect_single_select_engine::no_tables() const
 {
   return(select_lex->table_list.elements == 0);
 }
@@ -3082,7 +3049,7 @@ bool subselect_single_select_engine::no_
     FALSE  can guarantee that the subquery never return NULL
     TRUE   otherwise
 */
-bool subselect_single_select_engine::may_be_null()
+bool subselect_single_select_engine::may_be_null() const
 {
   return ((no_tables() && !join->conds && !join->having) ? maybe_null : 1);
 }
@@ -3096,7 +3063,7 @@ bool subselect_single_select_engine::may
   @retval
     FALSE there are some tables in subquery
 */
-bool subselect_union_engine::no_tables()
+bool subselect_union_engine::no_tables() const
 {
   for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
   {
@@ -3116,7 +3083,7 @@ bool subselect_union_engine::no_tables()
     FALSE there are some tables in subquery
 */
 
-bool subselect_uniquesubquery_engine::no_tables()
+bool subselect_uniquesubquery_engine::no_tables() const
 {
   /* returning value is correct, but this method should never be called */
   return 0;
@@ -3129,8 +3096,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
@@ -3148,7 +3114,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;
@@ -3158,7 +3124,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. */
 
@@ -3204,8 +3170,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. */
 
@@ -3300,43 +3266,24 @@ 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()
 {
+  /* Assure that cleanup has been called for this engine. */
+  DBUG_ASSERT(!tab);
+
   delete result;
-  if (tab)
-    free_tmp_table(thd, tab->table);
 }
 
 
@@ -3349,10 +3296,16 @@ 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. */
+  DEBUG_SYNC(thd, "before_index_end_in_subselect");
+  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;
 }
 
 
@@ -3367,7 +3320,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;
 
@@ -3379,17 +3332,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	2011-03-08 19:14:42 +0000
+++ b/sql/item_subselect.h	2011-03-17 07:40:26 +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,13 +110,13 @@ public:
 		     select_result_interceptor *result);
 
   ~Item_subselect();
-  void cleanup();
+  virtual void cleanup();
   virtual void reset()
   {
     null_value= 1;
   }
   virtual trans_res select_transformer(JOIN *join);
-  bool assigned() { return value_assigned; }
+  bool assigned() const { return value_assigned; }
   void assigned(bool a) { value_assigned= a; }
   enum Type type() const;
   bool is_null()
@@ -190,10 +191,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();
@@ -240,7 +241,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; }
@@ -292,7 +293,7 @@ public:
     return RES_OK;
   }
   subs_type substype() { return EXISTS_SUBS; }
-  void reset() 
+  virtual void reset() 
   {
     value= 0;
   }
@@ -380,9 +381,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;
@@ -455,15 +456,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;
 
   /*
@@ -471,8 +470,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
@@ -494,23 +493,23 @@ 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 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 bool exec()= 0;
+  virtual uint cols() const = 0; /* return number of columns in select */
+  virtual uint8 uncacheable() const = 0; /* query is uncacheable */
+  virtual enum Item_result type() const { return res_type; }
+  virtual 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;
+  virtual bool may_be_null() const { return maybe_null; };
+  virtual table_map upper_select_const_tables() const = 0;
   static table_map calc_const_tables(TABLE_LIST *);
   virtual void print(String *str, enum_query_type query_type)= 0;
   virtual bool change_result(Item_subselect *si,
                              select_result_interceptor *result)= 0;
-  virtual bool no_tables()= 0;
+  virtual bool no_tables() const = 0;
   virtual bool is_executed() const { return FALSE; }
   /* Check if subquery produced any rows during last query execution */
-  virtual bool no_rows() = 0;
-  virtual enum_engine_type engine_type() { return ABSTRACT_ENGINE; }
+  virtual bool no_rows() const = 0;
+  virtual enum_engine_type engine_type() const { return ABSTRACT_ENGINE; }
 
 protected:
   void set_row(List<Item> &item_list, Item_cache **row);
@@ -519,30 +518,31 @@ 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() const;
+  virtual uint8 uncacheable() const;
+  virtual void exclude();
+  virtual table_map upper_select_const_tables() const;
   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 enum_engine_type engine_type() { return SINGLE_SELECT_ENGINE; }
+  virtual bool change_result(Item_subselect *si,
+                             select_result_interceptor *result);
+  virtual bool no_tables() const;
+  virtual bool may_be_null() const;
+  virtual bool is_executed() const { return executed; }
+  virtual bool no_rows() const;
+  virtual enum_engine_type engine_type() const { return SINGLE_SELECT_ENGINE; }
   bool save_join_if_explain(); 
 
   friend class subselect_hash_sj_engine;
@@ -552,25 +552,28 @@ public:
 
 class subselect_union_engine: public subselect_engine
 {
-  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() const;
+  virtual uint8 uncacheable() const;
+  virtual void exclude();
+  virtual table_map upper_select_const_tables() const;
   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 enum_engine_type engine_type() { return UNION_ENGINE; }
+  virtual bool change_result(Item_subselect *si,
+                             select_result_interceptor *result);
+  virtual bool no_tables() const;
+  virtual bool is_executed() const;
+  virtual bool no_rows() const;
+  virtual enum_engine_type engine_type() const { return UNION_ENGINE; }
+
+private:
+  st_select_lex_unit *unit;  /* corresponding unit structure */
 };
 
 
@@ -614,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() const { return 1; }
+  virtual uint8 uncacheable() const { return UNCACHEABLE_DEPENDENT; }
+  virtual void exclude();
+  virtual table_map upper_select_const_tables() const { 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() const;
+  bool scan_table();
   bool copy_ref_key();
-  bool no_rows() { return empty_result_set; }
-  virtual enum_engine_type engine_type() { return UNIQUESUBQUERY_ENGINE; }
+  virtual bool no_rows() const { return empty_result_set; }
+  virtual enum_engine_type engine_type() const { return UNIQUESUBQUERY_ENGINE; }
 };
 
 
 class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine
 {
+private:
   /* FALSE for 'ref', TRUE for 'ref-or-null'. */
   bool check_null;
   /* 
@@ -676,9 +681,9 @@ 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; }
+  virtual enum_engine_type engine_type() const { return INDEXSUBQUERY_ENGINE; }
 };
 
 /*
@@ -711,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;
 
@@ -734,23 +735,22 @@ 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() const
   {
     return materialize_engine->cols();
   }
-  virtual enum_engine_type engine_type() { return HASH_SJ_ENGINE; }
+  virtual enum_engine_type engine_type() const { return HASH_SJ_ENGINE; }
 };
 #endif /* ITEM_SUBSELECT_INCLUDED */

=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h	2011-03-11 09:35:38 +0000
+++ b/sql/sql_lex.h	2011-03-17 07:40:26 +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_select.cc'
--- a/sql/sql_select.cc	2011-03-11 09:35:38 +0000
+++ b/sql/sql_select.cc	2011-03-17 07:40:26 +0000
@@ -2645,10 +2645,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() :
@@ -2699,7 +2703,7 @@ JOIN::reinit()
   if (!(select_options & SELECT_DESCRIBE))
     init_ftfuncs(thd, select_lex, test(order));
 
-  DBUG_RETURN(0);
+  DBUG_VOID_RETURN;
 }
 
 /**
@@ -3394,14 +3398,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;
@@ -3427,6 +3429,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);
@@ -3443,7 +3450,7 @@ JOIN::destroy()
 
   delete_dynamic(&keyuse);
   delete procedure;
-  DBUG_RETURN(error);
+  DBUG_RETURN(test(error));
 }
 
 
@@ -3539,8 +3546,8 @@ mysql_select(THD *thd, Item ***rref_poin
           subselect execution. So we need to restore them.
         */
         Item_subselect *subselect= select_lex->master_unit()->item;
-        if (subselect && subselect->is_uncacheable() && join->reinit())
-          DBUG_RETURN(TRUE);
+        if (subselect && subselect->is_uncacheable())
+          join->reset();
       }
       else
       {
@@ -3592,6 +3599,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)
@@ -11388,7 +11397,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()
@@ -23335,7 +23349,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	2011-03-09 20:54:55 +0000
+++ b/sql/sql_select.h	2011-03-17 07:40:26 +0000
@@ -1918,9 +1918,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-11-11 09:40:06 +0000
+++ b/sql/sql_union.cc	2011-03-01 14:57:53 +0000
@@ -214,16 +214,16 @@ bool st_select_lex_unit::prepare(THD *th
       /* fast reinit for EXPLAIN */
       for (sl= first_sl; sl; sl= sl->next_select())
       {
-	sl->join->result= result;
-	select_limit_cnt= HA_POS_ERROR;
-	offset_limit_cnt= 0;
-	if (!sl->join->procedure &&
-	    result->prepare(sl->join->fields_list, this))
-	{
-	  DBUG_RETURN(TRUE);
-	}
-	sl->join->select_options|= SELECT_DESCRIBE;
-	sl->join->reinit();
+        sl->join->result= result;
+        select_limit_cnt= HA_POS_ERROR;
+        offset_limit_cnt= 0;
+        if (!sl->join->procedure &&
+            result->prepare(sl->join->fields_list, this))
+        {
+          DBUG_RETURN(TRUE);
+        }
+        sl->join->select_options|= SELECT_DESCRIBE;
+        sl->join->reset();
       }
     }
     DBUG_RETURN(FALSE);
@@ -469,8 +469,8 @@ bool st_select_lex_unit::exec()
   DBUG_ENTER("st_select_lex_unit::exec");
 
   if (executed && !uncacheable && !describe)
-    DBUG_RETURN(FALSE);
-  executed= 1;
+    DBUG_RETURN(false);
+  executed= true;
   
   if (uncacheable || !item || !item->assigned() || describe)
   {
@@ -496,19 +496,22 @@ 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);
-	if (sl == global_parameters || describe)
-	{
-	  offset_limit_cnt= 0;
-	  /*
-	    We can't use LIMIT at this stage if we are using ORDER BY for the
-	    whole query
-	  */
-	  if (sl->order_list.first || describe)
-	    select_limit_cnt= HA_POS_ERROR;
+        if (sl == global_parameters || describe)
+        {
+          offset_limit_cnt= 0;
+          /*
+            We can't use LIMIT at this stage if we are using ORDER BY for the
+            whole query
+          */
+          if (sl->order_list.first || describe)
+            select_limit_cnt= HA_POS_ERROR;
         }
 
         /*
@@ -520,62 +523,62 @@ bool st_select_lex_unit::exec()
           (select_limit_cnt == HA_POS_ERROR || sl->braces) ?
           sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union;
 
-	saved_error= sl->join->optimize();
+        saved_error= sl->join->optimize();
       }
       if (!saved_error)
       {
-	records_at_start= table->file->stats.records;
-	sl->join->exec();
+        records_at_start= table->file->stats.records;
+        sl->join->exec();
         if (sl == union_distinct)
-	{
-	  if (table->file->ha_disable_indexes(HA_KEY_SWITCH_ALL))
-	    DBUG_RETURN(TRUE);
-	  table->no_keyread=1;
-	}
-	saved_error= sl->join->error;
-	offset_limit_cnt= (ha_rows)(sl->offset_limit ?
+        {
+          if (table->file->ha_disable_indexes(HA_KEY_SWITCH_ALL))
+            DBUG_RETURN(true);
+          table->no_keyread=1;
+        }
+        saved_error= sl->join->error;
+        offset_limit_cnt= (ha_rows)(sl->offset_limit ?
                                     sl->offset_limit->val_uint() :
                                     0);
-	if (!saved_error)
-	{
-	  examined_rows+= thd->examined_row_count;
-	  if (union_result->flush())
-	  {
-	    thd->lex->current_select= lex_select_save;
-	    DBUG_RETURN(1);
-	  }
-	}
+        if (!saved_error)
+        {
+          examined_rows+= thd->examined_row_count;
+          if (union_result->flush())
+          {
+            thd->lex->current_select= lex_select_save;
+            DBUG_RETURN(true);
+          }
+        }
       }
       if (saved_error)
       {
-	thd->lex->current_select= lex_select_save;
-	DBUG_RETURN(saved_error);
+        thd->lex->current_select= lex_select_save;
+        DBUG_RETURN(saved_error);
       }
       /* Needed for the following test and for records_at_start in next loop */
       int error= table->file->info(HA_STATUS_VARIABLE);
       if(error)
       {
         table->file->print_error(error, MYF(0));
-        DBUG_RETURN(1);
+        DBUG_RETURN(true);
       }
       if (found_rows_for_union && !sl->braces && 
           select_limit_cnt != HA_POS_ERROR)
       {
-	/*
-	  This is a union without braces. Remember the number of rows that
-	  could also have been part of the result set.
-	  We get this from the difference of between total number of possible
-	  rows and actual rows added to the temporary table.
-	*/
-	add_rows+= (ulonglong) (thd->limit_found_rows - (ulonglong)
-			      ((table->file->stats.records -  records_at_start)));
+        /*
+          This is a union without braces. Remember the number of rows that
+          could also have been part of the result set.
+          We get this from the difference of between total number of possible
+          rows and actual rows added to the temporary table.
+        */
+        add_rows+= (ulonglong) (thd->limit_found_rows -
+                   (ulonglong)(table->file->stats.records - records_at_start));
       }
     }
   }
-  optimized= 1;
+  optimized= true;
 
   /* Send result to 'result' */
-  saved_error= TRUE;
+  saved_error= true;
   {
     List<Item_func_match> empty_list;
     empty_list.empty();
@@ -587,27 +590,27 @@ bool st_select_lex_unit::exec()
       JOIN *join= fake_select_lex->join;
       if (!join)
       {
-	/*
-	  allocate JOIN for fake select only once (prevent
-	  mysql_select automatic allocation)
+        /*
+          allocate JOIN for fake select only once (prevent
+          mysql_select automatic allocation)
           TODO: The above is nonsense. mysql_select() will not allocate the
           join if one already exists. There must be some other reason why we
           don't let it allocate the join. Perhaps this is because we need
           some special parameter values passed to join constructor?
 	*/
-	if (!(fake_select_lex->join= new JOIN(thd, item_list,
-					      fake_select_lex->options, result)))
+        if (!(fake_select_lex->join=
+            new JOIN(thd, item_list, fake_select_lex->options, result)))
 	{
-	  fake_select_lex->table_list.empty();
-	  DBUG_RETURN(TRUE);
+          fake_select_lex->table_list.empty();
+          DBUG_RETURN(true);
 	}
-        fake_select_lex->join->no_const_tables= TRUE;
+        fake_select_lex->join->no_const_tables= true;
 
-	/*
-	  Fake st_select_lex should have item list for correctref_array
-	  allocation.
-	*/
-	fake_select_lex->item_list= item_list;
+        /*
+          Fake st_select_lex should have item list for correctref_array
+          allocation.
+        */
+        fake_select_lex->item_list= item_list;
         saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
                               &result_table_list,
                               0, item_list, NULL,
@@ -630,7 +633,7 @@ bool st_select_lex_unit::exec()
             subquery execution rather than EXPLAIN line production. In order 
             to reset them back, we re-do all of the actions (yes it is ugly):
           */
-	  join->init(thd, item_list, fake_select_lex->options, result);
+          join->init(thd, item_list, fake_select_lex->options, result);
           saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
                                 &result_table_list,
                                 0, item_list, NULL,
@@ -643,7 +646,8 @@ bool st_select_lex_unit::exec()
         else
         {
           join->examined_rows= 0;
-          saved_error= join->reinit();
+          saved_error= false;
+          join->reset();
           join->exec();
         }
       }
@@ -655,8 +659,8 @@ bool st_select_lex_unit::exec()
         thd->examined_row_count+= examined_rows;
       }
       /*
-	Mark for slow query log if any of the union parts didn't use
-	indexes efficiently
+        Mark for slow query log if any of the union parts didn't use
+        indexes efficiently
       */
     }
   }
@@ -665,16 +669,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)
   {
@@ -812,6 +825,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;
@@ -827,7 +847,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();

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (jorgen.loland:3773 to 3774) Jorgen Loland17 Mar