[Commits] Rev 3570: MDEV-536: LP:1050806 - different result for a query using subquery, and in file:///data0/psergey/dev2/5.5/

Sergey Petrunya psergey at askmonty.org
Sun Nov 4 17:09:46 EET 2012


At file:///data0/psergey/dev2/5.5/

------------------------------------------------------------
revno: 3570
revision-id: psergey at askmonty.org-20121104150946-gjj2f536kt0e7jkq
parent: wlad at montyprogram.com-20121102233150-3t281xbzq5pck2jz
committer: Sergey Petrunya <psergey at askmonty.org>
branch nick: 5.5
timestamp: Sun 2012-11-04 19:09:46 +0400
message:
  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 at 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.
=== modified file 'mysql-test/r/subselect2.result'
--- a/mysql-test/r/subselect2.result	2012-10-18 21:33:06 +0000
+++ b/mysql-test/r/subselect2.result	2012-11-04 15:09:46 +0000
@@ -180,6 +180,32 @@
 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 @@
 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	<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;

=== modified file 'mysql-test/t/subselect2.test'
--- a/mysql-test/t/subselect2.test	2012-10-10 05:21:22 +0000
+++ b/mysql-test/t/subselect2.test	2012-11-04 15:09:46 +0000
@@ -204,6 +204,32 @@
 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 #
 CREATE TABLE t1 (a int, b int, INDEX idx(a));
@@ -220,7 +246,75 @@
                 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;
 

=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc	2012-10-16 11:04:42 +0000
+++ b/sql/opt_range.cc	2012-11-04 15:09:46 +0000
@@ -10944,6 +10944,13 @@
   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)
   {

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2012-10-18 21:33:06 +0000
+++ b/sql/sql_select.cc	2012-11-04 15:09:46 +0000
@@ -10603,9 +10603,22 @@
 
     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 @@
   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 @@
   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 @@
 			    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 @@
   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 @@
     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 @@
     // 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

=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h	2012-10-26 21:56:14 +0000
+++ b/sql/sql_select.h	2012-11-04 15:09:46 +0000
@@ -897,6 +897,14 @@
 
 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 @@
     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,



More information about the commits mailing list