List:Commits« Previous MessageNext Message »
From:Roy Lyseng Date:August 19 2010 7:11am
Subject:bzr commit into mysql-next-mr-bugfixing branch (roy.lyseng:3227) Bug#50489
View as plain text  
#At file:///home/rl136806/mysql/repo/mysql-work5/ based on revid:epotemkin@stripped

 3227 Roy Lyseng	2010-08-19
      Bug#50489: another segfault in fix_semijoin_strategies...
      
      This particular problem occurs when we try to execute a query multiple
      times with different optimizer switch settings. On first execution,
      semijoin materialization strategy is a candidate and an
      SJ_MATERIALIZATION_INFO object is created. On second execution,
      materialization strategy is not a candidate, but there is a dangling
      pointer to the SJ_MATERIALIZATION_INFO object created in the prior
      execution. The pointer is followed, and we suffer a segfault.
      
      The solution chosen here is to refactor the SJ_MATERIALIZATION_INFO
      class so that optimization information is put into a new struct
      Semijoin_mat_optimize which is embedded in struct st_nested_join.
      SJ_MATERIALIZATION_INFO itself is renamed to Semijoin_mat_exec.
      
      If semijoin materialization is an allowed strategy and materialization
      is possible for the semijoin in question, the Semijoin_mat_optimize object
      is filled in and an st_position object is created and filled with
      information about the join strategy for the materialization.
      
      Later in the optimization, the materialization strategy is compared
      with other semijoin strategies, and, if selected, an
      Semijoin_mat_exec object is created and attached to the join nest
      representing the semijoin operation.
      The object is then filled with data relevant for semijoin execution,
      such as number of tables involved, whether this is a scan, information
      about temporary table for materialization, etc.
      
      NOTE. This bug no longer occurs on the current souce code base.
            It does however fix bug#46744, which is re-introduced by the
            fix for bug#43768, and it should also be useful because of the
            refactoring effect on the semijoin materialization strategy.
      
      mysql-test/r/optimizer_switch.result
        Added results for test case for bug#50489
      
      mysql-test/t/optimizer_switch.test
        Added test case for bug#50489
      
      sql/sql_class.h
        Optimization data are removed from class SJ_MATERIALIZATION_INFO.
        SJ_MATERIALIZATION_INFO is renamed to Semijoin_mat_exec.
      
      sql/sql_select.cc
        optimize_semijoin_nests() will no longer create
        SJ_MATERIALIZATION_INFO objects. Instead it populates the
        Semijoin_mat_optimize struct inside the nested_join object with estimated
        cost for the materialized semijoin.
      
        fix_semijoin_strategies_for_picked_join_order() is given a boolean
        return value. The return value is necessary because the function may
        create Semijoin_mat_exec objects, hence it must be able to
        return error conditions. Notice that these objects are created and
        populated only if a semijoin materialization strategy is actually
        chosen. Reset of sjm.positions is performed in this function.
      
        advance_sj_state() has been slightly simplified: the "emb_sj_nest"
        is now assigned when the function is entered, in addition to changes
        that was necessitated by the splitting up of SJ_MATERIALIZATION_INFO.
      
        Reset of the pointer sj_nest->sj_mat_exec is added to JOIN::destroy().
      
      sql/sql_select.h
        List with name sjm_info_list is renamed to sjm_exec_list.
      
      sql/sql_test.cc
        New interface for function print_sjm(), made necessary by the splitting
        of SJ_MATERIALIZATION_INFO.
      
      sql/sql_test.h
        New interface for function print_sjm().
      
      sql/table.h
        Defines struct Semijoin_mat_optimize containing estimated cost for a
        materialized semijoin operation.
        The struct is added as a member in struct st_nested_join.

    modified:
      mysql-test/r/optimizer_switch.result
      mysql-test/t/optimizer_switch.test
      sql/sql_class.h
      sql/sql_select.cc
      sql/sql_select.h
      sql/sql_test.cc
      sql/sql_test.h
      sql/table.h
=== modified file 'mysql-test/r/optimizer_switch.result'
--- a/mysql-test/r/optimizer_switch.result	2010-06-18 08:45:53 +0000
+++ b/mysql-test/r/optimizer_switch.result	2010-08-19 07:10:58 +0000
@@ -138,3 +138,69 @@ drop view v1;
 drop procedure p1;
 set SESSION optimizer_switch='default';
 # End of bug#46744
+#
+# Bug#50489: another segfault in fix_semijoin_strategies... 
+#
+CREATE TABLE it (
+id INT NOT NULL,
+expr_key INT NOT NULL,
+expr_nokey INT NOT NULL,
+expr_padder INT DEFAULT NULL,
+KEY expr_key(expr_key)
+);
+INSERT INTO it VALUES (135,218264606,218264606,100);
+INSERT INTO it VALUES (201,810783319,810783319,200);
+CREATE TABLE ot (
+id INT NOT NULL,
+expr_key INT NOT NULL,
+expr_nokey INT NOT NULL,
+KEY expr_key(expr_key)
+);
+CREATE PROCEDURE run_n_times(x int)
+BEGIN
+DECLARE c int;
+WHILE x DO
+SET x = x-1;
+SELECT COUNT(expr_key) INTO c FROM ot
+WHERE expr_key IN (SELECT expr_nokey FROM it)
+AND ot.expr_key<100000000;
+END WHILE;
+END;
+SET optimizer_switch="default";
+call run_n_times(1);
+SET optimizer_switch="firstmatch=off,materialization=off";
+call run_n_times(1);
+SET optimizer_switch="default";
+call run_n_times(1);
+DROP PROCEDURE run_n_times;
+CREATE PROCEDURE run_n_times(x int)
+BEGIN
+DECLARE c int;
+WHILE x DO
+SET x = x-1;
+SELECT COUNT(expr_key) INTO c FROM ot
+WHERE expr_key IN (SELECT expr_nokey FROM it)
+AND ot.expr_key<100000000;
+END WHILE;
+END;
+SET optimizer_switch="firstmatch=off,materialization=off";
+call run_n_times(1);
+SET optimizer_switch="default";
+call run_n_times(1);
+DROP PROCEDURE run_n_times;
+CREATE PROCEDURE run_n_times(x int)
+BEGIN
+DECLARE c int;
+WHILE x DO
+SET x = x-1;
+SELECT COUNT(expr_key) INTO c FROM ot
+WHERE expr_key IN (SELECT expr_nokey FROM it)
+AND ot.expr_key<100000000;
+END WHILE;
+END;
+SET optimizer_switch="semijoin=off,materialization=off";
+call run_n_times(1);
+SET optimizer_switch="default";
+call run_n_times(1);
+DROP PROCEDURE run_n_times;
+DROP TABLE it, ot;

=== modified file 'mysql-test/t/optimizer_switch.test'
--- a/mysql-test/t/optimizer_switch.test	2010-06-18 08:45:53 +0000
+++ b/mysql-test/t/optimizer_switch.test	2010-08-19 07:10:58 +0000
@@ -148,3 +148,64 @@ drop procedure p1;
 set SESSION optimizer_switch='default';
 
 --echo # End of bug#46744
