Re-commit in git:

MDEV-406: ANALYZE $stmt
- Ported the old patch to new explain code
- New SQL syntax (ANALYZE $stmt)
- ANALYZE UPDATE/DELETE is now supported (because EXPLAIN UPDATE/DELETE is supported)
- Basic counters are calculated for basic kinds of queries
  (still need to see what happens with join buffer, ORDER BY...LIMIT queries, etc)
This commit is contained in:
Sergei Petrunia 2014-05-27 20:13:17 +04:00
parent 5a61516afd
commit eaba1ba4a5
13 changed files with 239 additions and 58 deletions

View File

@ -2282,6 +2282,9 @@ int THD::send_explain_fields(select_result *result)
/*
Populate the provided field_list with EXPLAIN output columns.
this->lex->describe has the EXPLAIN flags
The set/order of columns must be kept in sync with
Explain_query::print_explain and co.
*/
void THD::make_explain_field_list(List<Item> &field_list)
@ -2317,11 +2320,25 @@ void THD::make_explain_field_list(List<Item> &field_list)
item->maybe_null=1;
field_list.push_back(item= new Item_return_int("rows", 10,
MYSQL_TYPE_LONGLONG));
if (lex->describe & DESCRIBE_EXTENDED)
if (lex->analyze_stmt)
{
field_list.push_back(item= new Item_return_int("r_rows", 10,
MYSQL_TYPE_LONGLONG));
item->maybe_null=1;
}
if (lex->analyze_stmt || lex->describe & DESCRIBE_EXTENDED)
{
field_list.push_back(item= new Item_float("filtered", 0.1234, 2, 4));
item->maybe_null=1;
}
if (lex->analyze_stmt)
{
field_list.push_back(item= new Item_float("r_filtered", 0.1234, 2, 4));
item->maybe_null=1;
}
item->maybe_null= 1;
field_list.push_back(new Item_empty_string("Extra", 255, cs));
}

View File

@ -3959,6 +3959,18 @@ public:
virtual void cleanup();
};
class select_send_analyze : public select_send
{
bool discard_data;
bool send_result_set_metadata(List<Item> &list, uint flags) { return 0; }
/*
ANALYZE-todo: we should call val_int() (or val_str() or whatever) to
compute the columns. If we don't, it's not full execution.
*/
int send_data(List<Item> &items) { return 0; }
bool send_eof() { return 0; }
void abort_result_set() {}
};
class select_to_file :public select_result_interceptor {
protected:

View File

@ -223,6 +223,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
killed_state killed_status= NOT_KILLED;
THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE;
bool with_select= !select_lex->item_list.is_empty();
Explain_delete *explain;
Delete_plan query_plan(thd->mem_root);
query_plan.index= MAX_KEY;
query_plan.using_filesort= FALSE;
@ -538,9 +539,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
goto cleanup;
}
explain= (Explain_delete*)thd->lex->explain->get_upd_del_plan();
while (!(error=info.read_record(&info)) && !thd->killed &&
! thd->is_error())
{
explain->on_record_read();
if (table->vfield)
update_virtual_fields(thd, table,
table->triggers ? VCOL_UPDATE_ALL :
@ -549,6 +552,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
// thd->is_error() is tested to disallow delete row on error
if (!select || select->skip_record(thd) > 0)
{
explain->on_record_after_where();
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
TRG_ACTION_BEFORE, FALSE))
@ -666,6 +670,11 @@ cleanup:
}
DBUG_ASSERT(transactional_table || !deleted || thd->transaction.stmt.modified_non_trans_table);
free_underlaid_joins(thd, select_lex);
if (thd->lex->analyze_stmt)
{
error= thd->lex->explain->send_explain(thd);
}
else
if (error < 0 ||
(thd->lex->ignore && !thd->is_error() && !thd->is_fatal_error))
{

View File

@ -140,7 +140,7 @@ int Explain_query::send_explain(THD *thd)
return 1;
int res;
if ((res= print_explain(result, lex->describe)))
if ((res= print_explain(result, lex->describe, lex->analyze_stmt)))
result->abort_result_set();
else
result->send_eof();
@ -154,16 +154,16 @@ int Explain_query::send_explain(THD *thd)
*/
int Explain_query::print_explain(select_result_sink *output,
uint8 explain_flags)
uint8 explain_flags, bool is_analyze)
{
if (upd_del_plan)
{
upd_del_plan->print_explain(this, output, explain_flags);
upd_del_plan->print_explain(this, output, explain_flags, is_analyze);
return 0;
}
else if (insert_plan)
{
insert_plan->print_explain(this, output, explain_flags);
insert_plan->print_explain(this, output, explain_flags, is_analyze);
return 0;
}
else
@ -172,14 +172,14 @@ int Explain_query::print_explain(select_result_sink *output,
Explain_node *node= get_node(1);
if (!node)
return 1; /* No query plan */
return node->print_explain(this, output, explain_flags);
return node->print_explain(this, output, explain_flags, is_analyze);
}
}
bool print_explain_query(LEX *lex, THD *thd, String *str)
{
return lex->explain->print_explain_str(thd, str);
return lex->explain->print_explain_str(thd, str, false);
}
@ -187,14 +187,14 @@ bool print_explain_query(LEX *lex, THD *thd, String *str)
Return tabular EXPLAIN output as a text string
*/
bool Explain_query::print_explain_str(THD *thd, String *out_str)
bool Explain_query::print_explain_str(THD *thd, String *out_str, bool is_analyze)
{
List<Item> fields;
thd->make_explain_field_list(fields);
select_result_text_buffer output_buf(thd);
output_buf.send_result_set_metadata(fields, thd->lex->describe);
if (print_explain(&output_buf, thd->lex->describe))
if (print_explain(&output_buf, thd->lex->describe, is_analyze))
return true;
output_buf.save_to(out_str);
return false;
@ -217,7 +217,8 @@ static void push_string(List<Item> *item_list, String *str)
int Explain_union::print_explain(Explain_query *query,
select_result_sink *output,
uint8 explain_flags)
uint8 explain_flags,
bool is_analyze)
{
char table_name_buffer[SAFE_NAME_LEN];
@ -225,7 +226,7 @@ int Explain_union::print_explain(Explain_query *query,
for (int i= 0; i < (int) union_members.elements(); i++)
{
Explain_select *sel= query->get_select(union_members.at(i));
sel->print_explain(query, output, explain_flags);
sel->print_explain(query, output, explain_flags, is_analyze);
}
/* Print a line with "UNION RESULT" */
@ -287,9 +288,17 @@ int Explain_union::print_explain(Explain_query *query,
/* `rows` */
item_list.push_back(item_null);
/* `r_rows` */
if (is_analyze)
item_list.push_back(item_null);
/* `filtered` */
if (explain_flags & DESCRIBE_EXTENDED)
if (explain_flags & DESCRIBE_EXTENDED || is_analyze)
item_list.push_back(item_null);
/* `r_filtered` */
if (is_analyze)
item_list.push_back(item_null);
/* `Extra` */
@ -309,7 +318,7 @@ int Explain_union::print_explain(Explain_query *query,
Print all subquery children (UNION children have already been printed at
the start of this function)
*/
return print_explain_for_children(query, output, explain_flags);
return print_explain_for_children(query, output, explain_flags, is_analyze);
}
@ -319,12 +328,13 @@ int Explain_union::print_explain(Explain_query *query,
int Explain_node::print_explain_for_children(Explain_query *query,
select_result_sink *output,
uint8 explain_flags)
uint8 explain_flags,
bool is_analyze)
{
for (int i= 0; i < (int) children.elements(); i++)
{
Explain_node *node= query->get_node(children.at(i));
if (node->print_explain(query, output, explain_flags))
if (node->print_explain(query, output, explain_flags, is_analyze))
return 1;
}
return 0;
@ -344,7 +354,7 @@ Explain_select::~Explain_select()
int Explain_select::print_explain(Explain_query *query,
select_result_sink *output,
uint8 explain_flags)
uint8 explain_flags, bool is_analyze)
{
if (message)
{
@ -359,8 +369,17 @@ int Explain_select::print_explain(Explain_query *query,
item_list.push_back(item_null);
if (explain_flags & DESCRIBE_PARTITIONS)
item_list.push_back(item_null);
if (explain_flags & DESCRIBE_EXTENDED)
/* filtered */
if (is_analyze || explain_flags & DESCRIBE_EXTENDED)
item_list.push_back(item_null);
if (is_analyze)
{
/* r_rows, r_filtered */
item_list.push_back(item_null);
item_list.push_back(item_null);
}
item_list.push_back(new Item_string(message,strlen(message),cs));
@ -373,7 +392,7 @@ int Explain_select::print_explain(Explain_query *query,
bool using_fs= using_filesort;
for (uint i=0; i< n_join_tabs; i++)
{
join_tabs[i]->print_explain(output, explain_flags, select_id,
join_tabs[i]->print_explain(output, explain_flags, is_analyze, select_id,
select_type, using_tmp, using_fs);
if (i == 0)
{
@ -387,7 +406,7 @@ int Explain_select::print_explain(Explain_query *query,
}
}
return print_explain_for_children(query, output, explain_flags);
return print_explain_for_children(query, output, explain_flags, is_analyze);
}
@ -398,8 +417,9 @@ void Explain_table_access::push_extra(enum explain_extra_tag extra_tag)
int Explain_table_access::print_explain(select_result_sink *output, uint8 explain_flags,
uint select_id, const char *select_type,
bool using_temporary, bool using_filesort)
bool is_analyze,
uint select_id, const char *select_type,
bool using_temporary, bool using_filesort)
{
const CHARSET_INFO *cs= system_charset_info;
const char *hash_key_prefix= "#hash#";
@ -519,8 +539,16 @@ int Explain_table_access::print_explain(select_result_sink *output, uint8 explai
else
item_list.push_back(item_null);
/* `r_rows` */
if (is_analyze)
{
ha_rows avg_rows= r_scans ? round((double) r_rows / r_scans): 0;
item_list.push_back(new Item_int((longlong) (ulonglong) avg_rows,
MY_INT64_NUM_DECIMAL_DIGITS));
}
/* `filtered` */
if (explain_flags & DESCRIBE_EXTENDED)
if (explain_flags & DESCRIBE_EXTENDED || is_analyze)
{
if (filtered_set)
{
@ -530,6 +558,17 @@ int Explain_table_access::print_explain(select_result_sink *output, uint8 explai
item_list.push_back(item_null);
}
/* `r_filtered` */
if (is_analyze)
{
double r_filtered;
if (r_rows > 0)
r_filtered= 100.0 * (double)r_rows_after_table_cond / r_rows;
else
r_filtered= 100.0;
item_list.push_back(new Item_float(r_filtered, 2));
}
/* `Extra` */
StringBuffer<256> extra_buf;
bool first= true;
@ -802,12 +841,13 @@ void Explain_quick_select::print_key_len(String *str)
int Explain_delete::print_explain(Explain_query *query,
select_result_sink *output,
uint8 explain_flags)
uint8 explain_flags,
bool is_analyze)
{
if (deleting_all_rows)
{
const char *msg= "Deleting all rows";
int res= print_explain_message_line(output, explain_flags,
int res= print_explain_message_line(output, explain_flags, is_analyze,
1 /*select number*/,
select_type, &rows, msg);
return res;
@ -815,14 +855,16 @@ int Explain_delete::print_explain(Explain_query *query,
}
else
{
return Explain_update::print_explain(query, output, explain_flags);
return Explain_update::print_explain(query, output, explain_flags,
is_analyze);
}
}
int Explain_update::print_explain(Explain_query *query,
select_result_sink *output,
uint8 explain_flags)
uint8 explain_flags,
bool is_analyze)
{
StringBuffer<64> key_buf;
StringBuffer<64> key_len_buf;
@ -832,7 +874,7 @@ int Explain_update::print_explain(Explain_query *query,
const char *msg= impossible_where ?
"Impossible WHERE" :
"No matching rows after partition pruning";
int res= print_explain_message_line(output, explain_flags,
int res= print_explain_message_line(output, explain_flags, is_analyze,
1 /*select number*/,
select_type,
NULL, /* rows */
@ -892,8 +934,9 @@ int Explain_update::print_explain(Explain_query *query,
Single-table DELETE commands do not do "Using temporary".
"Using index condition" is also not possible (which is an unjustified limitation)
*/
double r_filtered= 100 * (r_rows?((double)r_rows_after_where/r_rows):1.0);
print_explain_row(output, explain_flags,
print_explain_row(output, explain_flags, is_analyze,
1, /* id */
select_type,
table_name.c_ptr(),
@ -904,18 +947,21 @@ int Explain_update::print_explain(Explain_query *query,
key_len_buf.length() ? key_len_buf.c_ptr() : NULL,
NULL, /* 'ref' is always NULL in single-table EXPLAIN DELETE */
&rows,
&r_rows,
r_filtered,
extra_str.c_ptr_safe());
return print_explain_for_children(query, output, explain_flags);
return print_explain_for_children(query, output, explain_flags, is_analyze);
}
int Explain_insert::print_explain(Explain_query *query,
select_result_sink *output,
uint8 explain_flags)
uint8 explain_flags,
bool is_analyze)
{
const char *select_type="INSERT";
print_explain_row(output, explain_flags,
print_explain_row(output, explain_flags, is_analyze,
1, /* id */
select_type,
table_name.c_ptr(),
@ -926,9 +972,11 @@ int Explain_insert::print_explain(Explain_query *query,
NULL, // key_len
NULL, // ref
NULL, // rows
NULL, // r_rows
100.0, // r_filtered
NULL);
return print_explain_for_children(query, output, explain_flags);
return print_explain_for_children(query, output, explain_flags, is_analyze);
}

View File

@ -60,10 +60,10 @@ public:
}
virtual int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags)=0;
uint8 explain_flags, bool is_analyze)=0;
int print_explain_for_children(Explain_query *query, select_result_sink *output,
uint8 explain_flags);
uint8 explain_flags, bool is_analyze);
virtual ~Explain_node(){}
};
@ -134,7 +134,7 @@ public:
bool using_filesort;
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags);
uint8 explain_flags, bool is_analyze);
};
@ -172,7 +172,7 @@ public:
union_members.append(select_no);
}
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags);
uint8 explain_flags, bool is_analyze);
const char *fake_select_type;
bool using_filesort;
@ -238,13 +238,14 @@ public:
Explain_union *get_union(uint select_id);
/* Produce a tabular EXPLAIN output */
int print_explain(select_result_sink *output, uint8 explain_flags);
int print_explain(select_result_sink *output, uint8 explain_flags,
bool is_analyze);
/* Send tabular EXPLAIN to the client */
int send_explain(THD *thd);
/* Return tabular EXPLAIN output as a text string */
bool print_explain_str(THD *thd, String *out_str);
bool print_explain_str(THD *thd, String *out_str, bool is_analyze);
/* If true, at least part of EXPLAIN can be printed */
bool have_query_plan() { return insert_plan || upd_del_plan|| get_node(1) != NULL; }
@ -252,6 +253,8 @@ public:
void query_plan_ready();
MEM_ROOT *mem_root;
Explain_update *get_upd_del_plan() { return upd_del_plan; }
private:
/* Explain_delete inherits from Explain_update */
Explain_update *upd_del_plan;
@ -459,8 +462,21 @@ public:
StringBuffer<32> firstmatch_table_name;
int print_explain(select_result_sink *output, uint8 explain_flags,
bool is_analyze,
uint select_id, const char *select_type,
bool using_temporary, bool using_filesort);
/* ANALYZE members*/
ha_rows r_scans; /* How many scans were ran on this join_tab */
ha_rows r_rows; /* How many rows we've got after that */
ha_rows r_rows_after_table_cond; /* Rows after applying the table condition */
ha_rows r_rows_after_where; /* Rows after applying attached part of WHERE */
Explain_table_access():
r_scans(0), r_rows(0), r_rows_after_table_cond(0),
r_rows_after_where(0)
{}
private:
void append_tag_name(String *str, enum explain_extra_tag tag);
};
@ -502,8 +518,17 @@ public:
bool using_filesort;
bool using_io_buffer;
/* ANALYZE members and methods */
ha_rows r_rows;
ha_rows r_rows_after_where;
inline void on_record_read() { r_rows++; }
inline void on_record_after_where() { r_rows_after_where++; }
Explain_update() :
r_rows(0), r_rows_after_where(0)
{}
virtual int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags);
uint8 explain_flags, bool is_analyze);
};
@ -523,7 +548,7 @@ public:
int get_select_id() { return 1; /* always root */ }
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags);
uint8 explain_flags, bool is_analyze);
};
@ -544,7 +569,7 @@ public:
virtual int get_select_id() { return 1; /* always root */ }
virtual int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags);
uint8 explain_flags, bool is_analyze);
};

View File

@ -483,6 +483,7 @@ void lex_start(THD *thd)
if (lex->select_lex.group_list_ptrs)
lex->select_lex.group_list_ptrs->clear();
lex->describe= 0;
lex->analyze_stmt= 0;
lex->subqueries= FALSE;
lex->context_analysis_only= 0;
lex->derived_tables= 0;
@ -4181,12 +4182,12 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor)
*/
int LEX::print_explain(select_result_sink *output, uint8 explain_flags,
bool *printed_anything)
bool is_analyze, bool *printed_anything)
{
int res;
if (explain && explain->have_query_plan())
{
res= explain->print_explain(output, explain_flags);
res= explain->print_explain(output, explain_flags, is_analyze);
*printed_anything= true;
}
else

View File

@ -2268,6 +2268,7 @@ public:
void save_explain_data(Explain_query *query);
void save_explain_data_intern(Explain_query *query, Explain_update *eu);
virtual ~Update_plan() {}
Update_plan(MEM_ROOT *mem_root_arg) :
@ -2459,6 +2460,7 @@ struct LEX: public Query_tables_list
*/
uint table_count;
uint8 describe;
bool analyze_stmt; /* TRUE<=> this is "ANALYZE $stmt" */
/*
A flag that indicates what kinds of derived tables are present in the
query (0 if no derived tables, otherwise a combination of flags
@ -2735,7 +2737,7 @@ struct LEX: public Query_tables_list
}
int print_explain(select_result_sink *output, uint8 explain_flags,
bool *printed_anything);
bool is_analyze, bool *printed_anything);
};

View File

@ -5233,7 +5233,8 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
top-level LIMIT
*/
result->reset_offset_limit();
thd->lex->explain->print_explain(result, thd->lex->describe);
thd->lex->explain->print_explain(result, thd->lex->describe,
thd->lex->analyze_stmt);
if (lex->describe & DESCRIBE_EXTENDED)
{
char buff[1024];
@ -5257,12 +5258,33 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
}
else
{
if (!result && !(result= new select_send()))
return 1; /* purecov: inspected */
//psergey-todo: ANALYZE should hook in here...
select_result *save_result;
if (lex->analyze_stmt)
{
save_result= result;
result= new select_send_analyze();
}
else
{
if (!result && !(result= new select_send()))
return 1; /* purecov: inspected */
}
query_cache_store_query(thd, all_tables);
res= handle_select(thd, lex, result, 0);
if (result != lex->result)
delete result;
if (lex->analyze_stmt)
{
result= save_result;
if (!result && !(result= new select_send()))
return 1;
thd->lex->explain->send_explain(thd);
if (result != lex->result)
delete result;
}
}
}
/* Count number of empty select queries */

View File

@ -17532,6 +17532,8 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
(*join_tab->next_select)(join,join_tab+1,end_of_records);
DBUG_RETURN(nls);
}
join_tab->explain->r_scans++;
int error;
enum_nested_loop_state rc= NESTED_LOOP_OK;
READ_RECORD *info= &join_tab->read_record;
@ -17667,6 +17669,8 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */
}
join_tab->explain->r_rows++;
if (join_tab->table->vfield)
update_virtual_fields(join->thd, join_tab->table);
@ -17685,6 +17689,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
There is no select condition or the attached pushed down
condition is true => a match is found.
*/
join_tab->explain->r_rows_after_table_cond++;
bool found= 1;
while (join_tab->first_unmatched && found)
{
@ -22908,10 +22913,11 @@ void JOIN::clear()
/*
Print an EXPLAIN line with all NULLs and given message in the 'Extra' column
TODO: is_analyze
*/
int print_explain_message_line(select_result_sink *result,
uint8 options,
uint8 options, bool is_analyze,
uint select_number,
const char *select_type,
ha_rows *rows,
@ -22944,8 +22950,16 @@ int print_explain_message_line(select_result_sink *result,
else
item_list.push_back(item_null);
/* `r_rows` */
if (is_analyze)
item_list.push_back(item_null);
/* `filtered` */
if (options & DESCRIBE_EXTENDED)
if (is_analyze || options & DESCRIBE_EXTENDED)
item_list.push_back(item_null);
/* `r_filtered` */
if (is_analyze)
item_list.push_back(item_null);
/* `Extra` */
@ -22996,7 +23010,7 @@ void make_possible_keys_line(TABLE *table, key_map possible_keys, String *line)
*/
int print_explain_row(select_result_sink *result,
uint8 options,
uint8 options, bool is_analyze,
uint select_number,
const char *select_type,
const char *table_name,
@ -23007,6 +23021,8 @@ int print_explain_row(select_result_sink *result,
const char *key_len,
const char *ref,
ha_rows *rows,
ha_rows *r_rows,
double r_filtered,
const char *extra)
{
const CHARSET_INFO *cs= system_charset_info;
@ -23058,12 +23074,20 @@ int print_explain_row(select_result_sink *result,
}
else
item_list.push_back(item_null);
/* 'r_rows' */
if (is_analyze)
item_list.push_back(item_null);
/* 'filtered' */
const double filtered=100.0;
if (options & DESCRIBE_EXTENDED)
if (options & DESCRIBE_EXTENDED || is_analyze)
item_list.push_back(new Item_float(filtered, 2));
/* 'r_filtered' */
if (is_analyze)
item_list.push_back(new Item_float(r_filtered, 2));
/* 'Extra' */
if (extra)
item_list.push_back(new Item_string(extra, strlen(extra), cs));
@ -23291,6 +23315,8 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
eta->key.set(thd->mem_root, NULL, (uint)-1);
eta->quick_info= NULL;
tab->explain= eta;
/* id */
if (tab->bush_root_tab)
eta->sjm_nest_select_id= select_id;

View File

@ -250,7 +250,8 @@ typedef struct st_join_table {
/* Special content for EXPLAIN 'Extra' column or NULL if none */
enum explain_extra_tag info;
Explain_table_access *explain;
/*
Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
column, or 0 if there is no info.
@ -1854,14 +1855,14 @@ void push_index_cond(JOIN_TAB *tab, uint keyno);
/* EXPLAIN-related utility functions */
int print_explain_message_line(select_result_sink *result,
uint8 options,
uint8 options, bool is_analyze,
uint select_number,
const char *select_type,
ha_rows *rows,
const char *message);
void explain_append_mrr_info(QUICK_RANGE_SELECT *quick, String *res);
int print_explain_row(select_result_sink *result,
uint8 options,
uint8 options, bool is_analyze,
uint select_number,
const char *select_type,
const char *table_name,
@ -1872,6 +1873,8 @@ int print_explain_row(select_result_sink *result,
const char *key_len,
const char *ref,
ha_rows *rows,
ha_rows *r_rows,
double r_filtered,
const char *extra);
void make_possible_keys_line(TABLE *table, key_map possible_keys, String *line);

View File

@ -2366,7 +2366,7 @@ void Show_explain_request::call_in_target_thread()
DBUG_ASSERT(current_thd == target_thd);
set_current_thd(request_thd);
if (target_thd->lex->print_explain(explain_buf, 0 /* explain flags*/,
&printed_anything))
false /*TODO: analyze? */, &printed_anything))
{
failed_to_produce= TRUE;
}

View File

@ -277,6 +277,7 @@ int mysql_update(THD *thd,
List<Item> all_fields;
killed_state killed_status= NOT_KILLED;
Update_plan query_plan(thd->mem_root);
Explain_update *explain;
query_plan.index= MAX_KEY;
query_plan.using_filesort= FALSE;
DBUG_ENTER("mysql_update");
@ -717,15 +718,16 @@ int mysql_update(THD *thd,
if (table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ)
table->prepare_for_position();
explain= thd->lex->explain->get_upd_del_plan();
/*
We can use compare_record() to optimize away updates if
the table handler is returning all columns OR if
if all updated columns are read
*/
can_compare_record= records_are_comparable(table);
while (!(error=info.read_record(&info)) && !thd->killed)
{
explain->on_record_read();
if (table->vfield)
update_virtual_fields(thd, table,
table->triggers ? VCOL_UPDATE_ALL :
@ -736,6 +738,7 @@ int mysql_update(THD *thd,
if (table->file->was_semi_consistent_read())
continue; /* repeat the read of the same row if it still exists */
explain->on_record_after_where();
store_record(table,record[1]);
if (fill_record_n_invoke_before_triggers(thd, table, fields, values, 0,
TRG_EVENT_UPDATE))
@ -993,7 +996,11 @@ int mysql_update(THD *thd,
id= thd->arg_of_last_insert_id_function ?
thd->first_successful_insert_id_in_prev_stmt : 0;
if (error < 0)
if (thd->lex->analyze_stmt)
{
error= thd->lex->explain->send_explain(thd);
}
else if (error < 0)
{
char buff[MYSQL_ERRMSG_SIZE];
my_snprintf(buff, sizeof(buff), ER(ER_UPDATE_INFO), (ulong) found,

View File

@ -982,7 +982,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
This makes the code grep-able, and helps maintenance.
*/
%token ABORT_SYM /* INTERNAL (used in lex) */
%token ACCESSIBLE_SYM
%token ACTION /* SQL-2003-N */
@ -1804,6 +1804,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <dyncol_def_list> dyncall_create_list
%type <NONE>
analyze_stmt_command
query verb_clause create change select do drop insert replace insert2
insert_values update delete truncate rename
show describe load alter optimize keycache preload flush
@ -1990,6 +1991,7 @@ verb_clause:
statement:
alter
| analyze
| analyze_stmt_command
| binlog_base64_event
| call
| change
@ -12765,6 +12767,13 @@ describe_command:
| DESCRIBE
;
analyze_stmt_command:
ANALYZE_SYM explainable_command
{
Lex->analyze_stmt= true;
}
;
opt_extended_describe:
/* empty */ {}
| EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; }