Merge of fix for Bug#52357

This commit is contained in:
Martin Hansson 2010-05-06 10:59:28 +02:00
commit 0c82d3f3f4
4 changed files with 119 additions and 12 deletions

View file

@ -9091,6 +9091,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
@ -9104,19 +9144,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->join_list.elements-1 ==
last_emb->nested_join->counter)
{
join->cur_embedding_map|= last_emb->nested_join->nj_map;
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;
}
else
break;
last_emb= last_emb->embedding;
join->cur_embedding_map|= nest->nj_map;
}
}

View file

@ -1691,7 +1691,11 @@ typedef struct st_nested_join
List<TABLE_LIST> join_list; /* list of elements in the nested join */
table_map used_tables; /* bitmap of tables in the nested join */
table_map not_null_tables; /* tables that rejects nulls */
struct st_join_table *first_nested;/* the first nested table in the plan */
/**
Used for pointing out the first table in the plan being covered by this
join nest. It is used exclusively within make_outerjoin_info().
*/
struct st_join_table *first_nested;
/*
Used to count tables in the nested join in 2 isolated places:
1. In make_outerjoin_info().
@ -1701,6 +1705,15 @@ typedef struct st_nested_join
*/
uint counter;
nested_join_map nj_map; /* Bit used to identify this nested join*/
/**
True if this join nest node is completely covered by the query execution
plan. This means two things.
1. All tables on its @c join_list are covered by the plan.
2. All child join nest nodes are fully covered.
*/
bool is_fully_covered() const { return join_list.elements == counter; }
} NESTED_JOIN;