+
+--echo #
+--echo # Bug#50489: another segfault in fix_semijoin_strategies... 
+--echo #
+
+CREATE TABLE it (
+  id INT NOT NULL,
+  expr_key INT NOT NULL,
+  expr_nokey INT NOT NULL,
+  expr_padder INT DEFAULT NULL,
+  KEY expr_key(expr_key)
+);
+INSERT INTO it VALUES (135,218264606,218264606,100);
+INSERT INTO it VALUES (201,810783319,810783319,200);
+CREATE TABLE ot (
+  id INT NOT NULL,
+  expr_key INT NOT NULL,
+  expr_nokey INT NOT NULL,
+  KEY expr_key(expr_key)
+);
+delimiter |;
+let proc_text=
+CREATE PROCEDURE run_n_times(x int)
+BEGIN
+DECLARE c int;
+WHILE x DO
+  SET x = x-1;
+  SELECT COUNT(expr_key) INTO c FROM ot
+  WHERE expr_key IN (SELECT expr_nokey FROM it)
+    AND ot.expr_key<100000000;
+END WHILE;
+END|
+delimiter ;|
+eval $proc_text;
+SET optimizer_switch="default";
+call run_n_times(1);
+SET optimizer_switch="firstmatch=off,materialization=off";
+call run_n_times(1);
+SET optimizer_switch="default";
+call run_n_times(1);
+DROP PROCEDURE run_n_times;
+
+# Re-create procedure to avoid caching effects
+eval $proc_text;
+SET optimizer_switch="firstmatch=off,materialization=off";
+call run_n_times(1);
+SET optimizer_switch="default";
+call run_n_times(1);
+DROP PROCEDURE run_n_times;
+
+# Re-create procedure to avoid caching effects
+eval $proc_text;
+SET optimizer_switch="semijoin=off,materialization=off";
+call run_n_times(1);
+SET optimizer_switch="default";
+call run_n_times(1);
+DROP PROCEDURE run_n_times;
+
+DROP TABLE it, ot;
+
+# End of Bug#50489

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2010-08-12 00:26:10 +0000
+++ b/sql/sql_class.h	2010-08-19 07:10:58 +0000
@@ -3197,63 +3197,32 @@ public:
 struct st_table_ref;
 
 
-/*
-  Optimizer and executor structure for the materialized semi-join info. This
-  structure contains
+/**
+  Executor structure for the materialized semi-join info, which contains
    - The sj-materialization temporary table
    - Members needed to make index lookup or a full scan of the temptable.
 */
-class SJ_MATERIALIZATION_INFO : public Sql_alloc
+class Semijoin_mat_exec : public Sql_alloc
 {
 public:
-  /* Optimal join sub-order */
-  struct st_position *positions;
-
-  uint tables; /* Number of tables in the sj-nest */
-
-  /* Expected #rows in the materialized table */
-  double rows;
-
-  /* 
-    Cost to materialize - execute the sub-join and write rows into temp.table
-  */
-  COST_VECT materialization_cost;
-
-  /* Cost to make one lookup in the temptable */
-  COST_VECT lookup_cost;
-  
-  /* Cost of scanning the materialized table */
-  COST_VECT scan_cost;
-
-  /* --- Execution structures ---------- */
-  
-  /*
-    TRUE <=> This structure is used for execution. We don't necessarily pick
-    sj-materialization, so some of SJ_MATERIALIZATION_INFO structures are not
-    used by materialization
-  */
-  bool is_used;
-  
-  bool materialized; /* TRUE <=> materialization already performed */
-  /*
-    TRUE  - the temptable is read with full scan
-    FALSE - we use the temptable for index lookups
-  */
-  bool is_sj_scan; 
-  
-  /* The temptable and its related info */
-  TMP_TABLE_PARAM sjm_table_param;
-  List<Item> sjm_table_cols;
-  TABLE *table;
-
-  /* Structure used to make index lookups */
-  struct st_table_ref *tab_ref;
-  Item *in_equality; /* See create_subquery_equalities() */
-  /* True if data types allow the MaterializeScan semijoin strategy */
-  bool sjm_scan_allowed;
+  Semijoin_mat_exec(uint table_count, bool is_scan)
+    :table_count(table_count), is_scan(is_scan),
+    materialized(FALSE), table_param(), table_cols(),
+    table(NULL), tab_ref(NULL), in_equality(NULL),
+    join_cond(NULL), copy_field(NULL)
+  {}
+  ~Semijoin_mat_exec() {}
 
-  Item *join_cond; /* See comments in make_join_select() */
-  Copy_field *copy_field; /* Needed for SJ_Materialization scan */
+  const uint table_count;       // Number of tables in the sj-nest
+  const bool is_scan;           // TRUE if executing as a scan, FALSE if lookup
+  bool materialized;            // TRUE <=> materialization has been performed
+  TMP_TABLE_PARAM table_param;  // The temptable and its related info
+  List<Item> table_cols;        // List of columns describing temp. table
+  TABLE *table;                 // Reference to temporary table
+  struct st_table_ref *tab_ref; // Structure used to make index lookups
+  Item *in_equality;            // See create_subquery_equalities()
+  Item *join_cond;              // See comments in make_join_select()
+  Copy_field *copy_field;       // Needed for materialization scan
 };
 
 

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2010-08-13 19:19:23 +0000
+++ b/sql/sql_select.cc	2010-08-19 07:10:58 +0000
@@ -271,8 +271,7 @@ join_read_record_no_init(JOIN_TAB *tab);
 static
 bool subquery_types_allow_materialization(Item_in_subselect *predicate);
 static 
-bool semijoin_types_allow_materialization(TABLE_LIST *sj_nest,
-                                          bool *sjm_scan_allowed);
+bool semijoin_types_allow_materialization(TABLE_LIST *sj_nest);
 static
 bool types_allow_materialization(Item *outer, Item *inner);
 static
@@ -994,11 +993,11 @@ bool subquery_types_allow_materializatio
 /**
   @brief Check if semijoin's compared types allow materialization.
 
-  @param sj_nest Semi-join nest containing information about correlated
-                 expressions.
-  @param[out]    sjm_scan_allowed  TRUE if MaterializeScan strategy allowed.
+  @param[inout] sj_nest Semi-join nest containing information about correlated
+         expressions. Set nested_join->sjm.scan_allowed to TRUE if
+         MaterializeScan strategy allowed.
 
-  @return        TRUE if materialization is allowed, FALSE otherwise
+  @return TRUE if materialization is allowed, FALSE otherwise
 
   @details
     This is a temporary fix for BUG#36752.
@@ -1039,8 +1038,7 @@ bool subquery_types_allow_materializatio
 */
 
 static 
