Commit 39e7072d authored by Sergey Petrunya's avatar Sergey Petrunya

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.
parent 25b5831a
...@@ -180,6 +180,32 @@ SET optimizer_switch=@tmp_optimizer_switch; ...@@ -180,6 +180,32 @@ SET optimizer_switch=@tmp_optimizer_switch;
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1,t2,t3; 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 # MDEV-567: Wrong result from a query with correlated subquery if ICP is allowed
# #
CREATE TABLE t1 (a int, b int, INDEX idx(a)); CREATE TABLE t1 (a int, b int, INDEX idx(a));
...@@ -197,5 +223,76 @@ a b ...@@ -197,5 +223,76 @@ a b
1 0 1 0
1 1 1 1
1 3 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 <derived2> 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 <derived2> 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; set optimizer_switch=@subselect2_test_tmp;
...@@ -203,6 +203,32 @@ SET optimizer_switch=@tmp_optimizer_switch; ...@@ -203,6 +203,32 @@ SET optimizer_switch=@tmp_optimizer_switch;
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1,t2,t3; 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 #
--echo # MDEV-567: Wrong result from a query with correlated subquery if ICP is allowed --echo # MDEV-567: Wrong result from a query with correlated subquery if ICP is allowed
--echo # --echo #
...@@ -220,7 +246,75 @@ SELECT * FROM t3 ...@@ -220,7 +246,75 @@ SELECT * FROM t3
WHERE t1.a = t2.a AND t2.a BETWEEN 7 AND 9 WHERE t1.a = t2.a AND t2.a BETWEEN 7 AND 9
AND t3.b = t1.b AND t3.b = t1.b
GROUP BY 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; set optimizer_switch=@subselect2_test_tmp;
...@@ -10944,6 +10944,13 @@ int QUICK_RANGE_SELECT::reset() ...@@ -10944,6 +10944,13 @@ int QUICK_RANGE_SELECT::reset()
DBUG_ENTER("QUICK_RANGE_SELECT::reset"); DBUG_ENTER("QUICK_RANGE_SELECT::reset");
last_range= NULL; last_range= NULL;
cur_range= (QUICK_RANGE**) ranges.buffer; 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) if (file->inited == handler::NONE)
{ {
......
...@@ -10603,9 +10603,22 @@ void JOIN::cleanup(bool full) ...@@ -10603,9 +10603,22 @@ void JOIN::cleanup(bool full)
if (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; for (tab= first_linear_tab(this, WITH_CONST_TABLES); tab;
tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS)) tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
{
tab->cleanup(); tab->cleanup();
}
} }
else else
{ {
...@@ -18849,6 +18862,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, ...@@ -18849,6 +18862,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
TABLE *table; TABLE *table;
SQL_SELECT *select; SQL_SELECT *select;
JOIN_TAB *tab; JOIN_TAB *tab;
int err= 0;
bool quick_created= FALSE;
DBUG_ENTER("create_sort_index"); DBUG_ENTER("create_sort_index");
if (join->table_count == join->const_tables) if (join->table_count == join->const_tables)
...@@ -18856,18 +18871,61 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, ...@@ -18856,18 +18871,61 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
tab= join->join_tab + join->const_tables; tab= join->join_tab + join->const_tables;
table= tab->table; table= tab->table;
select= tab->select; 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. */ /* Currently ORDER BY ... LIMIT is not supported in subqueries. */
DBUG_ASSERT(join->group_list || !join->is_in_subquery()); 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, 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 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, ...@@ -18919,7 +18977,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
get_quick_select_for_ref(thd, table, &tab->ref, get_quick_select_for_ref(thd, table, &tab->ref,
tab->found_records)))) tab->found_records))))
goto err; goto err;
DBUG_ASSERT(!keep_quick); quick_created= TRUE;
} }
} }
...@@ -18935,7 +18993,27 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, ...@@ -18935,7 +18993,27 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
table->sort.found_records=filesort(thd, table,join->sortorder, length, table->sort.found_records=filesort(thd, table,join->sortorder, length,
select, filesort_limit, 0, select, filesort_limit, 0,
&examined_rows); &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 tab->records= table->sort.found_records; // For SQL_CALC_ROWS
#if 0
/* MariaDB doesn't need the following: */
if (select) if (select)
{ {
/* /*
...@@ -18952,6 +19030,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, ...@@ -18952,6 +19030,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
tablesort_result_cache= table->sort.io_cache; tablesort_result_cache= table->sort.io_cache;
table->sort.io_cache= NULL; table->sort.io_cache= NULL;
// select->cleanup(); // filesort did select
/* /*
If a quick object was created outside of create_sort_index() If a quick object was created outside of create_sort_index()
that might be reused, then do not call select->cleanup() since that might be reused, then do not call select->cleanup() since
...@@ -18974,18 +19053,61 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, ...@@ -18974,18 +19053,61 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
// Restore the output resultset // Restore the output resultset
table->sort.io_cache= tablesort_result_cache; table->sort.io_cache= tablesort_result_cache;
} }
#endif
tab->select=NULL;
tab->set_select_cond(NULL, __LINE__); tab->set_select_cond(NULL, __LINE__);
tab->last_inner= 0;
tab->first_unmatched= 0;
tab->type=JT_ALL; // Read with normal read_record tab->type=JT_ALL; // Read with normal read_record
tab->read_first_record= join_init_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; tab->join->examined_rows+=examined_rows;
table->disable_keyread(); // Restore if we used indexes
DBUG_RETURN(table->sort.found_records == HA_POS_ERROR); DBUG_RETURN(table->sort.found_records == HA_POS_ERROR);
err: err:
DBUG_RETURN(-1); 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 Remove duplicates from tmp table
This should be recoded to add a unique index to the table and remove This should be recoded to add a unique index to the table and remove
......
...@@ -897,6 +897,14 @@ class JOIN :public Sql_alloc ...@@ -897,6 +897,14 @@ class JOIN :public Sql_alloc
public: public:
JOIN_TAB *join_tab, **best_ref; 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 For "Using temporary+Using filesort" queries, JOIN::join_tab can point to
...@@ -1279,6 +1287,8 @@ class JOIN :public Sql_alloc ...@@ -1279,6 +1287,8 @@ class JOIN :public Sql_alloc
outer_ref_cond= pseudo_bits_cond= NULL; outer_ref_cond= pseudo_bits_cond= NULL;
in_to_exists_where= NULL; in_to_exists_where= NULL;
in_to_exists_having= NULL; in_to_exists_having= NULL;
pre_sort_join_tab= NULL;
} }
int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num, int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment