MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Sergey Petrunia Date:September 1 2008 11:09am
Subject:bzr push into mysql-6.0-opt branch (sergefp:2683 to 2684) WL#4520
View as plain text  
 2684 Sergey Petrunia	2008-09-01
      WL#4520 Make EXPLAIN show conditions involved in the query
      - Add EXPLAIN (CONDITIONS|CONDS) which prints conditions attached to various parts of the query plan
modified:
  sql/item.cc
  sql/item_cmpfunc.cc
  sql/item_cmpfunc.h
  sql/item_subselect.cc
  sql/lex.h
  sql/mysql_priv.h
  sql/sql_lex.h
  sql/sql_parse.cc
  sql/sql_select.cc
  sql/sql_select.h
  sql/sql_yacc.yy

 2683 Sergey Petrunia	2008-08-20 [merge]
      6.0 -> 6.0-opt merge
removed:
  mysql-test/suite/rpl/t/rpl_row_err_daisychain-master.opt
  mysql-test/suite/rpl/t/rpl_row_err_daisychain-slave.opt
  mysql-test/suite/rpl_ndb/t/rpl_truncate_7ndb_2-master.opt
modified:
  mysql-test/extra/binlog_tests/binlog_insert_delayed.test
  mysql-test/extra/rpl_tests/rpl_row_basic.test
  mysql-test/include/show_binlog_events.inc
  mysql-test/suite/binlog/r/binlog_killed_simulate.result
  mysql-test/suite/binlog/r/binlog_row_binlog.result
  mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result
  mysql-test/suite/binlog/r/binlog_statement_insert_delayed.result
  mysql-test/suite/binlog/r/binlog_stm_binlog.result
  mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result
  mysql-test/suite/rpl/r/rpl_loaddata_map.result
  mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result
  mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result
  mysql-test/suite/rpl/r/rpl_stm_log.result
  mysql-test/suite/rpl/r/rpl_variables.result
  mysql-test/suite/rpl/t/disabled.def
  mysql-test/suite/rpl/t/rpl_incident.test
  mysql-test/suite/rpl/t/rpl_loaddata_map.test
  mysql-test/suite/rpl/t/rpl_trunc_temp.test
  mysql-test/suite/rpl/t/rpl_variables.test
  mysql-test/suite/rpl_ndb/t/rpl_truncate_7ndb_2.test
  mysql-test/suite/rpl_ndb_big/r/rpl_row_basic_7ndb.result
  sql/sql_binlog.cc
  sql/sql_cursor.cc
  tests/mysql_client_test.c

=== modified file 'sql/item.cc'
--- a/sql/item.cc	2008-08-07 03:05:33 +0000
+++ b/sql/item.cc	2008-09-01 11:05:03 +0000
@@ -1931,7 +1931,10 @@ void Item_ident::print(String *str, enum
     append_identifier(thd, str, nm, (uint) strlen(nm));
     return;
   }
-  if (db_name && db_name[0] && !alias_name_used)
+
+  if (db_name && db_name[0] && !alias_name_used &&
+      !((query_type == QT_SICCINT) && !my_strcasecmp(system_charset_info,
+                                                     db_name, thd->db)))
   {
     if (!(cached_table && cached_table->belong_to_view &&
           cached_table->belong_to_view->compact_view_format))

=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc	2008-07-31 11:37:07 +0000
+++ b/sql/item_cmpfunc.cc	2008-09-01 11:05:03 +0000
@@ -5407,3 +5407,34 @@ void Item_equal::print(String *str, enum
   str->append(')');
 }
 
+void Item_func_trig_cond::print(String *str, enum_query_type query_type)
+{
+  if (query_type == QT_SICCINT && trig_tab)
+  {
+    /*
+      We need to print this:
+
+        IF(have_match(t1..tN), cond)
+      
+      where t1..tN are the inner tables. t1 is stored in this->trig_tab.
+    */
+
+    //trig_tab is the first inner tab. Find that is the first-inner. proceed from trig_tab until
+    //the table has the same emb-oj-nest (print first and last, or one if
+    //they are equal)
+
+    str->append("IF(have_match(");
+    str->append(trig_tab->table->alias);
+    if (trig_tab->last_inner != trig_tab)
+    {
+      str->append("..");
+      str->append(trig_tab->last_inner->table->alias);
+    }
+    str->append(", ");
+    args[0]->print(str, query_type);
+    str->append(')');
+  }
+  else
+    Item_bool_func::print(str, query_type);
+}
+

=== modified file 'sql/item_cmpfunc.h'
--- a/sql/item_cmpfunc.h	2008-03-05 10:32:49 +0000
+++ b/sql/item_cmpfunc.h	2008-09-01 11:05:03 +0000
@@ -378,7 +378,7 @@ public:
 };
 
 class Item_maxmin_subselect;
-
+struct st_join_table;
 /*
   trigcond<param>(arg) ::= param? arg : TRUE
 
@@ -412,7 +412,16 @@ class Item_func_trig_cond: public Item_b
 {
   bool *trig_var;
 public:
-  Item_func_trig_cond(Item *a, bool *f) : Item_bool_func(a) { trig_var= f; }
+  Item_func_trig_cond(Item *a, bool *f, struct st_join_table *tab) : 
+    Item_bool_func(a), trig_var(f), trig_tab(tab), is_on_expr(FALSE)
+  {}
+  Item_func_trig_cond(Item *a, bool *f, bool is_on_expr_arg) : 
+    Item_bool_func(a), trig_var(f), trig_tab(NULL),
+    is_on_expr(is_on_expr_arg)
+  {}
+  Item_func_trig_cond(Item *a, bool *f) : 
+    Item_bool_func(a), trig_var(f), trig_tab(NULL), is_on_expr(FALSE)
+  {}
   longlong val_int() { return *trig_var ? args[0]->val_int() : 1; }
   enum Functype functype() const { return TRIG_COND_FUNC; };
   const char *func_name() const { return "trigcond"; };
@@ -420,8 +429,17 @@ public:
   bool *get_trig_var() { return trig_var; }
   /* The following is needed for ICP: */
   table_map used_tables() const { return args[0]->used_tables(); }
+  void print(String *str, enum_query_type query_type);
+
+  /* The following is for EXPLAIN CONDS. */
+  /* != NULL means this is an outer-join-triggered WHERE clause */
+  struct st_join_table *trig_tab;
+  bool is_on_expr;
+  bool is_outer_join_on_expr() { return is_on_expr; }
+  bool is_outer_join_where_cond() { return test(trig_tab); }
 };
 
