Skip to content

Commit a3a0330

Browse files
committed
Bug#28957660 Regression: Crash in select_lex::flatten_subqueries
Followup patch: Ensure that semi-join transformation sequence is deterministic. Sorting of semi-join transformation candidate objects in SELECT_LEX::flatten_subqueries was not deterministic and could vary from platform to platform. The sort criterion has been improved by adding position in the candidate array as the last criterion, thus making sorting fully deterministic.
1 parent 0dc91e7 commit a3a0330

File tree

3 files changed

+20
-7
lines changed

3 files changed

+20
-7
lines changed

mysql-test/r/subquery_exists.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ EXISTS (SELECT * FROM t1) AND
486486
EXISTS (SELECT * FROM t1);
487487
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
488488
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
489-
3 SUBQUERY t1 NULL ALL NULL NULL NULL NULL 1 100.00 NULL
489+
32 SUBQUERY t1 NULL ALL NULL NULL NULL NULL 1 100.00 NULL
490490
Warnings:
491491
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) semi join (`test`.`t1`) where 0
492492
SELECT * FROM t1

sql/sql_const.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,10 @@
106106
element, such as a random function or a non-deterministic function.
107107
Expressions containing this bit cannot be evaluated once and then cached,
108108
they must be evaluated at latest possible point.
109+
MAX_TABLES_FOR_SIZE adds the pseudo bits and is used for sizing purposes only.
109110
*/
110-
#define MAX_TABLES (sizeof(table_map) * 8 - 3) /* Max tables in join */
111+
#define MAX_TABLES_FOR_SIZE (sizeof(table_map) * 8) ///< Use for sizing ONLY
112+
#define MAX_TABLES (MAX_TABLES_FOR_SIZE - 3) ///< Max tables in join
111113
#define INNER_TABLE_BIT (((table_map)1) << (MAX_TABLES + 0))
112114
#define OUTER_REF_TABLE_BIT (((table_map)1) << (MAX_TABLES + 1))
113115
#define RAND_TABLE_BIT (((table_map)1) << (MAX_TABLES + 2))

sql/sql_resolver.cc

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2996,7 +2996,11 @@ static bool replace_subcondition(THD *thd, Item **tree, Item *old_cond,
29962996
temporary table.
29972997
We deal with this problem by flattening children's subqueries first and
29982998
then using a heuristic rule to determine each subquery predicate's
2999-
"priority".
2999+
priority, which is calculated in this order:
3000+
3001+
1. Prefer dependent subqueries over non-dependent ones
3002+
2. Prefer subqueries with many tables over those with fewer tables
3003+
3. Prefer early subqueries over later ones (to make sort deterministic)
30003004
30013005
@returns false if success, true if error
30023006
*/
@@ -3031,7 +3035,8 @@ bool SELECT_LEX::flatten_subqueries(THD *thd) {
30313035
there are cases where flattening is not possible and only the parent can
30323036
know.
30333037
*/
3034-
for (subq = subq_begin; subq < subq_end; subq++) {
3038+
uint subq_no;
3039+
for (subq = subq_begin, subq_no = 0; subq < subq_end; subq++, subq_no++) {
30353040
// Transformation of IN and EXISTS subqueries is supported
30363041
DBUG_ASSERT((*subq)->substype() == Item_subselect::IN_SUBS ||
30373042
(*subq)->substype() == Item_subselect::EXISTS_SUBS);
@@ -3041,10 +3046,16 @@ bool SELECT_LEX::flatten_subqueries(THD *thd) {
30413046
// Check that we proceeded bottom-up
30423047
DBUG_ASSERT(child_select->sj_candidates == NULL);
30433048

3049+
bool dependent = (*subq)->unit->uncacheable & UNCACHEABLE_DEPENDENT;
30443050
(*subq)->sj_convert_priority =
3045-
(((*subq)->unit->uncacheable & UNCACHEABLE_DEPENDENT) ? MAX_TABLES
3046-
: 0) +
3047-
child_select->leaf_table_count;
3051+
(((dependent * MAX_TABLES_FOR_SIZE) + // dependent subqueries first
3052+
child_select->leaf_table_count) *
3053+
65536) + // then with many tables
3054+
(65536 - subq_no); // then based on position
3055+
/*
3056+
We may actually allocate more than 64k subqueries in a query block,
3057+
but this is so unlikely that we ignore the impact it may have on sorting.
3058+
*/
30483059
}
30493060

30503061
/*

0 commit comments

Comments
 (0)