-bool semijoin_types_allow_materialization(TABLE_LIST *sj_nest,
-                                          bool *sjm_scan_allowed)
+bool semijoin_types_allow_materialization(TABLE_LIST *sj_nest)
 {
   DBUG_ENTER("semijoin_types_allow_materialization");
 
@@ -1050,7 +1048,7 @@ bool semijoin_types_allow_materializatio
   List_iterator<Item> it1(sj_nest->nested_join->sj_outer_exprs);
   List_iterator<Item> it2(sj_nest->nested_join->sj_inner_exprs);
 
-  *sjm_scan_allowed= FALSE;
+  sj_nest->nested_join->sjm.scan_allowed= FALSE;
 
   bool all_are_fields= TRUE;
   Item *outer, *inner;
@@ -1061,7 +1059,7 @@ bool semijoin_types_allow_materializatio
     if (!types_allow_materialization(outer, inner))
       DBUG_RETURN(FALSE);
   }
-  *sjm_scan_allowed= all_are_fields;
+  sj_nest->nested_join->sjm.scan_allowed= all_are_fields;
   DBUG_PRINT("info",("semijoin_types_allow_materialization: ok, allowed"));
   DBUG_RETURN(TRUE);
 }
@@ -1569,7 +1567,7 @@ static void destroy_sj_tmp_tables(JOIN *
     free_tmp_table(join->thd, table);
   }
   join->sj_tmp_tables.empty();
-  join->sjm_info_list.empty();
+  join->sjm_exec_list.empty();
 }
 
 
@@ -1596,8 +1594,8 @@ static int clear_sj_tmp_tables(JOIN *joi
       return res; /* purecov: inspected */
   }
 
