From 25b5831a77cd3a8f1b0a1dfdb9ef16d9f33da0b8 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sat, 3 Nov 2012 00:31:50 +0100 Subject: [PATCH 1/2] MDEV-3830 - fix build on Intel compiler --- mysys/my_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/my_context.c b/mysys/my_context.c index 9d56b13ecb5..bcacd5b167d 100644 --- a/mysys/my_context.c +++ b/mysys/my_context.c @@ -206,7 +206,7 @@ my_context_spawn(struct my_context *c, void (*f)(void *), void *d) ( "movq %%rsp, (%[save])\n\t" "movq %[stack], %%rsp\n\t" -#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 && !defined(__INTEL_COMPILER) /* This emits a DWARF DW_CFA_undefined directive to make the return address undefined. This indicates that this is the top of the stack frame, and From 39e7072d64f5ff36d61bf81970ec398f8d937cfd Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Sun, 4 Nov 2012 19:09:46 +0400 Subject: [PATCH 2/2] MDEV-536: LP:1050806 - different result for a query using subquery, and MDEV-567: Wrong result from a query with correlated subquery if ICP is allowed: backport the fix developed for SHOW EXPLAIN: revision-id: psergey@askmonty.org-20120719115219-212cxmm6qvf0wlrb branch nick: 5.5-show-explain-r21 timestamp: Thu 2012-07-19 15:52:19 +0400 BUG#992942 & MDEV-325: Pre-liminary commit for testing and adjust it so that it handles DS-MRR scans correctly. --- mysql-test/r/subselect2.result | 99 +++++++++++++++++++++- mysql-test/t/subselect2.test | 96 +++++++++++++++++++++- sql/opt_range.cc | 7 ++ sql/sql_select.cc | 146 ++++++++++++++++++++++++++++++--- sql/sql_select.h | 10 +++ 5 files changed, 344 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/subselect2.result b/mysql-test/r/subselect2.result index 7eff7f949a8..4fd303dfd44 100644 --- a/mysql-test/r/subselect2.result +++ b/mysql-test/r/subselect2.result @@ -180,6 +180,32 @@ SET optimizer_switch=@tmp_optimizer_switch; DROP VIEW v1; DROP TABLE t1,t2,t3; # +# MDEV-536: LP:1050806 - different result for a query using subquery +# +DROP TABLE IF EXISTS `t1`; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE `t1` ( +`node_uid` bigint(20) unsigned DEFAULT NULL, +`date` datetime DEFAULT NULL, +`mirror_date` datetime DEFAULT NULL, +KEY `date` (`date`) +) ENGINE=MyISAM; +INSERT INTO `t1` VALUES (2085,'2012-01-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2084,'2012-02-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2088,'2012-03-01 00:00:00','2013-01-01 00:00:00'); +SELECT * FROM ( +SELECT node_uid, date, mirror_date, @result := 0 AS result +FROM t1 +WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) +ORDER BY mirror_date ASC +) AS calculated_result; +node_uid date mirror_date result +2085 2012-01-01 00:00:00 2013-01-01 00:00:00 0 +2084 2012-02-01 00:00:00 2013-01-01 00:00:00 0 +DROP TABLE t1; +# # MDEV-567: Wrong result from a query with correlated subquery if ICP is allowed # CREATE TABLE t1 (a int, b int, INDEX idx(a)); @@ -197,5 +223,76 @@ a b 1 0 1 1 1 3 -DROP TABLE t1, t2, t3; +set @tmp_mdev567=@@optimizer_switch; +set optimizer_switch='mrr=off'; +SELECT * FROM t3 +WHERE a = (SELECT COUNT(DISTINCT t2.b) FROM t1, t2 +WHERE t1.a = t2.a AND t2.a BETWEEN 7 AND 9 +AND t3.b = t1.b +GROUP BY t1.b); +a b +1 0 +1 1 +1 3 +DROP TABLE t1,t2,t3; +set optimizer_switch=@tmp_mdev567; +# +# MDEV-614, also MDEV-536, also LP:1050806: +# different result for a query using subquery between 5.5.25 and 5.5.27 +# +CREATE TABLE `t1` ( +`node_uid` bigint(20) unsigned DEFAULT NULL, +`date` datetime DEFAULT NULL, +`mirror_date` datetime DEFAULT NULL, +KEY `date` (`date`) +) ENGINE=MyISAM; +INSERT INTO `t1` VALUES (2085,'2012-01-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2084,'2012-02-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2088,'2012-03-01 00:00:00','2013-01-01 00:00:00'); +explain +SELECT * FROM ( +SELECT node_uid, date, mirror_date, @result := 0 AS result +FROM t1 +WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) +ORDER BY mirror_date ASC +) AS calculated_result; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE ALL NULL NULL NULL NULL 2 +2 DERIVED t1 range date date 9 NULL 2 Using index condition; Using where; Rowid-ordered scan; Using filesort +SELECT * FROM ( +SELECT node_uid, date, mirror_date, @result := 0 AS result +FROM t1 +WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) +ORDER BY mirror_date ASC +) AS calculated_result; +node_uid date mirror_date result +2085 2012-01-01 00:00:00 2013-01-01 00:00:00 0 +2084 2012-02-01 00:00:00 2013-01-01 00:00:00 0 +set @tmp_mdev614=@@optimizer_switch; +set optimizer_switch='mrr=off'; +explain +SELECT * FROM ( +SELECT node_uid, date, mirror_date, @result := 0 AS result +FROM t1 +WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) +ORDER BY mirror_date ASC +) AS calculated_result; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE ALL NULL NULL NULL NULL 2 +2 DERIVED t1 range date date 9 NULL 2 Using index condition; Using where; Using filesort +SELECT * FROM ( +SELECT node_uid, date, mirror_date, @result := 0 AS result +FROM t1 +WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) +ORDER BY mirror_date ASC +) AS calculated_result; +node_uid date mirror_date result +2085 2012-01-01 00:00:00 2013-01-01 00:00:00 0 +2084 2012-02-01 00:00:00 2013-01-01 00:00:00 0 +set optimizer_switch=@tmp_mdev614; +DROP TABLE t1; set optimizer_switch=@subselect2_test_tmp; diff --git a/mysql-test/t/subselect2.test b/mysql-test/t/subselect2.test index 75cf842fbdb..68894ad18cb 100644 --- a/mysql-test/t/subselect2.test +++ b/mysql-test/t/subselect2.test @@ -203,6 +203,32 @@ SET optimizer_switch=@tmp_optimizer_switch; DROP VIEW v1; DROP TABLE t1,t2,t3; +--echo # +--echo # MDEV-536: LP:1050806 - different result for a query using subquery +--echo # +DROP TABLE IF EXISTS `t1`; + +CREATE TABLE `t1` ( + `node_uid` bigint(20) unsigned DEFAULT NULL, + `date` datetime DEFAULT NULL, + `mirror_date` datetime DEFAULT NULL, + KEY `date` (`date`) +) ENGINE=MyISAM; + +INSERT INTO `t1` VALUES (2085,'2012-01-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2084,'2012-02-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2088,'2012-03-01 00:00:00','2013-01-01 00:00:00'); + +SELECT * FROM ( + SELECT node_uid, date, mirror_date, @result := 0 AS result + FROM t1 + WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) + ORDER BY mirror_date ASC +) AS calculated_result; + +DROP TABLE t1; + --echo # --echo # MDEV-567: Wrong result from a query with correlated subquery if ICP is allowed --echo # @@ -220,7 +246,75 @@ SELECT * FROM t3 WHERE t1.a = t2.a AND t2.a BETWEEN 7 AND 9 AND t3.b = t1.b GROUP BY t1.b); -DROP TABLE t1, t2, t3; + + +set @tmp_mdev567=@@optimizer_switch; +set optimizer_switch='mrr=off'; +SELECT * FROM t3 + WHERE a = (SELECT COUNT(DISTINCT t2.b) FROM t1, t2 + WHERE t1.a = t2.a AND t2.a BETWEEN 7 AND 9 + AND t3.b = t1.b + GROUP BY t1.b); + +DROP TABLE t1,t2,t3; +set optimizer_switch=@tmp_mdev567; + +--echo # +--echo # MDEV-614, also MDEV-536, also LP:1050806: +--echo # different result for a query using subquery between 5.5.25 and 5.5.27 +--echo # + +CREATE TABLE `t1` ( + `node_uid` bigint(20) unsigned DEFAULT NULL, + `date` datetime DEFAULT NULL, + `mirror_date` datetime DEFAULT NULL, + KEY `date` (`date`) +) ENGINE=MyISAM; + +INSERT INTO `t1` VALUES (2085,'2012-01-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2084,'2012-02-01 00:00:00','2013-01-01 00:00:00'); +INSERT INTO `t1` VALUES (2088,'2012-03-01 00:00:00','2013-01-01 00:00:00'); + +explain +SELECT * FROM ( + SELECT node_uid, date, mirror_date, @result := 0 AS result + FROM t1 + WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) + ORDER BY mirror_date ASC +) AS calculated_result; + +SELECT * FROM ( + SELECT node_uid, date, mirror_date, @result := 0 AS result + FROM t1 + WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) + ORDER BY mirror_date ASC +) AS calculated_result; + +set @tmp_mdev614=@@optimizer_switch; +set optimizer_switch='mrr=off'; +explain +SELECT * FROM ( + SELECT node_uid, date, mirror_date, @result := 0 AS result + FROM t1 + WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) + ORDER BY mirror_date ASC +) AS calculated_result; + +SELECT * FROM ( + SELECT node_uid, date, mirror_date, @result := 0 AS result + FROM t1 + WHERE date < '2012-12-12 12:12:12' + AND node_uid in (2085, 2084) + ORDER BY mirror_date ASC +) AS calculated_result; + +set optimizer_switch=@tmp_mdev614; + +DROP TABLE t1; + set optimizer_switch=@subselect2_test_tmp; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 791af42521a..b98edeb15db 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -10944,6 +10944,13 @@ int QUICK_RANGE_SELECT::reset() DBUG_ENTER("QUICK_RANGE_SELECT::reset"); last_range= NULL; cur_range= (QUICK_RANGE**) ranges.buffer; + + if (file->inited == handler::RND) + { + /* Handler could be left in this state by MRR */ + if ((error= file->ha_rnd_end())) + DBUG_RETURN(error); + } if (file->inited == handler::NONE) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a4b2d376e05..b6b1259ca49 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10603,9 +10603,22 @@ void JOIN::cleanup(bool full) if (full) { + JOIN_TAB *sort_tab= first_linear_tab(this, WITHOUT_CONST_TABLES); + if (pre_sort_join_tab) + { + if (sort_tab && sort_tab->select == pre_sort_join_tab->select) + { + pre_sort_join_tab->select= NULL; + } + else + clean_pre_sort_join_tab(); + } + for (tab= first_linear_tab(this, WITH_CONST_TABLES); tab; tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS)) + { tab->cleanup(); + } } else { @@ -18849,6 +18862,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, TABLE *table; SQL_SELECT *select; JOIN_TAB *tab; + int err= 0; + bool quick_created= FALSE; DBUG_ENTER("create_sort_index"); if (join->table_count == join->const_tables) @@ -18856,18 +18871,61 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, tab= join->join_tab + join->const_tables; table= tab->table; select= tab->select; + + JOIN_TAB *save_pre_sort_join_tab= NULL; + if (join->pre_sort_join_tab) + { + /* + we've already been in this function, and stashed away the original access + method in join->pre_sort_join_tab, restore it now. + */ + + /* First, restore state of the handler */ + if (join->pre_sort_index != MAX_KEY) + { + if (table->file->ha_index_or_rnd_end()) + goto err; + if (join->pre_sort_idx_pushed_cond) + { + table->file->idx_cond_push(join->pre_sort_index, + join->pre_sort_idx_pushed_cond); + } + } + else + { + if (table->file->ha_index_or_rnd_end() || + table->file->ha_rnd_init(TRUE)) + goto err; + } + + /* Second, restore access method parameters */ + tab->records= join->pre_sort_join_tab->records; + tab->select= join->pre_sort_join_tab->select; + tab->select_cond= join->pre_sort_join_tab->select_cond; + tab->type= join->pre_sort_join_tab->type; + tab->read_first_record= join->pre_sort_join_tab->read_first_record; + + save_pre_sort_join_tab= join->pre_sort_join_tab; + join->pre_sort_join_tab= NULL; + } + else + { + /* + Save index #, save index condition. Do it right now, because MRR may + */ + if (table->file->inited == handler::INDEX) + { + join->pre_sort_index= table->file->active_index; + join->pre_sort_idx_pushed_cond= table->file->pushed_idx_cond; + // no need to save key_read + } + else + join->pre_sort_index= MAX_KEY; + } /* Currently ORDER BY ... LIMIT is not supported in subqueries. */ DBUG_ASSERT(join->group_list || !join->is_in_subquery()); - /* - If we have a select->quick object that is created outside of - create_sort_index() and this is part of a subquery that - potentially can be executed multiple times then we should not - delete the quick object on exit from this function. - */ - bool keep_quick= select && select->quick && join->join_tab_save; - /* When there is SQL_BIG_RESULT do not sort using index for GROUP BY, and thus force sorting on disk unless a group min-max optimization @@ -18919,7 +18977,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, get_quick_select_for_ref(thd, table, &tab->ref, tab->found_records)))) goto err; - DBUG_ASSERT(!keep_quick); + quick_created= TRUE; } } @@ -18935,7 +18993,27 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, table->sort.found_records=filesort(thd, table,join->sortorder, length, select, filesort_limit, 0, &examined_rows); + + if (quick_created) + { + /* This will delete the quick select. */ + select->cleanup(); + } + + if (!join->pre_sort_join_tab) + { + if (save_pre_sort_join_tab) + join->pre_sort_join_tab= save_pre_sort_join_tab; + else if (!(join->pre_sort_join_tab= (JOIN_TAB*)thd->alloc(sizeof(JOIN_TAB)))) + goto err; + } + + *(join->pre_sort_join_tab)= *tab; + + /*TODO: here, close the index scan, cancel index-only read. */ tab->records= table->sort.found_records; // For SQL_CALC_ROWS +#if 0 + /* MariaDB doesn't need the following: */ if (select) { /* @@ -18952,6 +19030,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, tablesort_result_cache= table->sort.io_cache; table->sort.io_cache= NULL; + // select->cleanup(); // filesort did select /* If a quick object was created outside of create_sort_index() that might be reused, then do not call select->cleanup() since @@ -18974,18 +19053,61 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, // Restore the output resultset table->sort.io_cache= tablesort_result_cache; } +#endif + tab->select=NULL; tab->set_select_cond(NULL, __LINE__); - tab->last_inner= 0; - tab->first_unmatched= 0; tab->type=JT_ALL; // Read with normal read_record tab->read_first_record= join_init_read_record; + tab->table->file->ha_index_or_rnd_end(); + + if (err) + goto err; + tab->join->examined_rows+=examined_rows; - table->disable_keyread(); // Restore if we used indexes DBUG_RETURN(table->sort.found_records == HA_POS_ERROR); err: DBUG_RETURN(-1); } + +void JOIN::clean_pre_sort_join_tab() +{ + //TABLE *table= pre_sort_join_tab->table; + /* + Note: we can come here for fake_select_lex object. That object will have + the table already deleted by st_select_lex_unit::cleanup(). + We rely on that fake_select_lex didn't have quick select. + */ +#if 0 + if (pre_sort_join_tab->select && pre_sort_join_tab->select->quick) + { + /* + We need to preserve tablesort's output resultset here, because + QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT (called by + SQL_SELECT::cleanup()) may free it assuming it's the result of the quick + select operation that we no longer need. Note that all the other parts of + this data structure are cleaned up when + QUICK_INDEX_MERGE_SELECT::get_next encounters end of data, so the next + SQL_SELECT::cleanup() call changes sort.io_cache alone. + */ + IO_CACHE *tablesort_result_cache; + + tablesort_result_cache= table->sort.io_cache; + table->sort.io_cache= NULL; + pre_sort_join_tab->select->cleanup(); + table->quick_keys.clear_all(); // as far as we cleanup select->quick + table->intersect_keys.clear_all(); + table->sort.io_cache= tablesort_result_cache; + } +#endif + //table->disable_keyread(); // Restore if we used indexes + if (pre_sort_join_tab->select && pre_sort_join_tab->select->quick) + { + pre_sort_join_tab->select->cleanup(); + } +} + + /***************************************************************************** Remove duplicates from tmp table This should be recoded to add a unique index to the table and remove diff --git a/sql/sql_select.h b/sql/sql_select.h index 118a684ab62..e4687b4f00c 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -897,6 +897,14 @@ protected: public: JOIN_TAB *join_tab, **best_ref; + + /* + Saved join_tab for pre_sorting. create_sort_index() will save here.. + */ + JOIN_TAB *pre_sort_join_tab; + uint pre_sort_index; + Item *pre_sort_idx_pushed_cond; + void clean_pre_sort_join_tab(); /* For "Using temporary+Using filesort" queries, JOIN::join_tab can point to @@ -1279,6 +1287,8 @@ public: outer_ref_cond= pseudo_bits_cond= NULL; in_to_exists_where= NULL; in_to_exists_having= NULL; + + pre_sort_join_tab= NULL; } int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,