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#4520 | Sergey Petrunia | 1 Sep |