-  SJ_MATERIALIZATION_INFO *sjm;
-  List_iterator<SJ_MATERIALIZATION_INFO> it2(join->sjm_info_list);
+  Semijoin_mat_exec *sjm;
+  List_iterator<Semijoin_mat_exec> it2(join->sjm_exec_list);
   while ((sjm= it2++))
   {
     sjm->materialized= FALSE;
@@ -3227,6 +3225,12 @@ JOIN::destroy()
   if (exec_tmp_table2)
     free_tmp_table(thd, exec_tmp_table2);
   destroy_sj_tmp_tables(this);
+
+  List_iterator<TABLE_LIST> sj_list_it(select_lex->sj_nests);
+  TABLE_LIST *sj_nest;
+  while ((sj_nest= sj_list_it++))
+    sj_nest->sj_mat_exec= NULL;
+
   delete_dynamic(&keyuse);
   delete procedure;
   DBUG_RETURN(error);
@@ -4855,14 +4859,16 @@ static bool optimize_semijoin_nests(JOIN
   DBUG_ENTER("optimize_semijoin_nests");
   List_iterator<TABLE_LIST> sj_list_it(join->select_lex->sj_nests);
   TABLE_LIST *sj_nest;
-  /*
-    The statement may have been executed with 'semijoin=on' earlier.
-    We need to verify that 'semijoin=on' still holds.
-   */
-  if (join->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_SEMIJOIN) &&
-      join->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_MATERIALIZATION))
+
+  while ((sj_nest= sj_list_it++))
   {
-    while ((sj_nest= sj_list_it++))
+    /* As a precaution, reset pointers that were used in prior execution */
+    sj_nest->sj_mat_exec= NULL;
+    sj_nest->nested_join->sjm.positions= NULL;
+
+    /* Calculate the cost of materialization if materialization is allowed. */
+    if (join->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_SEMIJOIN) &&
+        join->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_MATERIALIZATION))
     {
       /* semi-join nests with only constant tables are not valid */
       DBUG_ASSERT(sj_nest->sj_inner_tables & ~join->const_table_map);
@@ -4870,14 +4876,12 @@ static bool optimize_semijoin_nests(JOIN
         Try semijoin materialization if the semijoin is classified as
         non-trivially-correlated.
       */ 
-      sj_nest->sj_mat_info= NULL;
       if (sj_nest->nested_join->sj_corr_tables)
         continue;
       /*
         Check whether data types allow execution with materialization.
       */
-      bool sjm_scan_allowed;
-      if (semijoin_types_allow_materialization(sj_nest, &sjm_scan_allowed))
+      if (semijoin_types_allow_materialization(sj_nest))
       {
         join->emb_sjm_nest= sj_nest;
         if (choose_plan(join, all_table_map & ~join->const_table_map))
@@ -4886,22 +4890,14 @@ static bool optimize_semijoin_nests(JOIN
           The best plan to run the subquery is now in join->best_positions,
           save it.
         */
-        uint n_tables= my_count_bits(sj_nest->sj_inner_tables);
-        SJ_MATERIALIZATION_INFO* sjm;
-        if (!(sjm= new SJ_MATERIALIZATION_INFO) ||
-            !(sjm->positions= (POSITION*)join->thd->alloc(sizeof(POSITION)*
-                                                          n_tables)))
-          DBUG_RETURN(TRUE); /* purecov: inspected */
-        sjm->tables= n_tables;
-        sjm->is_used= FALSE;
-        sjm->sjm_scan_allowed= sjm_scan_allowed;
-
+        const uint n_tables= my_count_bits(sj_nest->sj_inner_tables);
         double subjoin_out_rows, subjoin_read_time;
         get_partial_join_cost(join, n_tables,
                               &subjoin_read_time, &subjoin_out_rows);
 
-        sjm->materialization_cost.convert_from_cost(subjoin_read_time);
-        sjm->rows= subjoin_out_rows;
+        sj_nest->nested_join->sjm.materialization_cost
+          .convert_from_cost(subjoin_read_time);
+        sj_nest->nested_join->sjm.expected_rowcount= subjoin_out_rows;
 
         List<Item> &inner_expr_list= sj_nest->nested_join->sj_inner_exprs;
         /*
@@ -4920,7 +4916,7 @@ static bool optimize_semijoin_nests(JOIN
                 nest (the payoff is probably less here?)
         */
         {
-          for (uint i=0 ; i < join->const_tables + sjm->tables ; i++)
+          for (uint i=0 ; i < join->const_tables + n_tables ; i++)
           {
             JOIN_TAB *tab= join->best_positions[i].table;
             join->map2table[tab->table->tablenr]= tab;
@@ -4936,10 +4932,16 @@ static bool optimize_semijoin_nests(JOIN
           double rows= 1.0;
           while ((tableno = tm_it.next_bit()) != Table_map_iterator::BITMAP_END)
             rows *= join->map2table[tableno]->table->quick_condition_rows;
-          sjm->rows= min(sjm->rows, rows);
+          sj_nest->nested_join->sjm.expected_rowcount=
+            min(sj_nest->nested_join->sjm.expected_rowcount, rows);
         }
-        memcpy(sjm->positions, join->best_positions + join->const_tables, 
-               sizeof(POSITION) * n_tables);
+        if (!(sj_nest->nested_join->sjm.positions=
+              (st_position*)join->thd->alloc(sizeof(st_position)*n_tables)))
+          DBUG_RETURN(TRUE);
+
+        memcpy(sj_nest->nested_join->sjm.positions,
+               join->best_positions + join->const_tables, 
+               sizeof(st_position) * n_tables);
 
         /*
           Calculate temporary table parameters and usage costs
@@ -4955,19 +4957,19 @@ static bool optimize_semijoin_nests(JOIN
           Let materialization cost include the cost to write the data into the
           temporary table:
         */ 
-        sjm->materialization_cost.add_io(subjoin_out_rows, lookup_cost);
+        sj_nest->nested_join->sjm.materialization_cost
+          .add_io(subjoin_out_rows, lookup_cost);
         
         /*
           Set the cost to do a full scan of the temptable (will need this to 
           consider doing sjm-scan):
         */ 
-        sjm->scan_cost.zero();
-        if (sjm->rows > 0.0)
-          sjm->scan_cost.add_io(sjm->rows, lookup_cost);
-
-        sjm->lookup_cost.convert_from_cost(lookup_cost);
-        sj_nest->sj_mat_info= sjm;
-        DBUG_EXECUTE("opt", print_sjm(sjm););
+        sj_nest->nested_join->sjm.scan_cost.zero();
+        if (sj_nest->nested_join->sjm.expected_rowcount > 0.0)
+          sj_nest->nested_join->sjm.scan_cost
+           .add_io(sj_nest->nested_join->sjm.expected_rowcount, lookup_cost);
+
+        sj_nest->nested_join->sjm.lookup_cost.convert_from_cost(lookup_cost);
       }
     }
   }
@@ -7485,7 +7487,7 @@ semijoin_order_allows_materialization(co
   */
   const TABLE_LIST *emb_sj_nest= tab->emb_sj_nest;
   if (!emb_sj_nest ||
-      !emb_sj_nest->sj_mat_info ||
+      !emb_sj_nest->nested_join->sjm.positions ||
       (remaining_tables & emb_sj_nest->sj_inner_tables))
     return SJ_OPT_NONE;
 
@@ -7506,7 +7508,7 @@ semijoin_order_allows_materialization(co
   */
   if (remaining_tables & emb_sj_nest->nested_join->sj_depends_on)
   {
-    if (emb_sj_nest->sj_mat_info->sjm_scan_allowed)
+    if (emb_sj_nest->nested_join->sjm.scan_allowed)
       return SJ_OPT_MATERIALIZE_SCAN;
     return SJ_OPT_NONE;
   }
@@ -8158,14 +8160,14 @@ prev_record_reads(JOIN *join, uint idx, 
 }
 
 
-/*
-  Fix semi-join strategies for the picked join order
+/**
+  @brief Fix semi-join strategies for the picked join order
 
-  SYNOPSIS
-    fix_semijoin_strategies_for_picked_join_order()
-      join  The join with the picked join order
+  @param join Pointer to JOIN object with picked join order
 
-  DESCRIPTION
+  @return FALSE if success, TRUE if error
+
+  @details
     Fix semi-join strategies for the picked join order. This is a step that
     needs to be done right after we have fixed the join order. What we do
     here is switch join's semi-join strategy description from backward-based
@@ -8200,16 +8202,19 @@ prev_record_reads(JOIN *join, uint idx, 
     join and semi-join order from left to right.
 */    
 
-static void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
+static bool fix_semijoin_strategies_for_picked_join_order(JOIN *join)
 {
-  uint table_count=join->tables;
   uint tablenr;
   table_map remaining_tables= 0;
   table_map handled_tabs= 0;
-  for (tablenr= table_count - 1 ; tablenr != join->const_tables - 1; tablenr--)
+
+  DBUG_ENTER("fix_semijoin_strategies_for_picked_join_order");
+
+  for (tablenr= join->tables - 1 ; tablenr != join->const_tables - 1; tablenr--)
   {
     POSITION *pos= join->best_positions + tablenr;
     JOIN_TAB *s= pos->table;
+    TABLE_LIST *emb_sj_nest= s->emb_sj_nest;
     uint first;
     LINT_INIT(first); // Set by every branch except SJ_OPT_NONE which doesn't use it
 
@@ -8221,9 +8226,12 @@ static void fix_semijoin_strategies_for_
 
     if (pos->sj_strategy == SJ_OPT_MATERIALIZE_LOOKUP)
     {
-      SJ_MATERIALIZATION_INFO *sjm= s->emb_sj_nest->sj_mat_info;
-      sjm->is_used= TRUE;
-      sjm->is_sj_scan= FALSE;
+      const uint table_count= my_count_bits(emb_sj_nest->sj_inner_tables);
+      Semijoin_mat_exec* sjm_exec;
+      if (!(sjm_exec= new (join->thd->mem_root)
+                          Semijoin_mat_exec(table_count, FALSE)))
+        DBUG_RETURN(TRUE);
+      emb_sj_nest->sj_mat_exec= sjm_exec;
       /*
         This memcpy() copies a partial QEP produced by
         optimize_semijoin_nests() (source) into the final top-level QEP
@@ -8239,23 +8247,30 @@ static void fix_semijoin_strategies_for_
         setting it to SJ_OPT_NONE). But until then, pos->sj_strategy should
         not be read.
       */
-      memcpy(pos - sjm->tables + 1, sjm->positions, 
-             sizeof(POSITION) * sjm->tables);
-      first= tablenr - sjm->tables + 1;
-      join->best_positions[first].n_sj_tables= sjm->tables;
+      memcpy(pos - table_count + 1, emb_sj_nest->nested_join->sjm.positions, 
+             sizeof(POSITION) * table_count);
+      first= tablenr - table_count + 1;
+      join->best_positions[first].n_sj_tables= table_count;
       join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE_LOOKUP;
+
+      DBUG_EXECUTE("opt", print_sjm(emb_sj_nest););
     }
     else if (pos->sj_strategy == SJ_OPT_MATERIALIZE_SCAN)
     {
       POSITION *first_inner= join->best_positions + pos->sjm_scan_last_inner;
-      SJ_MATERIALIZATION_INFO *sjm= first_inner->table->emb_sj_nest->sj_mat_info;
-      sjm->is_used= TRUE;
-      sjm->is_sj_scan= TRUE;
-      first= pos->sjm_scan_last_inner - sjm->tables + 1;
+      TABLE_LIST *mat_sj_nest= first_inner->table->emb_sj_nest;
+      const uint table_count= my_count_bits(mat_sj_nest->sj_inner_tables);
+      Semijoin_mat_exec* sjm_exec;
+      if (!(sjm_exec= new (join->thd->mem_root)
+                          Semijoin_mat_exec(table_count, TRUE)))
+        DBUG_RETURN(TRUE);
+      mat_sj_nest->sj_mat_exec= sjm_exec;
+      first= pos->sjm_scan_last_inner - table_count + 1;
       memcpy(join->best_positions + first, // stale semijoin strategy here too
-             sjm->positions, sizeof(POSITION) * sjm->tables);
+             mat_sj_nest->nested_join->sjm.positions,
+             sizeof(POSITION) * table_count);
       join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE_SCAN;
-      join->best_positions[first].n_sj_tables= sjm->tables;
+      join->best_positions[first].n_sj_tables= table_count;
       /* 
         Do what advance_sj_state did: re-run best_access_path for every table
         in the [last_inner_table + 1; pos..) range
@@ -8268,22 +8283,24 @@ static void fix_semijoin_strategies_for_
         prefix_rec_count= join->best_positions[first-1].prefix_record_count;
       
       /* Add materialization record count*/
-      prefix_rec_count *= sjm->rows;
+      prefix_rec_count *= mat_sj_nest->nested_join->sjm.expected_rowcount;
       
       uint i;
       table_map rem_tables= remaining_tables;
-      for (i= tablenr; i != (first + sjm->tables - 1); i--)
+      for (i= tablenr; i != (first + table_count - 1); i--)
         rem_tables |= join->best_positions[i].table->table->map;
 
       POSITION dummy;
       join->cur_sj_inner_tables= 0;
-      for (i= first + sjm->tables; i <= tablenr; i++)
+      for (i= first + table_count; i <= tablenr; i++)
       {
         best_access_path(join, join->best_positions[i].table, rem_tables, i, FALSE,
                          prefix_rec_count, join->best_positions + i, &dummy);
         prefix_rec_count *= join->best_positions[i].records_read;
         rem_tables &= ~join->best_positions[i].table->table->map;
       }
+
+      DBUG_EXECUTE("opt", print_sjm(mat_sj_nest););
     }
     else if (pos->sj_strategy == SJ_OPT_FIRST_MATCH)
     {
@@ -8378,6 +8395,14 @@ static void fix_semijoin_strategies_for_
       pos->sj_strategy= SJ_OPT_NONE;
     remaining_tables |= s->table->map;
   }
+
+  /* sjm.positions is no longer needed, reset the reference to it */
+  List_iterator<TABLE_LIST> sj_list_it(join->select_lex->sj_nests);
+  TABLE_LIST *sj_nest;
+  while ((sj_nest= sj_list_it++))
+    sj_nest->nested_join->sjm.positions= NULL;
+
+  DBUG_RETURN(FALSE);
 }
 
 
@@ -8391,8 +8416,8 @@ static void fix_semijoin_strategies_for_
 
   DESCRIPTION
     Setup join structures according the picked join order
-    - finalize semi-join strategy choices (see
-        fix_semijoin_strategies_for_picked_join_order)
+    - finalize semi-join strategy choices
+      (see fix_semijoin_strategies_for_picked_join_order)
     - create join->join_tab array and put there the JOIN_TABs in the join order
     - create data structures describing ref access methods.
 
@@ -8419,7 +8444,8 @@ static bool get_best_combination(JOIN *j
 
   used_tables= OUTER_REF_TABLE_BIT;		// Outer row is already read
 
-  fix_semijoin_strategies_for_picked_join_order(join);
+  if (fix_semijoin_strategies_for_picked_join_order(join))
+    DBUG_RETURN(TRUE);
 
   for (j=join_tab, tablenr=0 ; tablenr < table_count ; tablenr++,j++)
   {
@@ -9197,8 +9223,8 @@ static bool make_join_select(JOIN *join,
          - If we're looking at the first SJM table, reset used_tables
            to refer to only allowed tables
       */
-      if (tab->emb_sj_nest && tab->emb_sj_nest->sj_mat_info && 
-          tab->emb_sj_nest->sj_mat_info->is_used &&
+      if (tab->emb_sj_nest &&
+          tab->emb_sj_nest->sj_mat_exec && 
           !(used_tables & tab->emb_sj_nest->sj_inner_tables))
       {
         save_used_tables= used_tables;
@@ -9459,7 +9485,7 @@ static bool make_join_select(JOIN *join,
            - A condition that can be checked when we have all of the tables
              in the prefix (both inner and outer).
         */
-        tab->emb_sj_nest->sj_mat_info->join_cond= 
+        tab->emb_sj_nest->sj_mat_exec->join_cond= 
           cond ?
              make_cond_after_sjm(cond, cond, save_used_tables, used_tables):
             NULL;
@@ -10275,20 +10301,20 @@ end_sj_materialize(JOIN *join, JOIN_TAB 
 {
   int error;
   THD *thd= join->thd;
-  SJ_MATERIALIZATION_INFO *sjm= join_tab[-1].emb_sj_nest->sj_mat_info;
+  Semijoin_mat_exec *sjm= join_tab[-1].emb_sj_nest->sj_mat_exec;
   DBUG_ENTER("end_sj_materialize");
   if (!end_of_records)
   {
     TABLE *table= sjm->table;
 
-    List_iterator<Item> it(sjm->sjm_table_cols);
+    List_iterator<Item> it(sjm->table_cols);
     Item *item;
     while ((item= it++))
     {
       if (item->is_null())
         DBUG_RETURN(NESTED_LOOP_OK);
     }
-    fill_record(thd, table->field, sjm->sjm_table_cols, 1);
+    fill_record(thd, table->field, sjm->table_cols, 1);
     if (thd->is_error())
       DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
     if ((error= table->file->ha_write_row(table->record[0])))
@@ -10296,8 +10322,8 @@ end_sj_materialize(JOIN *join, JOIN_TAB 
       /* create_myisam_from_heap will generate error if needed */
       if (table->file->is_fatal_error(error, HA_CHECK_DUP) &&
           create_myisam_from_heap(thd, table,
-                                  sjm->sjm_table_param.start_recinfo, 
-                                  &sjm->sjm_table_param.recinfo, error,
+                                  sjm->table_param.start_recinfo, 
+                                  &sjm->table_param.recinfo, error,
                                   TRUE, NULL))
         DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
     }
@@ -10365,7 +10391,7 @@ void remove_sj_conds(Item **tree)
 Item *create_subquery_equalities(THD *thd, TABLE_LIST *sj_nest)
 {
   Item *res= NULL;
-  SJ_MATERIALIZATION_INFO *sjm= sj_nest->sj_mat_info;
+  Semijoin_mat_exec *sjm= sj_nest->sj_mat_exec;
   List_iterator<Item> outer_expr(sj_nest->nested_join->sj_outer_exprs);
 
   for (uint i= 0; i < sj_nest->nested_join->sj_outer_exprs.elements; i++)
@@ -10409,23 +10435,23 @@ bool setup_sj_materialization(JOIN_TAB *
   uint i;
   DBUG_ENTER("setup_sj_materialization");
   TABLE_LIST *emb_sj_nest= tab->table->pos_in_table_list->embedding;
-  SJ_MATERIALIZATION_INFO *sjm= emb_sj_nest->sj_mat_info;
+  Semijoin_mat_exec *sjm= emb_sj_nest->sj_mat_exec;
   THD *thd= tab->join->thd;
   /* First the calls come to the materialization function */
   List<Item> &item_list= emb_sj_nest->nested_join->sj_inner_exprs;
   /* 
     Set up the table to write to, do as select_union::create_result_table does
   */
-  sjm->sjm_table_param.init();
-  sjm->sjm_table_param.field_count= item_list.elements;
-  sjm->sjm_table_param.bit_fields_as_long= TRUE;
+  sjm->table_param.init();
+  sjm->table_param.field_count= item_list.elements;
+  sjm->table_param.bit_fields_as_long= TRUE;
   List_iterator<Item> it(item_list);
   Item *right_expr;
   while((right_expr= it++))
-    sjm->sjm_table_cols.push_back(right_expr);
+    sjm->table_cols.push_back(right_expr);
 
-  if (!(sjm->table= create_tmp_table(thd, &sjm->sjm_table_param, 
-                                     sjm->sjm_table_cols, (ORDER*) 0, 
+  if (!(sjm->table= create_tmp_table(thd, &sjm->table_param, 
+                                     sjm->table_cols, (ORDER*) 0, 
                                      TRUE /* distinct */, 
                                      1, /*save_sum_fields*/
                                      thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS, 
@@ -10435,10 +10461,10 @@ bool setup_sj_materialization(JOIN_TAB *
   sjm->table->file->extra(HA_EXTRA_WRITE_CACHE);
   sjm->table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
   tab->join->sj_tmp_tables.push_back(sjm->table);
-  tab->join->sjm_info_list.push_back(sjm);
+  tab->join->sjm_exec_list.push_back(sjm);
   
   sjm->materialized= FALSE;
-  if (!sjm->is_sj_scan)
+  if (!sjm->is_scan)
   {
     KEY           *tmp_key; /* The only index on the temporary table. */
     uint          tmp_key_parts; /* Number of keyparts in tmp_key. */
@@ -10500,7 +10526,7 @@ bool setup_sj_materialization(JOIN_TAB *
       sj-inner tables which are not available after the materialization
       has been finished.
     */
-    for (i= 0; i < sjm->tables; i++)
+    for (i= 0; i < sjm->table_count; i++)
     {
       remove_sj_conds(&tab[i].select_cond);
       if (tab[i].select)
@@ -10538,9 +10564,9 @@ bool setup_sj_materialization(JOIN_TAB *
       temptable record, we copy its columns to their corresponding columns
       in the record buffers for the source tables. 
     */
-    sjm->copy_field= new Copy_field[sjm->sjm_table_cols.elements];
+    sjm->copy_field= new Copy_field[sjm->table_cols.elements];
     it.rewind();
-    for (uint i=0; i < sjm->sjm_table_cols.elements; i++)
+    for (uint i=0; i < sjm->table_cols.elements; i++)
     {
       bool dummy;
       Item_equal *item_eq;
@@ -12329,8 +12355,7 @@ Item *eliminate_item_equal(Item *cond, C
       */
       TABLE_LIST *emb_nest= 
         item_field->field->table->pos_in_table_list->embedding;
-      if (!item_const && emb_nest && emb_nest->sj_mat_info &&
-          emb_nest->sj_mat_info->is_used)
+      if (!item_const && emb_nest && emb_nest->sj_mat_exec)
       {
         /* 
           Find the first equal expression that refers to a table that is
@@ -13419,7 +13444,7 @@ void advance_sj_state(JOIN *join, table_
                       double *current_record_count, double *current_read_time, 
                       POSITION *loose_scan_pos)
 {
-  TABLE_LIST *emb_sj_nest;
+  TABLE_LIST *emb_sj_nest= new_join_tab->emb_sj_nest;
   POSITION *pos= join->positions + idx;
   remaining_tables &= ~new_join_tab->table->map;
 
@@ -13469,13 +13494,11 @@ void advance_sj_state(JOIN *join, table_
   
   table_map handled_by_fm_or_ls= 0;
   /* FirstMatch Strategy */
-  if (new_join_tab->emb_sj_nest &&
+  if (emb_sj_nest &&
       join->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_FIRSTMATCH))
   {
-    const table_map outer_corr_tables=
-      new_join_tab->emb_sj_nest->nested_join->sj_depends_on;
-    const table_map sj_inner_tables=
-      new_join_tab->emb_sj_nest->sj_inner_tables;
+    const table_map outer_corr_tables= emb_sj_nest->nested_join->sj_depends_on;
+    const table_map sj_inner_tables=   emb_sj_nest->sj_inner_tables;
     /* 
       Enter condition:
        1. The next join tab belongs to semi-join nest
@@ -13560,7 +13583,7 @@ void advance_sj_state(JOIN *join, table_
     */
     if ((pos->first_loosescan_table != MAX_TABLES) &&   // (1)
         (first->table->emb_sj_nest->sj_inner_tables & remaining_tables) && //(2)
-        new_join_tab->emb_sj_nest != first->table->emb_sj_nest) //(2)
+        emb_sj_nest != first->table->emb_sj_nest) //(2)
     {
       pos->first_loosescan_table= MAX_TABLES;
     }
@@ -13572,9 +13595,8 @@ void advance_sj_state(JOIN *join, table_
     if (loose_scan_pos->read_time != DBL_MAX)
     {
       pos->first_loosescan_table= idx;
-      pos->loosescan_need_tables=
-        new_join_tab->emb_sj_nest->sj_inner_tables | 
-        new_join_tab->emb_sj_nest->nested_join->sj_depends_on;
+      pos->loosescan_need_tables=  emb_sj_nest->sj_inner_tables |
+                                   emb_sj_nest->nested_join->sj_depends_on;
     }
     
     if ((pos->first_loosescan_table != MAX_TABLES) && 
@@ -13623,7 +13645,7 @@ void advance_sj_state(JOIN *join, table_
     Update join->cur_sj_inner_tables (Used by FirstMatch in this function and
     LooseScan detector in best_access_path)
   */
-  if ((emb_sj_nest= new_join_tab->emb_sj_nest))
+  if (emb_sj_nest)
   {
     join->cur_sj_inner_tables |= emb_sj_nest->sj_inner_tables;
     pos->dups_producing_tables |= emb_sj_nest->sj_inner_tables;
@@ -13660,16 +13682,15 @@ void advance_sj_state(JOIN *join, table_
       we reach the point #2.
     */
     pos->sjm_scan_need_tables=
-      new_join_tab->emb_sj_nest->sj_inner_tables | 
-      new_join_tab->emb_sj_nest->nested_join->sj_depends_on |
-      new_join_tab->emb_sj_nest->nested_join->sj_corr_tables;
+      emb_sj_nest->sj_inner_tables | 
+      emb_sj_nest->nested_join->sj_depends_on |
+      emb_sj_nest->nested_join->sj_corr_tables;
     pos->sjm_scan_last_inner= idx;
   }
   else if (sjm_strategy == SJ_OPT_MATERIALIZE_LOOKUP)
   {
     COST_VECT prefix_cost; 
-    SJ_MATERIALIZATION_INFO *mat_info= emb_sj_nest->sj_mat_info;
-    signed int first_tab= (int)idx - mat_info->tables;
+    int first_tab= (int)idx - my_count_bits(emb_sj_nest->sj_inner_tables);
     double prefix_rec_count;
     if (first_tab < (int)join->const_tables)
     {
@@ -13683,8 +13704,9 @@ void advance_sj_state(JOIN *join, table_
     }
 
     double mat_read_time= prefix_cost.total_cost();
-    mat_read_time += mat_info->materialization_cost.total_cost() +
-                     prefix_rec_count * mat_info->lookup_cost.total_cost();
+    mat_read_time +=
+      emb_sj_nest->nested_join->sjm.materialization_cost.total_cost() +
+      prefix_rec_count * emb_sj_nest->nested_join->sjm.lookup_cost.total_cost();
 
     if (mat_read_time < *current_read_time || pos->dups_producing_tables)
     {
@@ -13697,8 +13719,7 @@ void advance_sj_state(JOIN *join, table_
       pos->sj_strategy= SJ_OPT_MATERIALIZE_LOOKUP;
       *current_read_time=    mat_read_time;
       *current_record_count= prefix_rec_count;
-      pos->dups_producing_tables &=
-        ~new_join_tab->emb_sj_nest->sj_inner_tables;
+      pos->dups_producing_tables &= ~emb_sj_nest->sj_inner_tables;
     }
   }
   
@@ -13708,11 +13729,11 @@ void advance_sj_state(JOIN *join, table_
   {
     TABLE_LIST *mat_nest= 
       join->positions[pos->sjm_scan_last_inner].table->emb_sj_nest;
-    SJ_MATERIALIZATION_INFO *mat_info= mat_nest->sj_mat_info;
+    const uint table_count= my_count_bits(mat_nest->sj_inner_tables);
 
     double prefix_cost;
     double prefix_rec_count;
-    int first_tab= pos->sjm_scan_last_inner + 1 - mat_info->tables;
+    int first_tab= pos->sjm_scan_last_inner + 1 - table_count;
     /* Get the prefix cost */
     if (first_tab == (int)join->const_tables)
     {
@@ -13726,18 +13747,19 @@ void advance_sj_state(JOIN *join, table_
     }
 
     /* Add materialization cost */
-    prefix_cost += mat_info->materialization_cost.total_cost() +
-                   prefix_rec_count * mat_info->scan_cost.total_cost();
-    prefix_rec_count *= mat_info->rows;
+    prefix_cost+=
+      mat_nest->nested_join->sjm.materialization_cost.total_cost() +
+      prefix_rec_count * mat_nest->nested_join->sjm.scan_cost.total_cost();
+    prefix_rec_count*= mat_nest->nested_join->sjm.expected_rowcount;
     
     uint i;
     table_map rem_tables= remaining_tables;
-    for (i= idx; i != (first_tab + mat_info->tables - 1); i--)
+    for (i= idx; i != (first_tab + table_count - 1); i--)
       rem_tables |= join->positions[i].table->table->map;
 
     POSITION curpos, dummy;
     /* Need to re-run best-access-path as we prefix_rec_count has changed */
-    for (i= first_tab + mat_info->tables; i <= idx; i++)
+    for (i= first_tab + table_count; i <= idx; i++)
     {
       best_access_path(join, join->positions[i].table, rem_tables, i, FALSE,
                        prefix_rec_count, &curpos, &dummy);
@@ -13769,14 +13791,13 @@ void advance_sj_state(JOIN *join, table_
        Duplicate weedout can be applied after all ON-correlated and 
        correlated 
     */
-    TABLE_LIST *nest;
-    if ((nest= new_join_tab->emb_sj_nest))
+    if (emb_sj_nest)
     {
       if (!pos->dupsweedout_tables)
         pos->first_dupsweedout_table= idx;
 
-      pos->dupsweedout_tables |= nest->sj_inner_tables |
-                                 nest->nested_join->sj_depends_on;
+      pos->dupsweedout_tables|= emb_sj_nest->sj_inner_tables |
+                                emb_sj_nest->nested_join->sj_depends_on;
     }
 
     if (pos->dupsweedout_tables && 
@@ -16629,12 +16650,11 @@ sub_select_sjm(JOIN *join, JOIN_TAB *joi
     DBUG_RETURN(rc);
   }
 
-  SJ_MATERIALIZATION_INFO *sjm= join_tab->emb_sj_nest->sj_mat_info;
+  Semijoin_mat_exec *sjm= join_tab->emb_sj_nest->sj_mat_exec;
   if (end_of_records)
   {
-    rc= (*join_tab[sjm->tables - 1].next_select)(join,
-                                                 join_tab + sjm->tables,
-                                                 end_of_records);
+    rc= (*join_tab[sjm->table_count - 1].next_select)
+          (join, join_tab + sjm->table_count, end_of_records);
     DBUG_RETURN(rc);
   }
   if (!sjm->materialized)
@@ -16643,8 +16663,8 @@ sub_select_sjm(JOIN *join, JOIN_TAB *joi
       Do the materialization. First, put end_sj_materialize after the last
       inner table so we can catch record combinations of sj-inner tables.
     */
-    Next_select_func next_func= join_tab[sjm->tables - 1].next_select;
-    join_tab[sjm->tables - 1].next_select= end_sj_materialize;
+    Next_select_func next_func= join_tab[sjm->table_count - 1].next_select;
+    join_tab[sjm->table_count - 1].next_select= end_sj_materialize;
 
     /*
       Now run the join for the inner tables. The first call is to run the
@@ -16654,20 +16674,20 @@ sub_select_sjm(JOIN *join, JOIN_TAB *joi
     if ((rc= sub_select(join, join_tab, FALSE)) < 0 ||
         (rc= sub_select(join, join_tab, TRUE/*EOF*/)) < 0)
     {
-      join_tab[sjm->tables - 1].next_select= next_func;
+      join_tab[sjm->table_count - 1].next_select= next_func;
       DBUG_RETURN(rc); /* it's NESTED_LOOP_(ERROR|KILLED)*/
     }
-    join_tab[sjm->tables - 1].next_select= next_func;
+    join_tab[sjm->table_count - 1].next_select= next_func;
 
     /*
       Ok, materialization finished. Initialize the access to the temptable
     */
     sjm->materialized= TRUE;
     join_tab->read_record.read_record= join_no_more_records;
-    if (sjm->is_sj_scan)
+    if (sjm->is_scan)
     {
       /* Initialize full scan */
-      JOIN_TAB *last_tab= join_tab + (sjm->tables - 1);
+      JOIN_TAB *last_tab= join_tab + (sjm->table_count - 1);
       init_read_record(&last_tab->read_record, join->thd,
                        sjm->table, NULL, TRUE, TRUE, FALSE);
 
@@ -16675,15 +16695,15 @@ sub_select_sjm(JOIN *join, JOIN_TAB *joi
       last_tab->read_first_record= join_read_record_no_init;
       last_tab->read_record.copy_field= sjm->copy_field;
       last_tab->read_record.copy_field_end= sjm->copy_field +
-                                            sjm->sjm_table_cols.elements;
+                                            sjm->table_cols.elements;
       last_tab->read_record.read_record= rr_sequential_and_unpack;
     }
   }
 
-  if (sjm->is_sj_scan)
+  if (sjm->is_scan)
   {
     /* Do full scan of the materialized table */
-    JOIN_TAB *last_tab= join_tab + (sjm->tables - 1);
+    JOIN_TAB *last_tab= join_tab + (sjm->table_count - 1);
 
     Item *save_cond= last_tab->select_cond;
     last_tab->set_select_cond(sjm->join_cond, __LINE__);
@@ -16699,9 +16719,8 @@ sub_select_sjm(JOIN *join, JOIN_TAB *joi
     if (res || !sjm->in_equality->val_int())
       DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS);
   }
-  rc= (*join_tab[sjm->tables - 1].next_select)(join,
-                                               join_tab + sjm->tables,
-                                               end_of_records);
+  rc= (*join_tab[sjm->table_count - 1].next_select)
+        (join, join_tab + sjm->table_count, end_of_records);
   DBUG_RETURN(rc);
 }
 

=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h	2010-08-13 19:19:23 +0000
+++ b/sql/sql_select.h	2010-08-19 07:10:58 +0000
@@ -1775,7 +1775,7 @@ public:
 
   /* Temporary tables used to weed-out semi-join duplicates */
   List<TABLE> sj_tmp_tables;
-  List<SJ_MATERIALIZATION_INFO> sjm_info_list;
+  List<Semijoin_mat_exec> sjm_exec_list;
 
   /* 
     storage for caching buffers allocated during query execution. 

=== modified file 'sql/sql_test.cc'
--- a/sql/sql_test.cc	2010-07-13 17:29:44 +0000
+++ b/sql/sql_test.cc	2010-08-19 07:10:58 +0000
@@ -377,21 +377,23 @@ print_plan(JOIN* join, uint idx, double 
 }
 
 
-void print_sjm(SJ_MATERIALIZATION_INFO *sjm)
+void print_sjm(TABLE_LIST *emb_sj_nest)
 {
   DBUG_LOCK_FILE;
+  Semijoin_mat_exec *sjm= emb_sj_nest->sj_mat_exec;
   fprintf(DBUG_FILE, "\nsemi-join nest{\n");
   fprintf(DBUG_FILE, "  tables { \n");
-  for (uint i= 0;i < sjm->tables; i++)
+  for (uint i= 0;i < sjm->table_count; i++)
   {
     fprintf(DBUG_FILE, "    %s%s\n", 
-            sjm->positions[i].table->table->alias,
-            (i == sjm->tables -1)? "": ",");
+            emb_sj_nest->nested_join->sjm.positions[i].table->table->alias,
+            (i == sjm->table_count -1)? "": ",");
   }
   fprintf(DBUG_FILE, "  }\n");
   fprintf(DBUG_FILE, "  materialize_cost= %g\n",
-          sjm->materialization_cost.total_cost());
-  fprintf(DBUG_FILE, "  rows= %g\n", sjm->rows);
+          emb_sj_nest->nested_join->sjm.materialization_cost.total_cost());
+  fprintf(DBUG_FILE, "  rows= %g\n",
+          emb_sj_nest->nested_join->sjm.expected_rowcount);
   fprintf(DBUG_FILE, "}\n");
   DBUG_UNLOCK_FILE;
 }

=== modified file 'sql/sql_test.h'
--- a/sql/sql_test.h	2010-07-13 17:29:44 +0000
+++ b/sql/sql_test.h	2010-08-19 07:10:58 +0000
@@ -30,7 +30,7 @@ void TEST_join(JOIN *join);
 void print_plan(JOIN* join,uint idx, double record_count, double read_time,
                 double current_read_time, const char *info);
 void dump_TABLE_LIST_graph(SELECT_LEX *select_lex, TABLE_LIST* tl);
-void print_sjm(SJ_MATERIALIZATION_INFO *sjm);
+void print_sjm(TABLE_LIST *emb_sj_nest);
 void print_keyuse_array(DYNAMIC_ARRAY *keyuse_array);
 #endif
 void mysql_print_status();

=== modified file 'sql/table.h'
--- a/sql/table.h	2010-08-13 09:37:54 +0000
+++ b/sql/table.h	2010-08-19 07:10:58 +0000
@@ -1289,7 +1289,7 @@ enum enum_open_type
   OT_TEMPORARY_OR_BASE= 0, OT_TEMPORARY_ONLY, OT_BASE_ONLY
 };
 
-class SJ_MATERIALIZATION_INFO;
+class Semijoin_mat_exec;
 class Index_hint;
 class Item_exists_subselect;
 
@@ -1376,7 +1376,7 @@ struct TABLE_LIST
   */
   table_map     sj_inner_tables;
   Item_exists_subselect  *sj_subq_pred;
-  SJ_MATERIALIZATION_INFO *sj_mat_info;
+  Semijoin_mat_exec *sj_mat_exec;
 
   /*
     The structure of ON expression presented in the member above
@@ -1813,8 +1813,6 @@ private:
 };
 
 struct st_position;
-
-class SJ_MATERIALIZATION_INFO;
   
 class Item;
 
@@ -1938,6 +1936,27 @@ public:
   Natural_join_column *get_natural_column_ref();
 };
 
+/**
+  Semijoin_mat_optimize collects data used when calculating the cost of
+  executing a semijoin operation using a materialization strategy.
+  It is used during optimization phase only.
+*/
+
+struct Semijoin_mat_optimize
+{
+  /* Optimal join order calculated for inner tables of this semijoin op. */
+  struct st_position *positions;
+  /* True if data types allow the MaterializeScan semijoin strategy */
+  bool scan_allowed;
+  /* Expected #rows in the materialized table */
+  double expected_rowcount;
+  /* Materialization cost - execute sub-join and write rows to temp.table */
+  COST_VECT materialization_cost;
+  /* Cost to make one lookup in the temptable */
+  COST_VECT lookup_cost;
+  /* Cost of scanning the materialized table */
+  COST_VECT scan_cost;
+};
 
 typedef struct st_nested_join
 {
@@ -1970,6 +1989,7 @@ typedef struct st_nested_join
     of the semi-join, respectively.
   */
   List<Item>        sj_outer_exprs, sj_inner_exprs;
+  Semijoin_mat_optimize sjm;
   /**
      True if this join nest node is completely covered by the query execution
      plan. This means two things.


Attachment: [text/bzr-bundle] bzr/roy.lyseng@oracle.com-20100819071058-8rgwb329yoq2lqg3.bundle
Thread
bzr commit into mysql-next-mr-bugfixing branch (roy.lyseng:3227) Bug#50489Roy Lyseng19 Aug