4669 Ole John Aske 2013-01-24
Fix for bug#16202425 INCORRECT LOGIC USED TO FIND OUTER JOINS IN AQP (ABSTRACT QUERY PLAN)
The AQP module contain the member function ::get_join_type('predecessor')
which is intended to return whether 'this' table and its 'predecessor'
table is related with an inner or outer join.
We had implemented this logic by using the nested 'embedding' structures
in the TABLE_LIST. As MySQL 5.6 seems to have extended the usage of the
'embedding' to also be used as part of subquery optimization, this code
is now broken. (And it might even have been broken prior to 5.6...)
Currently this materializes as crashing RQG tests in our clone
mysql-5.6-cluster which fails on
'DBUG_ASSERT(child_embedding->outer_join != 0);'.
I assume this to be due to 5.6 extending the usage of 'embedding' to not
only be used as part of inner/outer join nests.
This fix reimplements ::get_join_type() to instead use the
'first_inner' and 'last_inner' member fields to determine the
join type between two tables. This seems to also more closely resembles
how the join types are determined internally in the optimizer.
modified:
sql/abstract_query_plan.cc
4668 Venkata Sidagam 2013-01-24 [merge]
Bug #11752803 SERVER CRASHES IF MAX_CONNECTIONS DECREASED BELOW
CERTAIN LEVEL
Merging from 5.5 to 5.6
modified:
internal/mysql-test/suite/i_main/r/connect.result
internal/mysql-test/suite/i_main/t/connect.test
mysys/thr_alarm.c
=== modified file 'sql/abstract_query_plan.cc'
=== modified file 'sql/abstract_query_plan.cc'
--- a/sql/abstract_query_plan.cc 2012-10-30 07:59:01 +0000
+++ b/sql/abstract_query_plan.cc 2013-01-24 09:45:50 +0000
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
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
@@ -73,70 +73,37 @@
DBUG_ENTER("get_join_type");
DBUG_ASSERT(get_access_no() > predecessor->get_access_no());
- if (get_join_tab()->table->pos_in_table_list->outer_join != 0)
- {
- /*
- This cover unnested outer joins such as
- 'select * from t1 left join t2 on t1.attr=t1.pk'.
- */
+ const JOIN_TAB* const first_inner= get_join_tab()->first_inner;
+ if (first_inner == NULL)
+ {
+ // 'this' is not outer joined with any table.
+ DBUG_PRINT("info", ("JT_INNER_JOIN'ed table %s",
+ get_join_tab()->table->alias));
+ DBUG_RETURN(JT_INNER_JOIN);
+ }
+
+ /**
+ * Fall Through: 'this' is a member in an outer join,
+ * but 'predecessor' may still be embedded in the same
+ * inner join as 'this'.
+ */
+ const JOIN_TAB* const last_inner= first_inner->last_inner;
+ if (predecessor->get_join_tab() >= first_inner &&
+ predecessor->get_join_tab() <= last_inner)
+ {
+ DBUG_PRINT("info", ("JT_INNER_JOIN between %s and %s",
+ predecessor->get_join_tab()->table->alias,
+ get_join_tab()->table->alias));
+ DBUG_RETURN(JT_INNER_JOIN);
+ }
+ else
+ {
DBUG_PRINT("info", ("JT_OUTER_JOIN between %s and %s",
predecessor->get_join_tab()->table->alias,
get_join_tab()->table->alias));
DBUG_RETURN(JT_OUTER_JOIN);
}
-
- const TABLE_LIST* const child_embedding=
- get_join_tab()->table->pos_in_table_list->embedding;
-
- if (child_embedding == NULL)
- {
- // 'this' is not on the inner side of any left join.
- DBUG_PRINT("info", ("JT_INNER_JOIN between %s and %s",
- predecessor->get_join_tab()->table->alias,
- get_join_tab()->table->alias));
- DBUG_RETURN(JT_INNER_JOIN);
- }
-
- DBUG_ASSERT(child_embedding->outer_join != 0);
-
- const TABLE_LIST *predecessor_embedding=
- predecessor->get_join_tab()->table->pos_in_table_list->embedding;
-
- /*
- This covers the nested join case, i.e:
- <table reference> LEFT JOIN (<joined table>).
-
- TABLE_LIST objects form a tree where TABLE_LIST::emebedding points to
- the parent object. Now if child_embedding is non null and not an
- ancestor of predecessor_embedding in the embedding tree, then 'this'
- must be on the inner side of some left join where 'predecessor' is on
- the outer side.
- */
- while (true)
- {
- if (predecessor_embedding == child_embedding)
- {
- DBUG_PRINT("info", ("JT_INNER_JOIN between %s and %s",
- predecessor->get_join_tab()->table->alias,
- get_join_tab()->table->alias));
- DBUG_RETURN(JT_INNER_JOIN);
- }
- else if (predecessor_embedding == NULL)
- {
- /*
- We reached the root of the tree without finding child_embedding,
- so it must be in another branch and hence on the inner side of some
- left join where 'predecessor' is on the outer side.
- */
- DBUG_PRINT("info", ("JT_OUTER_JOIN between %s and %s",
- predecessor->get_join_tab()->table->alias,
- get_join_tab()->table->alias));
- DBUG_RETURN(JT_OUTER_JOIN);
- }
- // Iterate through ancestors of predecessor_embedding.
- predecessor_embedding = predecessor_embedding->embedding;
- }
- }
+ } //Table_access::get_join_type
/**
Get the number of key values for this operation. It is an error
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-5.6 branch (ole.john.aske:4668 to 4669) Bug#16202425 | Ole John Aske | 11 Mar 2013 |