+
 class Item_func_not_all :public Item_func_not
 {
   /* allow to check presence of values in max/min optimization */

=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc	2008-07-24 10:00:56 +0000
+++ b/sql/item_subselect.cc	2008-09-01 11:05:03 +0000
@@ -2777,13 +2777,29 @@ table_map subselect_union_engine::upper_
 void subselect_single_select_engine::print(String *str,
                                            enum_query_type query_type)
 {
-  select_lex->print(thd, str, query_type);
+  if (query_type == QT_SICCINT)
+  {
+    char buf[32]; // enough for uint
+    my_snprintf(buf, sizeof(buf), "%u", select_lex->select_number);
+    str->append(STRING_WITH_LEN("select #"));
+    str->append(buf, strlen(buf));
+  }
+  else
+    select_lex->print(thd, str, query_type);
 }
 
 
 void subselect_union_engine::print(String *str, enum_query_type query_type)
 {
-  unit->print(str, query_type);
+  if (query_type == QT_SICCINT)
+  {
+    char union_name[NAME_LEN];
+    uint len= create_union_table_name(unit, union_name);
+    str->append(STRING_WITH_LEN("select #"));
+    str->append(union_name, len);
+  }
+  else
+    unit->print(str, query_type);
 }
 
 

=== modified file 'sql/lex.h'
--- a/sql/lex.h	2008-07-09 07:12:43 +0000
+++ b/sql/lex.h	2008-09-01 11:05:03 +0000
@@ -123,6 +123,8 @@ static SYMBOL symbols[] = {
   { "COMPRESSION_ALGORITHM", SYM(COMPRESSION_ALGORITHM_SYM)},
   { "CONCURRENT",	SYM(CONCURRENT)},
   { "CONDITION",        SYM(CONDITION_SYM)},
+  { "CONDS",            SYM(CONDS_SYM)},
+  { "CONDITIONS",       SYM(CONDITIONS_SYM)},
   { "CONNECTION",       SYM(CONNECTION_SYM)},
   { "CONSISTENT",	SYM(CONSISTENT_SYM)},
   { "CONSTRAINT",	SYM(CONSTRAINT)},

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2008-08-16 15:22:47 +0000
+++ b/sql/mysql_priv.h	2008-09-01 11:05:03 +0000
@@ -65,7 +65,8 @@ class Parser_state;
 enum enum_query_type
 {
   QT_ORDINARY,
-  QT_IS
+  QT_IS,
+  QT_SICCINT
 };
 
 /* TODO convert all these three maps to Bitmap classes */

=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h	2008-08-18 18:12:46 +0000
+++ b/sql/sql_lex.h	2008-09-01 11:05:03 +0000
@@ -139,6 +139,7 @@ enum enum_sql_command {
   additional "partitions" column even if partitioning is not compiled in.
 */
 #define DESCRIBE_PARTITIONS	4
+#define DESCRIBE_CONDS	        8
 
 #ifdef MYSQL_SERVER
 
@@ -1510,6 +1511,26 @@ public:
   CHARSET_INFO *m_underscore_cs;
 };
 
+/*
+  EXPLAIN CONDS output line.
+*/
+class Explain_conds_line : public Sql_alloc
+{
+public:
+  int id;
+  /*
+    Table name, as shown by EXPLAIN. we can't just use a pointer because
+    names like <derived%x> are generated on the fly.
+  */
+  String table_name;
+
+  /* Condition types. There's a fixed list of those so far */
+  const char *cond_type;
+  
+  /* The condition */
+  String cond;
+};
+
 
 /* The state of the lex parsing. This is saved in the THD struct */
 
@@ -1537,6 +1558,7 @@ typedef struct st_lex : public Query_tab
   LEX_USER *grant_user;
   XID *xid;
   THD *thd;
+  List<Explain_conds_line> *explain_conds_list;
 
   /* maintain a list of used plugins for this LEX */
   DYNAMIC_ARRAY plugins;

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2008-08-08 13:34:35 +0000
+++ b/sql/sql_parse.cc	2008-09-01 11:05:03 +0000
@@ -4823,6 +4823,8 @@ error:
   goto finish;
 }
 
+void
+net_send_eof(THD *thd, uint server_status, uint total_warn_count);
 
 static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
 {
@@ -4837,10 +4839,19 @@ static bool execute_sqlcom_select(THD *t
         new Item_int((ulonglong) thd->variables.select_limit);
   }
   thd->thd_marker.emb_on_expr_nest= NULL;
+
+
   if (!(res= open_and_lock_tables(thd, all_tables)))
   {
     if (lex->describe)
     {
+      thd->lex->explain_conds_list= NULL;
+      if (lex->describe & DESCRIBE_CONDS &&
+          thd->client_capabilities & CLIENT_MULTI_RESULTS)
+      {
+        thd->server_status |= SERVER_MORE_RESULTS_EXISTS;
+        thd->lex->explain_conds_list= new List<Explain_conds_line>;
+      }
       /*
         We always use select_send for EXPLAIN, even if it's an EXPLAIN
         for SELECT ... INTO OUTFILE: a user application should be able
@@ -4865,6 +4876,71 @@ static bool execute_sqlcom_select(THD *t
         result->abort();
       else
         result->send_eof();
+
+      if (lex->describe & DESCRIBE_CONDS)
+      {
+        if (thd->client_capabilities & CLIENT_MULTI_RESULTS)
+        {
+          net_send_eof(thd,
+                       thd->main_da.server_status(),
+                       thd->main_da.total_warn_count());
+          thd->main_da.reset_diagnostics_area();
+          {
+            List<Item> field_list;
+            Item *item;
+            CHARSET_INFO *cs= system_charset_info;
+            field_list.push_back(new Item_return_int("id",3, MYSQL_TYPE_LONGLONG));
+            field_list.push_back(item= new Item_empty_string("table", NAME_CHAR_LEN, cs));
+            field_list.push_back(item= new Item_empty_string("cond_type", NAME_CHAR_LEN, cs));
+            field_list.push_back(item= new Item_empty_string("cond", NAME_CHAR_LEN, cs));
+            result->send_fields(field_list,
+                                Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
+          }
+          // Now, send some garbage to see if it works.
+          res= 0;
+          List_iterator<Explain_conds_line> it(*thd->lex->explain_conds_list);
+          Explain_conds_line *line;
+          CHARSET_INFO *cs= system_charset_info;
+          while ((line = it++))
+          {
+            List<Item> item_list;
+            item_list.push_back(new Item_int(line->id));
+            if (line->table_name.length())
+              item_list.push_back(new Item_string(line->table_name.ptr(),
+                                                  line->table_name.length(), cs));
+            else
+              item_list.push_back(new Item_null());
+
+            item_list.push_back(new Item_string(line->cond_type, 
+                                                strlen(line->cond_type), cs));
+            item_list.push_back(new Item_string(line->cond.ptr(), 
+                                                line->cond.length(), cs));
+            if (result->send_data(item_list))
+            {
+              //join->error= 1;
+              res= 1;
+            }
+          }
+          if (res)
+            result->abort();
+          else
+            result->send_eof();
+
+          net_send_eof(thd,
+                       thd->main_da.server_status(),
+                       thd->main_da.total_warn_count());
+          thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
+          thd->main_da.reset_diagnostics_area();
+          thd->main_da.set_ok_status(thd, 0, 0, NULL);
+          delete thd->lex->explain_conds_list;
+        }
+        else
+        {
+          DBUG_ASSERT(0);
+          //psergey-todo: produce a warning that EXPLAIN CONDS won't work
+          //because we can't emit the second recordset.
+        }
+        }
       delete result;
     }
     else

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2008-08-16 15:22:47 +0000
+++ b/sql/sql_select.cc	2008-09-01 11:05:03 +0000
@@ -7449,7 +7449,7 @@ add_found_match_trig_cond(JOIN_TAB *tab,
   if (tab == root_tab)
     return cond;
   if ((tmp= add_found_match_trig_cond(tab->first_upper, cond, root_tab)))
-    tmp= new Item_func_trig_cond(tmp, &tab->found);
+    tmp= new Item_func_trig_cond(tmp, &tab->found, tab);
   if (tmp)
   {
     tmp->quick_fix_field();
@@ -7597,7 +7597,7 @@ make_join_select(JOIN *join,SQL_SELECT *
                                            (  table_map) 0, 0);
             if (!tmp)
               continue;
-            tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl);
+            tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl, TRUE);
             if (!tmp)
               DBUG_RETURN(1);
             tmp->quick_fix_field();
@@ -7872,7 +7872,7 @@ make_join_select(JOIN *join,SQL_SELECT *
                                          (table_map) 0, 0);
           if (!tmp)
             continue;
-          tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl);
+          tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl, TRUE);
           if (!tmp)
             DBUG_RETURN(1);
           tmp->quick_fix_field();
@@ -7920,7 +7920,8 @@ make_join_select(JOIN *join,SQL_SELECT *
             DBUG_PRINT("info", ("Item_func_trig_cond"));
             tmp_cond= new Item_func_trig_cond(tmp_cond,
                                               &first_inner_tab->
-                                              not_null_compl);
+                                              not_null_compl,
+                                              TRUE);
             DBUG_PRINT("info", ("Item_func_trig_cond %p",
                                 tmp_cond));
             if (tmp_cond)
@@ -18828,6 +18829,179 @@ void JOIN::clear()
   }
 }
 
+
+static
+void add_explain_cond(JOIN *join, const char *table_name, uint table_name_len,
+                      const char *cond_type, const Item *cond)
+{
+  Explain_conds_line *line= new Explain_conds_line;
+  THD *thd= join->thd;
+
+  line->id= join->select_lex->select_number;
+  if (table_name)
+    line->table_name.copy(table_name, table_name_len, system_charset_info);
+  line->cond_type=cond_type;
+  /* Turn off excessive qouting and print */
+  ulonglong save_opts= thd->options;
+  thd->options &= ~OPTION_QUOTE_SHOW_CREATE;
+  ((Item*)cond)->print(&line->cond, QT_SICCINT);
+  thd->options= save_opts;
+  thd->lex->explain_conds_list->push_back(line);
+}
+
+
+/*
+  Print out all triggered conditions attached to this table.
+
+  1. Start walking.
+  *  if it is a trigger cond and not on-expr
+      - print its children.
+  *  if it is a trigger cond ...
+  This is achieved by:
+  
+    - let Item_func_trig_cond doesn't print itself if it's a QT_SICCINT 
+      printout and it is a where-expr trigger.
+    - 
+*/
+
+#if 0
+void add_triggered_conds(JOIN *join, JOIN_TAB *prev, JOIN_TAB *tab, 
+                         const char *table_name, uint table_name_len)
+{
+  Item *item= tab->select_cond;
+  if ((item->type() == Item::COND_ITEM) &&
+      ((Item_cond*)item)->functype() == Item_func::COND_AND_FUNC)
+  {
+    List_iterator_fast<Item> li(*((Item_cond*) item)->argument_list());
+    Item *child;
+    while ((child= li++))
+    {
+      if ((child->type() == Item::FUNC_ITEM &&
+          (Item_func*)child)->functype() == Item_func::TRIG_COND_FUNC)
+      {
+        if (((Item_func_trig_cond*)child)->trig_tab != NULL)
+          ; // Descend into child
+        else
+        {
+          //this is a ON-expr
+        }
+      }
+      else
+      {
+        //print it out as-is.
+        add_explain_cond(join, table_name, table_name_len,
+                               const char *cond_type, child);
+      }
+    }
+  }
+}
+#endif
+
+static void 
+print_outer_join_conds_inner(JOIN *join, const char *tbl_name, 
+                             uint tbl_name_len, Item *item,
+                             const char *cond_type)
+{
+  Item *print_cond= item;
+  const char *print_type= cond_type;
+  String print_type_str;
+
+  if (item->type() == Item::FUNC_ITEM &&
+      ((Item_func*)item)->functype() == Item_func::TRIG_COND_FUNC)
+  {
+    Item_func_trig_cond *trigcond= (Item_func_trig_cond*)item;
+    if (trigcond->is_outer_join_on_expr())
+    {
+      print_cond= trigcond->arguments()[0];
+      print_type= "left join on";
+    }
+    else if (trigcond->is_outer_join_where_cond())
+    {
+      //print_cond= trigcond->arguments()[0];
+      print_type= "left join where";
+      /*
+      Have trig_tab. that is the first-inner. proceed from trig_tab until
+      the table has the same emb-oj-nest (print first and last, or one if
+      they are equal)
+      print_type_str.append(STRING_WITH_LEN("where("));
+      print_type_str.append(tbl_name, tbl_name_len);
+      print_type_str.append(")");
+      print_type= print_type_str.c_ptr_safe();
+      */
+    }
+  }
+  add_explain_cond(join, tbl_name, tbl_name_len, print_type, print_cond);
+}
+
+
+static 
+void print_outer_join_conds(JOIN *join, const char *tbl_name, 
+                            uint tbl_name_len, Item *item,
+                            const char *cond_type)
+{
+  if ((item->type() == Item::COND_ITEM) &&
+      ((Item_cond*)item)->functype() == Item_func::COND_AND_FUNC)
+  {
+    List_iterator_fast<Item> li(*((Item_cond*) item)->argument_list());
+    Item *child;
+    /* Do the two loops: first print ON expressions */
+    while ((child= li++))
+    {
+      if (child->type() == Item::FUNC_ITEM &&
+          ((Item_func*)child)->functype() == Item_func::TRIG_COND_FUNC &&
+          ((Item_func_trig_cond*)child)->is_outer_join_on_expr())
+      {
+        print_outer_join_conds_inner(join, tbl_name, tbl_name_len, child,
+                                     cond_type);
+      }
+    }
+
+    /* then print everything else */
+    li.rewind();
+    while ((child= li++))
+    {
+      if (!(child->type() == Item::FUNC_ITEM &&
+            ((Item_func*)child)->functype() == Item_func::TRIG_COND_FUNC &&
+            ((Item_func_trig_cond*)child)->is_outer_join_on_expr()))
+      {
+        print_outer_join_conds_inner(join, tbl_name, tbl_name_len, child,
+                                     cond_type);
+      }
+    }
+  }
+  else
+    print_outer_join_conds_inner(join, tbl_name, tbl_name_len, item,
+                                 cond_type);
+}
+
+
+/* Utility function for EXPLAIN handling */
+
+uint create_union_table_name(SELECT_LEX_UNIT *unit, char *table_name_buffer)
+{
+  SELECT_LEX *sl= unit->first_select();
+  uint len= 6, lastop= 0;
+  memcpy(table_name_buffer, STRING_WITH_LEN("<union"));
+  for (; sl && len + lastop + 5 < NAME_LEN; sl= sl->next_select())
+  {
+    len+= lastop;
+    lastop= my_snprintf(table_name_buffer + len, NAME_LEN - len,
+                        "%u,", sl->select_number);
+  }
+  if (sl || len + lastop >= NAME_LEN)
+  {
+    memcpy(table_name_buffer + len, STRING_WITH_LEN("...>") + 1);
+    len+= 4;
+  }
+  else
+  {
+    len+= lastop;
+    table_name_buffer[len - 1]= '>';  // change ',' to '>'
+  }
+  return len;
+}
+
+
 /**
   EXPLAIN handling.
 
@@ -18892,25 +19066,7 @@ void select_describe(JOIN *join, bool ne
 					cs));
     /* table */
     {
-      SELECT_LEX *sl= join->unit->first_select();
-      uint len= 6, lastop= 0;
-      memcpy(table_name_buffer, STRING_WITH_LEN("<union"));
-      for (; sl && len + lastop + 5 < NAME_LEN; sl= sl->next_select())
-      {
-        len+= lastop;
-        lastop= my_snprintf(table_name_buffer + len, NAME_LEN - len,
-                            "%u,", sl->select_number);
-      }
-      if (sl || len + lastop >= NAME_LEN)
-      {
-        memcpy(table_name_buffer + len, STRING_WITH_LEN("...>") + 1);
-        len+= 4;
-      }
-      else
-      {
-        len+= lastop;
-        table_name_buffer[len - 1]= '>';  // change ',' to '>'
-      }
+      uint len= create_union_table_name(join->unit, table_name_buffer);
       item_list.push_back(new Item_string(table_name_buffer, len, cs));
     }
     /* partitions */
@@ -18963,6 +19119,9 @@ void select_describe(JOIN *join, bool ne
       tmp1.length(0);
       tmp2.length(0);
       tmp3.length(0);
+      const char *table_name;
+      uint table_name_len;
+      uint keyno= MAX_KEY;
 
       quick_type= -1;
       item_list.empty();
@@ -18986,19 +19145,20 @@ void select_describe(JOIN *join, bool ne
       /* table */
       if (table->derived_select_number)
       {
-	/* Derived table name generation */
-	int len= my_snprintf(table_name_buffer, sizeof(table_name_buffer)-1,
-			     "<derived%u>",
-			     table->derived_select_number);
-	item_list.push_back(new Item_string(table_name_buffer, len, cs));
+        /* Derived table name generation */
+        table_name= table_name_buffer;
+        table_name_len= my_snprintf(table_name_buffer, 
+                                    sizeof(table_name_buffer)-1,
+                                    "<derived%u>",
+                                    table->derived_select_number);
       }
       else
       {
-        TABLE_LIST *real_table= table->pos_in_table_list; 
-	item_list.push_back(new Item_string(real_table->alias,
-					    strlen(real_table->alias),
-					    cs));
+        table_name= table->pos_in_table_list->alias;
+        table_name_len= strlen(table_name);
       }
+      item_list.push_back(new Item_string(table_name, table_name_len, cs));
+
       /* "partitions" column */
       if (join->thd->lex->describe & DESCRIBE_PARTITIONS)
       {
@@ -19167,6 +19327,7 @@ void select_describe(JOIN *join, bool ne
           extra.append(STRING_WITH_LEN("; Using index"));
         if (tab->packed_info & TAB_INFO_USING_WHERE)
           extra.append(STRING_WITH_LEN("; Using where"));
+        //psergey-conds: todo: ^ print this cond out ^.
         if (tab->packed_info & TAB_INFO_FULL_SCAN_ON_NULL)
           extra.append(STRING_WITH_LEN("; Full scan on NULL key"));
         /* Skip initial "; "*/
@@ -19181,7 +19342,6 @@ void select_describe(JOIN *join, bool ne
       }
       else
       {
-        uint keyno= MAX_KEY;
         if (tab->ref.key_parts)
           keyno= tab->ref.key;
         else if (tab->select && tab->select->quick)
@@ -19217,11 +19377,14 @@ void select_describe(JOIN *join, bool ne
             {
               extra.append(STRING_WITH_LEN("; Using where with pushed "
                                            "condition"));
+              /*
+              Don't print pushed condition here
               if (thd->lex->describe & DESCRIBE_EXTENDED)
               {
                 extra.append(STRING_WITH_LEN(": "));
                 ((COND *)pushed_cond)->print(&extra, QT_ORDINARY);
               }
+              */
             }
             else
               extra.append(STRING_WITH_LEN("; Using where"));
@@ -19324,12 +19487,70 @@ void select_describe(JOIN *join, bool ne
         }
         item_list.push_back(new Item_string(str, len, cs));
       }
+      
+      /*
+        EXPLAIN CONDITIONS handling: per-table part
+      */
+      if (join->thd->lex->explain_conds_list)
+      {
+        /* Pushed index condition */
+        if (keyno != MAX_KEY && keyno == table->file->pushed_idx_cond_keyno &&
+            table->file->pushed_idx_cond)
+        {
+          add_explain_cond(join, table_name, table_name_len,
+                           "pushed_idx_cond", table->file->pushed_idx_cond);
+        }
+
+        /* Pushed table condition */
+        const Item *pushed_cond= tab->table->file->pushed_cond;
+        if (thd->variables.engine_condition_pushdown && pushed_cond)
+        {
+          add_explain_cond(join, table_name, table_name_len, "pushed_cond", 
+                           pushed_cond);
+        }
+
+        /* The WHERE */
+        if (tab->select_cond)
+        {
+          //psergey-conds: separate ON/WHERE.
+          if (table->map & join->outer_join) //within an outer join
+          {
+            /*
+            JOIN_TAB *prev;
+            for (prev= tab->first_inner; prev != tab+1; prev++)
+            {
+              / * Collect/print WHERE * /
+              //:add_triggered_conds(join, prev, tab, table_name, table_name_len);
+            }*/
+            print_outer_join_conds(join, table_name, table_name_len, 
+                                   tab->select_cond, "impossible");
+          }
+          else
+          {
+            add_explain_cond(join, table_name, table_name_len, "where", 
+                             tab->select_cond);
+          }
+         }
+        /* Join buffering part of the WHERE */
+        if (i > 0 && tab[-1].next_select == sub_select_cache &&
+          tab->cache.select)
+        {
+          add_explain_cond(join, table_name, table_name_len, "join_buf", 
+                           tab->cache.select->cond);
+        }
+      }
+      
       // For next iteration
       used_tables|=table->map;
       if (result->send_data(item_list))
 	join->error= 1;
     }
   }
+  
+  /* EXPLAIN CONDITIONS handling: per-join part: print  HAVING */
+  if (join->thd->lex->explain_conds_list && join->having)
+    add_explain_cond(join, NULL, 0, "having", join->having);
+
   for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit();
        unit;
        unit= unit->next_unit())

=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h	2008-08-16 15:22:47 +0000
+++ b/sql/sql_select.h	2008-09-01 11:05:03 +0000
@@ -893,3 +893,7 @@ int report_error(TABLE *table, int error
 int safe_index_read(JOIN_TAB *tab);
 COND *remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value);
 int test_if_item_cache_changed(List<Cached_item> &list);
+
+/* EXPLAIN helper funcs */
+uint create_union_table_name(SELECT_LEX_UNIT *unit, char *table_name_buffer);
+

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2008-08-20 10:34:46 +0000
+++ b/sql/sql_yacc.yy	2008-09-01 11:05:03 +0000
@@ -689,6 +689,8 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  COMPRESSION_ALGORITHM_SYM
 %token  CONCURRENT
 %token  CONDITION_SYM                 /* SQL-2003-N */
+%token  CONDS_SYM
+%token  CONDITIONS_SYM
 %token  CONNECTION_SYM
 %token  CONSISTENT_SYM
 %token  CONSTRAINT                    /* SQL-2003-R */
@@ -10624,6 +10626,8 @@ opt_extended_describe:
           /* empty */ {}
         | EXTENDED_SYM   { Lex->describe|= DESCRIBE_EXTENDED; }
         | PARTITIONS_SYM { Lex->describe|= DESCRIBE_PARTITIONS; }
+        | CONDS_SYM       { Lex->describe|= DESCRIBE_CONDS; }
+        | CONDITIONS_SYM { Lex->describe|= DESCRIBE_CONDS; }
         ;
 
 opt_describe_column:
@@ -11784,6 +11788,8 @@ keyword_sp:
         | COMPRESSION_SYM          {}
         | COMPRESSION_ALGORITHM_SYM{}
         | CONCURRENT               {}
+        | CONDS_SYM                {}
+        | CONDITIONS_SYM           {}
         | CONNECTION_SYM           {}
         | CONSISTENT_SYM           {}
         | CONTEXT_SYM              {}

Thread
bzr push into mysql-6.0-opt branch (sergefp:2683 to 2684) WL#4520Sergey Petrunia1 Sep