mirror of
https://github.com/MariaDB/server.git
synced 2026-05-07 07:35:32 +02:00
Merge of fix for Bug#52357
This commit is contained in:
commit
0c82d3f3f4
4 changed files with 119 additions and 12 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
15
sql/table.h
15
sql/table.h
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue