summaryrefslogtreecommitdiff
path: root/sql/sql_select.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r--sql/sql_select.cc195
1 files changed, 131 insertions, 64 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 223e5c44fcf..0ed351b720c 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2010 Oracle and/or its affiliates.
- 2009-2011 Monty Program Ab
+/* Copyright (c) 2000, 2012 Oracle and/or its affiliates.
+ Copyright (c) 2009, 2012, Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -271,6 +271,8 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field,
bool *inherited_fl);
JOIN_TAB *first_depth_first_tab(JOIN* join);
JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab);
+JOIN_TAB *first_breadth_first_tab(JOIN *join);
+JOIN_TAB *next_breadth_first_tab(JOIN *join, JOIN_TAB *tab);
/**
This handles SELECT with and without UNION.
@@ -987,7 +989,10 @@ JOIN::optimize()
}
eval_select_list_used_tables();
-
+
+ if (optimize_constant_subqueries())
+ DBUG_RETURN(1);
+
table_count= select_lex->leaf_tables.elements;
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
@@ -1274,6 +1279,12 @@ JOIN::optimize()
{
conds= substitute_for_best_equal_field(NO_PARTICULAR_TAB, conds,
cond_equal, map2table);
+ if (thd->is_error())
+ {
+ error= 1;
+ DBUG_PRINT("error",("Error from substitute_for_best_equal"));
+ DBUG_RETURN(1);
+ }
conds->update_used_tables();
DBUG_EXECUTE("where",
print_where(conds,
@@ -1294,6 +1305,12 @@ JOIN::optimize()
*tab->on_expr_ref,
tab->cond_equal,
map2table);
+ if (thd->is_error())
+ {
+ error= 1;
+ DBUG_PRINT("error",("Error from substitute_for_best_equal"));
+ DBUG_RETURN(1);
+ }
(*tab->on_expr_ref)->update_used_tables();
}
}
@@ -6615,6 +6632,32 @@ void JOIN::get_prefix_cost_and_fanout(uint n_tables,
/**
+ Estimate the number of rows that query execution will read.
+
+ @todo This is a very pessimistic upper bound. Use join selectivity
+ when available to produce a more realistic number.
+*/
+
+double JOIN::get_examined_rows()
+{
+ ha_rows examined_rows;
+ double prev_fanout= 1;
+ JOIN_TAB *tab= first_breadth_first_tab(this);
+ JOIN_TAB *prev_tab= tab;
+
+ examined_rows= tab->get_examined_rows();
+
+ while ((tab= next_breadth_first_tab(this, tab)))
+ {
+ prev_fanout *= prev_tab->records_read;
+ examined_rows+= tab->get_examined_rows() * prev_fanout;
+ prev_tab= tab;
+ }
+ return examined_rows;
+}
+
+
+/**
Find a good, possibly optimal, query execution plan (QEP) by a possibly
exhaustive search.
@@ -8061,36 +8104,15 @@ JOIN::make_simple_join(JOIN *parent, TABLE *temp_table)
row_limit= unit->select_limit_cnt;
do_send_rows= row_limit ? 1 : 0;
- join_tab->use_join_cache= FALSE;
- join_tab->cache=0; /* No caching */
+ bzero(join_tab, sizeof(JOIN_TAB));
join_tab->table=temp_table;
- join_tab->cache_select= 0;
- join_tab->select=0;
- join_tab->select_cond= 0; // Avoid valgrind warning
join_tab->set_select_cond(NULL, __LINE__);
- join_tab->quick=0;
join_tab->type= JT_ALL; /* Map through all records */
join_tab->keys.init();
join_tab->keys.set_all(); /* test everything in quick */
- join_tab->info=0;
- join_tab->on_expr_ref=0;
- join_tab->last_inner= 0;
- join_tab->first_unmatched= 0;
join_tab->ref.key = -1;
- join_tab->not_used_in_distinct=0;
join_tab->read_first_record= join_init_read_record;
- join_tab->preread_init_done= FALSE;
join_tab->join= this;
- join_tab->ref.key_parts= 0;
- join_tab->keep_current_rowid= FALSE;
- join_tab->flush_weedout_table= join_tab->check_weed_out_table= NULL;
- join_tab->do_firstmatch= NULL;
- join_tab->loosescan_match_tab= NULL;
- join_tab->emb_sj_nest= NULL;
- join_tab->pre_idx_push_select_cond= NULL;
- join_tab->bush_root_tab= NULL;
- join_tab->bush_children= NULL;
- join_tab->last_leaf_in_bush= FALSE;
bzero((char*) &join_tab->read_record,sizeof(join_tab->read_record));
temp_table->status=0;
temp_table->null_row=0;
@@ -10288,6 +10310,51 @@ double JOIN_TAB::scan_time()
return res;
}
+
+/**
+ Estimate the number of rows that a an access method will read from a table.
+
+ @todo: why not use JOIN_TAB::found_records
+*/
+
+ha_rows JOIN_TAB::get_examined_rows()
+{
+ ha_rows examined_rows;
+
+ if (select && select->quick)
+ examined_rows= select->quick->records;
+ else if (type == JT_NEXT || type == JT_ALL ||
+ type == JT_HASH || type ==JT_HASH_NEXT)
+ {
+ if (limit)
+ {
+ /*
+ @todo This estimate is wrong, a LIMIT query may examine much more rows
+ than the LIMIT itself.
+ */
+ examined_rows= limit;
+ }
+ else
+ {
+ if (table->is_filled_at_execution())
+ examined_rows= records;
+ else
+ {
+ /*
+ handler->info(HA_STATUS_VARIABLE) has been called in
+ make_join_statistics()
+ */
+ examined_rows= table->file->stats.records;
+ }
+ }
+ }
+ else
+ examined_rows= (ha_rows) records_read;
+
+ return examined_rows;
+}
+
+
/**
Initialize the join_tab before reading.
Currently only derived table/view materialization is done here.
@@ -10591,6 +10658,22 @@ void JOIN::cleanup(bool full)
tmp_join->tmp_table_param.save_copy_field= 0;
}
tmp_table_param.cleanup();
+
+ if (!join_tab)
+ {
+ List_iterator<TABLE_LIST> li(*join_list);
+ TABLE_LIST *table_ref;
+ while ((table_ref= li++))
+ {
+ if (table_ref->table &&
+ table_ref->jtbm_subselect &&
+ table_ref->jtbm_subselect->is_jtbm_const_tab)
+ {
+ free_tmp_table(thd, table_ref->table);
+ table_ref->table= NULL;
+ }
+ }
+ }
}
DBUG_VOID_RETURN;
}
@@ -11267,9 +11350,9 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
if (!item)
{
Item_func_eq *eq_item;
- if ((eq_item= new Item_func_eq(orig_left_item, orig_right_item)))
+ if (!(eq_item= new Item_func_eq(orig_left_item, orig_right_item)) ||
+ eq_item->set_cmp_func())
return FALSE;
- eq_item->set_cmp_func();
eq_item->quick_fix_field();
item= eq_item;
}
@@ -11362,9 +11445,9 @@ static bool check_row_equality(THD *thd, Item *left_row, Item_row *right_row,
if (!is_converted)
{
Item_func_eq *eq_item;
- if (!(eq_item= new Item_func_eq(left_item, right_item)))
+ if (!(eq_item= new Item_func_eq(left_item, right_item)) ||
+ eq_item->set_cmp_func())
return FALSE;
- eq_item->set_cmp_func();
eq_item->quick_fix_field();
eq_list->push_back(eq_item);
}
@@ -12050,9 +12133,8 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
eq_item= new Item_func_eq(field_item->real_item(), head_item);
- if (!eq_item)
+ if (!eq_item || eq_item->set_cmp_func())
return 0;
- eq_item->set_cmp_func();
eq_item->quick_fix_field();
}
current_sjm= field_sjm;
@@ -12139,7 +12221,7 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
Item_equal::get_first() for details.
@return
- The transformed condition
+ The transformed condition, or NULL in case of error
*/
static COND* substitute_for_best_equal_field(JOIN_TAB *context_tab,
@@ -18594,8 +18676,6 @@ check_reverse_order:
join_read_first:join_read_last;
tab->type=JT_NEXT; // Read with index_first(), index_next()
- if (table->covering_keys.is_set(best_key) && ! table->key_read)
- table->enable_keyread();
if (tab->pre_idx_push_select_cond)
{
tab->set_cond(tab->pre_idx_push_select_cond);
@@ -18606,6 +18686,7 @@ check_reverse_order:
orig_cond= 0;
orig_cond_saved= false;
}
+
table->file->ha_index_or_rnd_end();
if (tab->join->select_options & SELECT_DESCRIBE)
{
@@ -18613,6 +18694,7 @@ check_reverse_order:
tab->ref.key_parts= 0;
if (select_limit < table->file->stats.records)
tab->limit= select_limit;
+ table->disable_keyread();
}
}
else if (tab->type != JT_ALL)
@@ -20214,6 +20296,8 @@ copy_fields(TMP_TABLE_PARAM *param)
Copy_field *ptr=param->copy_field;
Copy_field *end=param->copy_field_end;
+ DBUG_ASSERT((ptr != NULL && end >= ptr) || (ptr == NULL && end == NULL));
+
for (; ptr != end; ptr++)
(*ptr->do_copy)(ptr);
@@ -21354,10 +21438,17 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
}
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_LIST *real_table= table->pos_in_table_list;
+ /*
+ Internal temporary tables have no corresponding table reference
+ object. Such a table may appear in EXPLAIN when a subquery that needs
+ a temporary table has been executed, and JOIN::exec replaced the
+ original JOIN with a plan to access the data in the temp table
+ (made by JOIN::make_simple_join).
+ */
+ const char *tab_name= real_table ? real_table->alias :
+ "internal_tmp_table";
+ item_list.push_back(new Item_string(tab_name, strlen(tab_name), cs));
}
/* "partitions" column */
if (join->thd->lex->describe & DESCRIBE_PARTITIONS)
@@ -21515,32 +21606,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
}
else
{
- ha_rows examined_rows;
- if (tab->select && tab->select->quick)
- examined_rows= tab->select->quick->records;
- else if (tab->type == JT_NEXT || tab->type == JT_ALL || is_hj)
- {
- if (tab->limit)
- examined_rows= tab->limit;
- else
- {
- if (tab->table->is_filled_at_execution())
- {
- examined_rows= tab->records;
- }
- else
- {
- /*
- handler->info(HA_STATUS_VARIABLE) has been called in
- make_join_statistics()
- */
- examined_rows= tab->table->file->stats.records;
- }
- }
- }
- else
- examined_rows=(ha_rows)tab->records_read;
-
+ ha_rows examined_rows= tab->get_examined_rows();
+
item_list.push_back(new Item_int((longlong) (ulonglong) examined_rows,
MY_INT64_NUM_DECIMAL_DIGITS));