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.cc144
1 files changed, 109 insertions, 35 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 167babe9658..932a8d51af3 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -266,15 +266,15 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
setup_tables_done_option changed for next rexecution
*/
res= mysql_select(thd, &select_lex->ref_pointer_array,
- (TABLE_LIST*) select_lex->table_list.first,
+ select_lex->table_list.first,
select_lex->with_wild, select_lex->item_list,
select_lex->where,
select_lex->order_list.elements +
select_lex->group_list.elements,
- (ORDER*) select_lex->order_list.first,
- (ORDER*) select_lex->group_list.first,
+ select_lex->order_list.first,
+ select_lex->group_list.first,
select_lex->having,
- (ORDER*) lex->proc_list.first,
+ lex->proc_list.first,
select_lex->options | thd->options |
setup_tables_done_option,
result, unit, select_lex);
@@ -574,13 +574,21 @@ JOIN::prepare(Item ***rref_pointer_array,
{
Item *item= *ord->item;
/*
- Disregard sort order if there's only "{VAR}CHAR(0) NOT NULL" fields
- there. Such fields don't contain any data to sort.
+ Disregard sort order if there's only
+ zero length NOT NULL fields (e.g. {VAR}CHAR(0) NOT NULL") or
+ zero length NOT NULL string functions there.
+ Such tuples don't contain any data to sort.
*/
if (!real_order &&
- (item->type() != Item::FIELD_ITEM ||
- ((Item_field *) item)->field->maybe_null() ||
- ((Item_field *) item)->field->sort_length()))
+ /* Not a zero length NOT NULL field */
+ ((item->type() != Item::FIELD_ITEM ||
+ ((Item_field *) item)->field->maybe_null() ||
+ ((Item_field *) item)->field->sort_length()) &&
+ /* AND not a zero length NOT NULL string function. */
+ (item->type() != Item::FUNC_ITEM ||
+ item->maybe_null ||
+ item->result_type() != STRING_RESULT ||
+ item->max_length)))
real_order= TRUE;
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
@@ -2717,15 +2725,29 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
as well as allow us to catch illegal cross references/
Warshall's algorithm is used to build the transitive closure.
As we use bitmaps to represent the relation the complexity
- of the algorithm is O((number of tables)^2).
+ of the algorithm is O((number of tables)^2).
+
+ The classic form of the Warshall's algorithm would look like:
+ for (i= 0; i < table_count; i++)
+ {
+ for (j= 0; j < table_count; j++)
+ {
+ for (k= 0; k < table_count; k++)
+ {
+ if (bitmap_is_set(stat[j].dependent, i) &&
+ bitmap_is_set(stat[i].dependent, k))
+ bitmap_set_bit(stat[j].dependent, k);
+ }
+ }
*/
- for (i= 0, s= stat ; i < table_count ; i++, s++)
+
+ for (s= stat ; s < stat_end ; s++)
{
- for (uint j= 0 ; j < table_count ; j++)
+ table= s->table;
+ for (JOIN_TAB *t= stat ; t < stat_end ; t++)
{
- table= stat[j].table;
- if (s->dependent & table->map)
- s->dependent |= table->reginfo.join_tab->dependent;
+ if (t->dependent & table->map)
+ t->dependent |= table->reginfo.join_tab->dependent;
}
if (outer_join & s->table->map)
s->table->maybe_null= 1;
@@ -7279,7 +7301,8 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
*simple_order=0; // Must do a temp table to sort
else if (!(order_tables & not_const_tables))
{
- if (order->item[0]->with_subselect)
+ if (order->item[0]->with_subselect &&
+ !(join->select_lex->options & SELECT_DESCRIBE))
order->item[0]->val_str(&order->item[0]->str_value);
DBUG_PRINT("info",("removing: %s", order->item[0]->full_name()));
continue; // skip const item
@@ -8784,6 +8807,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
NESTED_JOIN *nested_join;
TABLE_LIST *prev_table= 0;
List_iterator<TABLE_LIST> li(*join_list);
+ bool straight_join= test(join->select_options & SELECT_STRAIGHT_JOIN);
DBUG_ENTER("simplify_joins");
/*
@@ -8896,7 +8920,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
if (prev_table)
{
/* The order of tables is reverse: prev_table follows table */
- if (prev_table->straight)
+ if (prev_table->straight || straight_join)
prev_table->dep_tables|= used_tables;
if (prev_table->on_expr)
{
@@ -9178,6 +9202,46 @@ static bool check_interleaving_with_nj(JOIN_TAB *next_tab)
/**
Nested joins perspective: Remove the last table from the join order.
+ The algorithm is the reciprocal of check_interleaving_with_nj(), hence
+ parent join nest nodes are updated only when the last table in its child
+ node is removed. The ASCII graphic below will clarify.
+
+ %A table nesting such as <tt> t1 x [ ( t2 x t3 ) x ( t4 x t5 ) ] </tt>is
+ represented by the below join nest tree.
+
+ @verbatim
+ NJ1
+ _/ / \
+ _/ / NJ2
+ _/ / / \
+ / / / \
+ t1 x [ (t2 x t3) x (t4 x t5) ]
+ @endverbatim
+
+ At the point in time when check_interleaving_with_nj() adds the table t5 to
+ the query execution plan, QEP, it also directs the node named NJ2 to mark
+ the table as covered. NJ2 does so by incrementing its @c counter
+ member. Since all of NJ2's tables are now covered by the QEP, the algorithm
+ proceeds up the tree to NJ1, incrementing its counter as well. All join
+ nests are now completely covered by the QEP.
+
+ restore_prev_nj_state() does the above in reverse. As seen above, the node
+ NJ1 contains the nodes t2, t3, and NJ2. Its counter being equal to 3 means
+ that the plan covers t2, t3, and NJ2, @e and that the sub-plan (t4 x t5)
+ completely covers NJ2. The removal of t5 from the partial plan will first
+ decrement NJ2's counter to 1. It will then detect that NJ2 went from being
+ completely to partially covered, and hence the algorithm must continue
+ upwards to NJ1 and decrement its counter to 2. %A subsequent removal of t4
+ will however not influence NJ1 since it did not un-cover the last table in
+ NJ2.
+
+ SYNOPSIS
+ restore_prev_nj_state()
+ last join table to remove, it is assumed to be the last in current
+ partial join order.
+
+ DESCRIPTION
+
Remove the last table from the partial join order and update the nested
joins counters and join->cur_embedding_map. It is ok to call this
function for the first table in join order (for which
@@ -9191,19 +9255,20 @@ static void restore_prev_nj_state(JOIN_TAB *last)
{
TABLE_LIST *last_emb= last->table->pos_in_table_list->embedding;
JOIN *join= last->join;
- while (last_emb)
+ for (;last_emb != NULL; last_emb= last_emb->embedding)
{
- if (!(--last_emb->nested_join->counter))
- join->cur_embedding_map&= ~last_emb->nested_join->nj_map;
- else if (last_emb->nested_join->n_tables-1 ==
- last_emb->nested_join->counter)
- {
- join->cur_embedding_map|= last_emb->nested_join->nj_map;
- break;
- }
- else
+ NESTED_JOIN *nest= last_emb->nested_join;
+ DBUG_ASSERT(nest->counter > 0);
+
+ bool was_fully_covered= nest->is_fully_covered();
+
+ if (--nest->counter == 0)
+ join->cur_embedding_map&= ~nest->nj_map;
+
+ if (!was_fully_covered)
break;
- last_emb= last_emb->embedding;
+
+ join->cur_embedding_map|= nest->nj_map;
}
}
@@ -13615,6 +13680,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
uint nr;
key_map keys;
uint best_key_parts;
+ uint saved_best_key_parts= 0;
int best_key_direction;
ha_rows best_records;
double read_time;
@@ -13816,6 +13882,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
{
best_key= nr;
best_key_parts= keyinfo->key_parts;
+ saved_best_key_parts= used_key_parts;
best_records= quick_records;
is_best_covering= is_covering;
best_key_direction= direction;
@@ -13902,8 +13969,15 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
}
}
- used_key_parts= best_key_parts;
order_direction= best_key_direction;
+ /*
+ saved_best_key_parts is actual number of used keyparts found by the
+ test_if_order_by_key function. It could differ from keyinfo->key_parts,
+ thus we have to restore it in case of desc order as it affects
+ QUICK_SELECT_DESC behaviour.
+ */
+ used_key_parts= (order_direction == -1) ?
+ saved_best_key_parts : best_key_parts;
}
else
DBUG_RETURN(0);
@@ -17052,15 +17126,15 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
thd->lex->current_select= first;
unit->set_limit(unit->global_parameters);
res= mysql_select(thd, &first->ref_pointer_array,
- (TABLE_LIST*) first->table_list.first,
+ first->table_list.first,
first->with_wild, first->item_list,
first->where,
first->order_list.elements +
first->group_list.elements,
- (ORDER*) first->order_list.first,
- (ORDER*) first->group_list.first,
+ first->order_list.first,
+ first->group_list.first,
first->having,
- (ORDER*) thd->lex->proc_list.first,
+ thd->lex->proc_list.first,
first->options | thd->options | SELECT_DESCRIBE,
result, unit, first);
}
@@ -17370,7 +17444,7 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
if (group_list.elements)
{
str->append(STRING_WITH_LEN(" group by "));
- print_order(str, (ORDER *) group_list.first, query_type);
+ print_order(str, group_list.first, query_type);
switch (olap)
{
case CUBE_TYPE:
@@ -17401,7 +17475,7 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
if (order_list.elements)
{
str->append(STRING_WITH_LEN(" order by "));
- print_order(str, (ORDER *) order_list.first, query_type);
+ print_order(str, order_list.first, query_type);
}
// limit