List:Commits« Previous MessageNext Message »
From:jonas oreland Date:June 23 2011 1:43pm
Subject:bzr push into mysql-5.1-telco-7.1 branch (jonas:4258 to 4259)
View as plain text  
 4259 jonas oreland	2011-06-23 [merge]
      ndb - merge 70 to 71

    added:
      mysql-test/suite/ndb/r/ndb_row_count.result
      mysql-test/suite/ndb/t/ndb_row_count.test
    modified:
      mysql-test/suite/ndb/r/ndb_condition_pushdown.result
      mysql-test/suite/ndb/r/ndb_index_unique.result
      sql/ha_ndbcluster.cc
      sql/ha_ndbcluster.h
 4258 magnus.blaudd@stripped	2011-06-22 [merge]
      Merge 7.0 -> 7.1

    modified:
      storage/ndb/include/mgmapi/ndb_logevent.h
      storage/ndb/include/ndb_types.h.in
      storage/ndb/src/mgmsrv/MgmtSrvr.cpp
=== modified file 'mysql-test/suite/ndb/r/ndb_condition_pushdown.result'
--- a/mysql-test/suite/ndb/r/ndb_condition_pushdown.result	2011-04-08 13:59:44 +0000
+++ b/mysql-test/suite/ndb/r/ndb_condition_pushdown.result	2011-06-23 12:19:32 +0000
@@ -1910,7 +1910,7 @@ insert into NodeAlias VALUES(null, 8 , '
 12:22:26');
 explain select * from NodeAlias where (aliasKey LIKE '491803%');
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	SIMPLE	NodeAlias	range	NodeAlias_KeyIndex	NodeAlias_KeyIndex	48	NULL	2	Using where with pushed condition
+1	SIMPLE	NodeAlias	range	NodeAlias_KeyIndex	NodeAlias_KeyIndex	48	NULL	3	Using where with pushed condition
 select * from NodeAlias where (aliasKey LIKE '491803%') order by id;
 id	nodeId	displayName	aliasKey	objectVersion	changed
 7	8	491803%	491803%	0	2008-03-10 12:22:26
@@ -2105,46 +2105,46 @@ pk	x
 set engine_condition_pushdown = on;
 explain select * from t where x <> "aa";
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	1	Using where
+1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	2	Using where
 select * from t where x <> "aa";
 pk	x
 0	a
 explain select * from t where "aa" <> x;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	1	Using where
+1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	2	Using where
 select * from t where "aa" <> x;
 pk	x
 0	a
 explain select * from t where x between "" and "bb";
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	1	Using where
+1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	2	Using where
 select * from t where x between "" and "bb";
 pk	x
 0	a
 explain select * from t where x not between "" and "bb";
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	1	Using where
+1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	2	Using where
 select * from t where x not between "" and "bb";
 pk	x
 explain select * from t where x in ("","aa","b");
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	1	Using where
+1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	2	Using where
 select * from t where x in ("","aa","b");
 pk	x
 explain select * from t where x not in ("","aa","b");
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	1	Using where
+1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	2	Using where
 select * from t where x not in ("","aa","b");
 pk	x
 0	a
 explain select * from t where x like "aa?";
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	1	Using where with pushed condition
+1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	2	Using where with pushed condition
 select * from t where x like "aa?";
 pk	x
 explain select * from t where x not like "aa?";
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	1	Using where with pushed condition
+1	SIMPLE	t	ALL	NULL	NULL	NULL	NULL	2	Using where with pushed condition
 select * from t where x not like "aa?";
 pk	x
 0	a
@@ -2201,8 +2201,8 @@ primary key (`a`,`b`)
 ) engine = ndb;
 explain extended select * from tx join tx as t2 on tx.c=1 where t2.c=1;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
-1	SIMPLE	tx	ALL	NULL	NULL	NULL	NULL	0	0.00	Using where with pushed condition: (`test`.`tx`.`c` = 1)
-1	SIMPLE	t2	ALL	NULL	NULL	NULL	NULL	0	0.00	Using where with pushed condition: (`test`.`t2`.`c` = 1); Using join buffer
+1	SIMPLE	tx	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where with pushed condition: (`test`.`tx`.`c` = 1)
+1	SIMPLE	t2	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where with pushed condition: (`test`.`t2`.`c` = 1); Using join buffer
 Warnings:
 Note	1003	select `test`.`tx`.`a` AS `a`,`test`.`tx`.`b` AS `b`,`test`.`tx`.`c` AS `c`,`test`.`tx`.`d` AS `d`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`tx` join `test`.`tx` `t2` where ((`test`.`tx`.`c` = 1) and (`test`.`t2`.`c` = 1))
 explain extended
@@ -2212,7 +2212,7 @@ join tx as t2 on t2.a = tx.a and t2.b =
 join tx as t3 on t3.a = tx.c and t3.b = tx.d
 join tx as t4 on t4.a = t3.b and t4.b = t2.c;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
-1	SIMPLE	tx	ALL	PRIMARY	NULL	NULL	NULL	0	0.00	
+1	SIMPLE	tx	ALL	PRIMARY	NULL	NULL	NULL	2	100.00	
 1	SIMPLE	t2	eq_ref	PRIMARY	PRIMARY	8	test.tx.a,test.tx.b	1	100.00	
 1	SIMPLE	t3	eq_ref	PRIMARY	PRIMARY	8	test.tx.c,test.tx.d	1	100.00	
 1	SIMPLE	t4	eq_ref	PRIMARY	PRIMARY	8	test.tx.d,test.t2.c	1	100.00	
@@ -2231,8 +2231,8 @@ Warnings:
 Note	1003	select `test`.`t2`.`c` AS `c`,count(distinct `test`.`t2`.`a`) AS `count(distinct t2.a)` from `test`.`tx` join `test`.`tx` `t2` where ((`test`.`tx`.`b` = `test`.`t2`.`d`) and (`test`.`tx`.`a` = `test`.`t2`.`c`) and (`test`.`t2`.`a` = 4)) group by `test`.`t2`.`c`
 explain extended select * from tx join tx as t2 on tx.c=1 where t2.c=1;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
-1	SIMPLE	tx	ALL	NULL	NULL	NULL	NULL	0	0.00	Using where with pushed condition: (`test`.`tx`.`c` = 1)
-1	SIMPLE	t2	ALL	NULL	NULL	NULL	NULL	0	0.00	Using where with pushed condition: (`test`.`t2`.`c` = 1); Using join buffer
+1	SIMPLE	tx	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where with pushed condition: (`test`.`tx`.`c` = 1)
+1	SIMPLE	t2	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where with pushed condition: (`test`.`t2`.`c` = 1); Using join buffer
 Warnings:
 Note	1003	select `test`.`tx`.`a` AS `a`,`test`.`tx`.`b` AS `b`,`test`.`tx`.`c` AS `c`,`test`.`tx`.`d` AS `d`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`tx` join `test`.`tx` `t2` where ((`test`.`tx`.`c` = 1) and (`test`.`t2`.`c` = 1))
 explain extended
@@ -2256,7 +2256,7 @@ explain extended
 select * from t where exists
 (select * from t as subq where subq.i=3 and t.i=3);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
-1	PRIMARY	t	ALL	NULL	NULL	NULL	NULL	4	50.00	Using where
+1	PRIMARY	t	ALL	NULL	NULL	NULL	NULL	4	100.00	Using where
 2	DEPENDENT SUBQUERY	subq	ALL	NULL	NULL	NULL	NULL	4	100.00	Using where with pushed condition: (`test`.`subq`.`i` = 3)
 Warnings:
 Note	1276	Field or reference 'test.t.i' of SELECT #2 was resolved in SELECT #1
@@ -2266,7 +2266,7 @@ select * from t where exists
 (select * from subq where subq.i=3 and t.i=3);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
 1	PRIMARY	t	ALL	NULL	NULL	NULL	NULL	4	100.00	Using where
-2	DEPENDENT SUBQUERY	subq	ALL	NULL	NULL	NULL	NULL	4	50.00	Using where with pushed condition: (`test`.`subq`.`i` = 3)
+2	DEPENDENT SUBQUERY	subq	ALL	NULL	NULL	NULL	NULL	4	100.00	Using where with pushed condition: (`test`.`subq`.`i` = 3)
 Warnings:
 Note	1276	Field or reference 'test.t.i' of SELECT #2 was resolved in SELECT #1
 Note	1003	select `test`.`t`.`pk` AS `pk`,`test`.`t`.`i` AS `i` from `test`.`t` where exists(select 1 from `test`.`subq` where ((`test`.`subq`.`i` = 3) and (`test`.`t`.`i` = 3)))

=== modified file 'mysql-test/suite/ndb/r/ndb_index_unique.result'
--- a/mysql-test/suite/ndb/r/ndb_index_unique.result	2011-02-28 10:42:04 +0000
+++ b/mysql-test/suite/ndb/r/ndb_index_unique.result	2011-06-23 12:19:32 +0000
@@ -185,7 +185,7 @@ set @old_ecpd = @@session.engine_conditi
 set engine_condition_pushdown = true;
 explain select * from t2 where (b = 3 OR b = 5) AND c IS NULL AND a < 9 order by a;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	SIMPLE	t2	range	PRIMARY,b	PRIMARY	4	NULL	2	Using where with pushed condition
+1	SIMPLE	t2	range	PRIMARY,b	b	9	NULL	2	Using where with pushed condition; Using filesort
 select * from t2 where (b = 3 OR b = 5) AND c IS NULL AND a < 9 order by a;
 a	b	c
 3	3	NULL

=== added file 'mysql-test/suite/ndb/r/ndb_row_count.result'
--- a/mysql-test/suite/ndb/r/ndb_row_count.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb/r/ndb_row_count.result	2011-06-23 12:19:32 +0000
@@ -0,0 +1,115 @@
+create table t1(
+a int primary key
+) engine=ndbcluster;
+insert into t1 values
+(00),(01),(02),(03),(04),(05),(06),(07),(08),(09),
+(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35),(36),(37),(38),(39),
+(40),(41),(42),(43),(44),(45),(46),(47),(48),(49),
+(50),(51),(52),(53),(54),(55),(56),(57),(58),(59),
+(60),(61),(62),(63),(64),(65),(66),(67),(68),(69),
+(70),(71),(72),(73),(74),(75),(76),(77),(78),(79),
+(80),(81),(82),(83),(84),(85),(86),(87),(88),(89),
+(90),(91),(92),(93),(94),(95),(96),(97),(98),(99);
+
+# expected result 0 roundtrips - read stats from share
+explain extended select * from t1 where a < 100;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	t1	range	PRIMARY	PRIMARY	4	NULL	10	100.00	Using where with pushed condition: (`test`.`t1`.`a` < 100)
+Warnings:
+Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` < 100)
+@ndb_execute_count:=VARIABLE_VALUE-@ndb_init_execute_count
+0
+insert into t1 select a+100 from t1;
+
+# expected result 0 roundtrips - read stats from share
+explain extended select * from t1 where a < 100;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	t1	range	PRIMARY	PRIMARY	4	NULL	20	100.00	Using where with pushed condition: (`test`.`t1`.`a` < 100)
+Warnings:
+Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` < 100)
+@ndb_execute_count:=VARIABLE_VALUE-@ndb_init_execute_count
+0
+delete from t1 where a >= 100;
+
+# expected result 0 roundtrips - read stats from share
+explain extended select * from t1 where a < 100;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	t1	range	PRIMARY	PRIMARY	4	NULL	10	100.00	Using where with pushed condition: (`test`.`t1`.`a` < 100)
+Warnings:
+Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` < 100)
+@ndb_execute_count:=VARIABLE_VALUE-@ndb_init_execute_count
+0
+begin;
+insert into t1 select a+100 from t1;
+commit;
+
+# expected result 0 roundtrips - read stats from share
+explain extended select * from t1 where a < 100;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	t1	range	PRIMARY	PRIMARY	4	NULL	20	100.00	Using where with pushed condition: (`test`.`t1`.`a` < 100)
+Warnings:
+Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` < 100)
+@ndb_execute_count:=VARIABLE_VALUE-@ndb_init_execute_count
+0
+begin;
+delete from t1 where a >= 100;
+commit;
+
+# expected result 0 roundtrips - read stats from share
+explain extended select * from t1 where a < 100;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	t1	range	PRIMARY	PRIMARY	4	NULL	10	100.00	Using where with pushed condition: (`test`.`t1`.`a` < 100)
+Warnings:
+Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` < 100)
+@ndb_execute_count:=VARIABLE_VALUE-@ndb_init_execute_count
+0
+begin;
+insert into t1 select a+100 from t1;
+rollback;
+
+# expected result 0 roundtrips - read stats from share
+explain extended select * from t1 where a < 100;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	t1	range	PRIMARY	PRIMARY	4	NULL	10	100.00	Using where with pushed condition: (`test`.`t1`.`a` < 100)
+Warnings:
+Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` < 100)
+@ndb_execute_count:=VARIABLE_VALUE-@ndb_init_execute_count
+0
+begin;
+delete from t1 where a <= 100;
+rollback;
+
+# expected result 0 roundtrips - read stats from share
+explain extended select * from t1 where a < 100;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	t1	range	PRIMARY	PRIMARY	4	NULL	10	100.00	Using where with pushed condition: (`test`.`t1`.`a` < 100)
+Warnings:
+Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` < 100)
+@ndb_execute_count:=VARIABLE_VALUE-@ndb_init_execute_count
+0
+insert into t1 select a from t1;
+ERROR 23000: Can't write; duplicate key in table 't1'
+
+# expected result 0 roundtrips - read stats from share
+explain extended select * from t1 where a < 100;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	t1	range	PRIMARY	PRIMARY	4	NULL	10	100.00	Using where with pushed condition: (`test`.`t1`.`a` < 100)
+Warnings:
+Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` < 100)
+@ndb_execute_count:=VARIABLE_VALUE-@ndb_init_execute_count
+0
+begin;
+insert into t1 select a from t1;
+ERROR 23000: Can't write; duplicate key in table 't1'
+
+# expected result 0 roundtrips - read stats from share
+explain extended select * from t1 where a < 100;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	t1	range	PRIMARY	PRIMARY	4	NULL	10	100.00	Using where with pushed condition: (`test`.`t1`.`a` < 100)
+Warnings:
+Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` < 100)
+@ndb_execute_count:=VARIABLE_VALUE-@ndb_init_execute_count
+0
+drop table t1;

=== added file 'mysql-test/suite/ndb/t/ndb_row_count.test'
--- a/mysql-test/suite/ndb/t/ndb_row_count.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb/t/ndb_row_count.test	2011-06-23 12:19:32 +0000
@@ -0,0 +1,100 @@
+-- source include/have_ndb.inc
+
+create table t1(
+  a int primary key
+) engine=ndbcluster;
+
+insert into t1 values
+(00),(01),(02),(03),(04),(05),(06),(07),(08),(09),
+(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
+(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
+(30),(31),(32),(33),(34),(35),(36),(37),(38),(39),
+(40),(41),(42),(43),(44),(45),(46),(47),(48),(49),
+(50),(51),(52),(53),(54),(55),(56),(57),(58),(59),
+(60),(61),(62),(63),(64),(65),(66),(67),(68),(69),
+(70),(71),(72),(73),(74),(75),(76),(77),(78),(79),
+(80),(81),(82),(83),(84),(85),(86),(87),(88),(89),
+(90),(91),(92),(93),(94),(95),(96),(97),(98),(99);
+
+--echo
+--echo # expected result 0 roundtrips - read stats from share
+--source suite/ndb/include/ndb_init_execute_count.inc
+explain extended select * from t1 where a < 100;
+--source suite/ndb/include/ndb_execute_count.inc
+
+insert into t1 select a+100 from t1;
+
+--echo
+--echo # expected result 0 roundtrips - read stats from share
+--source suite/ndb/include/ndb_init_execute_count.inc
+explain extended select * from t1 where a < 100;
+--source suite/ndb/include/ndb_execute_count.inc
+
+delete from t1 where a >= 100;
+
+--echo
+--echo # expected result 0 roundtrips - read stats from share
+--source suite/ndb/include/ndb_init_execute_count.inc
+explain extended select * from t1 where a < 100;
+--source suite/ndb/include/ndb_execute_count.inc
+
+begin;
+insert into t1 select a+100 from t1;
+commit;
+
+--echo
+--echo # expected result 0 roundtrips - read stats from share
+--source suite/ndb/include/ndb_init_execute_count.inc
+explain extended select * from t1 where a < 100;
+--source suite/ndb/include/ndb_execute_count.inc
+
+begin;
+delete from t1 where a >= 100;
+commit;
+
+--echo
+--echo # expected result 0 roundtrips - read stats from share
+--source suite/ndb/include/ndb_init_execute_count.inc
+explain extended select * from t1 where a < 100;
+--source suite/ndb/include/ndb_execute_count.inc
+
+begin;
+insert into t1 select a+100 from t1;
+rollback;
+
+--echo
+--echo # expected result 0 roundtrips - read stats from share
+--source suite/ndb/include/ndb_init_execute_count.inc
+explain extended select * from t1 where a < 100;
+--source suite/ndb/include/ndb_execute_count.inc
+
+begin;
+delete from t1 where a <= 100;
+rollback;
+
+--echo
+--echo # expected result 0 roundtrips - read stats from share
+--source suite/ndb/include/ndb_init_execute_count.inc
+explain extended select * from t1 where a < 100;
+--source suite/ndb/include/ndb_execute_count.inc
+
+--error ER_DUP_KEY
+insert into t1 select a from t1;
+
+--echo
+--echo # expected result 0 roundtrips - read stats from share
+--source suite/ndb/include/ndb_init_execute_count.inc
+explain extended select * from t1 where a < 100;
+--source suite/ndb/include/ndb_execute_count.inc
+
+begin;
+--error ER_DUP_KEY
+insert into t1 select a from t1;
+
+--echo
+--echo # expected result 0 roundtrips - read stats from share
+--source suite/ndb/include/ndb_init_execute_count.inc
+explain extended select * from t1 where a < 100;
+--source suite/ndb/include/ndb_execute_count.inc
+
+drop table t1;

=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc	2011-06-22 08:36:40 +0000
+++ b/sql/ha_ndbcluster.cc	2011-06-23 13:43:00 +0000
@@ -265,9 +265,7 @@ static MYSQL_THDVAR_UINT(
 */
 bool ndb_index_stat_get_enable(THD *thd)
 {
-  mysql_mutex_lock(&LOCK_global_system_variables);
   const bool value = THDVAR(thd, index_stat_enable);
-  mysql_mutex_unlock(&LOCK_global_system_variables);
   return value;
 }
 
@@ -407,6 +405,9 @@ HASH ndbcluster_open_tables;
 static uchar *ndbcluster_get_key(NDB_SHARE *share, size_t *length,
                                 my_bool not_used __attribute__((unused)));
 
+static void modify_shared_stats(NDB_SHARE *share,
+                                Ndb_local_table_statistics *local_stat);
+
 static int ndb_get_table_statistics(THD *thd, ha_ndbcluster*, bool, Ndb*,
                                     const NdbRecord *, struct Ndb_statistics *,
                                     bool have_lock= FALSE,
@@ -6061,27 +6062,50 @@ int ha_ndbcluster::info(uint flag)
     if (!thd)
       thd= current_thd;
     DBUG_PRINT("info", ("HA_STATUS_VARIABLE"));
-    if ((flag & HA_STATUS_NO_LOCK) &&
-        !THDVAR(thd, use_exact_count))
-    {
-      if (thd->lex->sql_command != SQLCOM_SHOW_TABLE_STATUS &&
-          thd->lex->sql_command != SQLCOM_SHOW_KEYS)
-      {
-        /*
-          just use whatever stats we have however,
-          optimizer behaves strangely if we return few rows
-        */
-        if (stats.records < 2)
-          stats.records= 2;
-        break;
-      }
-    }
+
     if (!m_table_info)
     {
       if ((my_errno= check_ndb_connection(thd)))
         DBUG_RETURN(my_errno);
     }
-    result= update_stats(thd, 1);
+
+    /*
+      May need to update local copy of statistics in
+      'm_table_info', either directly from datanodes,
+      or from shared (mutex protected) cached copy, if:
+       1) 'use_exact_count' has been set (by config or user).
+       2) HA_STATUS_NO_LOCK -> read from shared cached copy.
+       3) Local copy is invalid.
+    */
+    bool exact_count= THDVAR(thd, use_exact_count);
+    if (exact_count                 ||         // 1)
+        !(flag & HA_STATUS_NO_LOCK) ||         // 2)
+        m_table_info == NULL        ||         // 3)
+        m_table_info->records == ~(ha_rows)0)  // 3)
+    {
+      result= update_stats(thd, (exact_count || !(flag & HA_STATUS_NO_LOCK)));
+      if (result)
+        DBUG_RETURN(result);
+    }
+    /* Read from local statistics, fast and fuzzy, wo/ locks */
+    else
+    {
+      DBUG_ASSERT(m_table_info->records != ~(ha_rows)0);
+      stats.records= m_table_info->records +
+                     m_table_info->no_uncommitted_rows_count;
+    }
+
+    if (thd->lex->sql_command != SQLCOM_SHOW_TABLE_STATUS &&
+        thd->lex->sql_command != SQLCOM_SHOW_KEYS)
+    {
+      /*
+        just use whatever stats we have. However,
+        optimizer interprets the values 0 and 1 as EXACT:
+          -> < 2 should not be returned.
+      */
+      if (stats.records < 2)
+        stats.records= 2;
+    }
     break;
   }
   /* RPK moved to variable part */
@@ -6643,7 +6667,18 @@ int ha_ndbcluster::start_statement(THD *
       there is more than one handler involved, execute deferal
       not possible
     */
+    ha_ndbcluster* handler = thd_ndb->m_handler;
     thd_ndb->m_handler= NULL;
+    if (handler != NULL)
+    {
+      /**
+       * If we initially belived that this could be run
+       *  using execute deferal...but changed out mind
+       *  add handler to thd_ndb->open_tables like it would
+       *  have done "normally"
+       */
+      add_handler_to_open_tables(thd, thd_ndb, handler);
+    }
   }
   if (!trans && table_count == 0)
   {
@@ -6689,6 +6724,57 @@ int ha_ndbcluster::start_statement(THD *
   DBUG_RETURN(0);
 }
 
+int
+ha_ndbcluster::add_handler_to_open_tables(THD *thd,
+                                          Thd_ndb *thd_ndb,
+                                          ha_ndbcluster* handler)
+{
+  DBUG_ENTER("ha_ndbcluster::add_handler_to_open_tables");
+  DBUG_PRINT("info", ("Adding %s", handler->m_share->key));
+
+  /**
+   * thd_ndb->open_tables is only used iff thd_ndb->m_handler is not
+   */
+  DBUG_ASSERT(thd_ndb->m_handler == NULL);
+  const void *key= handler->m_share;
+  HASH_SEARCH_STATE state;
+  THD_NDB_SHARE *thd_ndb_share=
+    (THD_NDB_SHARE*)my_hash_first(&thd_ndb->open_tables,
+                                  (const uchar *)&key, sizeof(key),
+                                  &state);
+  while (thd_ndb_share && thd_ndb_share->key != key)
+  {
+    thd_ndb_share=
+      (THD_NDB_SHARE*)my_hash_next(&thd_ndb->open_tables,
+                                   (const uchar *)&key, sizeof(key),
+                                   &state);
+  }
+  if (thd_ndb_share == 0)
+  {
+    thd_ndb_share= (THD_NDB_SHARE *) alloc_root(&thd->transaction.mem_root,
+                                                sizeof(THD_NDB_SHARE));
+    if (!thd_ndb_share)
+    {
+      mem_alloc_error(sizeof(THD_NDB_SHARE));
+      DBUG_RETURN(1);
+    }
+    thd_ndb_share->key= key;
+    thd_ndb_share->stat.last_count= thd_ndb->count;
+    thd_ndb_share->stat.no_uncommitted_rows_count= 0;
+    thd_ndb_share->stat.records= ~(ha_rows)0;
+    my_hash_insert(&thd_ndb->open_tables, (uchar *)thd_ndb_share);
+  }
+  else if (thd_ndb_share->stat.last_count != thd_ndb->count)
+  {
+    thd_ndb_share->stat.last_count= thd_ndb->count;
+    thd_ndb_share->stat.no_uncommitted_rows_count= 0;
+    thd_ndb_share->stat.records= ~(ha_rows)0;
+  }
+
+  handler->m_table_info= &thd_ndb_share->stat;
+  DBUG_RETURN(0);
+}
+
 int ha_ndbcluster::init_handler_for_statement(THD *thd)
 {
   /*
@@ -6722,45 +6808,11 @@ int ha_ndbcluster::init_handler_for_stat
   }
 #endif
 
-  if (thd_options(thd) & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+  int ret = 0;
+  if (thd_ndb->m_handler == 0)
   {
-    const void *key= m_table;
-    HASH_SEARCH_STATE state;
-    THD_NDB_SHARE *thd_ndb_share=
-      (THD_NDB_SHARE*)my_hash_first(&thd_ndb->open_tables,
-                                    (const uchar *)&key, sizeof(key),
-                                    &state);
-    while (thd_ndb_share && thd_ndb_share->key != key)
-    {
-      thd_ndb_share=
-        (THD_NDB_SHARE*)my_hash_next(&thd_ndb->open_tables,
-                                     (const uchar *)&key, sizeof(key),
-                                     &state);
-    }
-    if (thd_ndb_share == 0)
-    {
-      thd_ndb_share= (THD_NDB_SHARE *) alloc_root(&thd->transaction.mem_root,
-                                                  sizeof(THD_NDB_SHARE));
-      if (!thd_ndb_share)
-      {
-        mem_alloc_error(sizeof(THD_NDB_SHARE));
-        DBUG_RETURN(1);
-      }
-      thd_ndb_share->key= key;
-      thd_ndb_share->stat.last_count= thd_ndb->count;
-      thd_ndb_share->stat.no_uncommitted_rows_count= 0;
-      thd_ndb_share->stat.records= ~(ha_rows)0;
-      my_hash_insert(&thd_ndb->open_tables, (uchar *)thd_ndb_share);
-    }
-    else if (thd_ndb_share->stat.last_count != thd_ndb->count)
-    {
-      thd_ndb_share->stat.last_count= thd_ndb->count;
-      thd_ndb_share->stat.no_uncommitted_rows_count= 0;
-      thd_ndb_share->stat.records= ~(ha_rows)0;
-    }
-    DBUG_PRINT("exit", ("thd_ndb_share: 0x%lx  key: 0x%lx",
-                        (long) thd_ndb_share, (long) key));
-    m_table_info= &thd_ndb_share->stat;
+    DBUG_ASSERT(m_share);
+    ret = add_handler_to_open_tables(thd, thd_ndb, this);
   }
   else
   {
@@ -6770,7 +6822,7 @@ int ha_ndbcluster::init_handler_for_stat
     stat.records= ~(ha_rows)0;
     m_table_info= &stat;
   }
-  DBUG_RETURN(0);
+  DBUG_RETURN(ret);
 }
 
 int ha_ndbcluster::external_lock(THD *thd, int lock_type)
@@ -7142,6 +7194,25 @@ int ndbcluster_commit(handlerton *hton,
     if (res != -1)
       ndbcluster_print_error(res, error_op);
   }
+  else
+  {
+    /* Update shared statistics for tables inserted into / deleted from*/
+    if (thd_ndb->m_handler &&      // Autocommit Txn
+        thd_ndb->m_handler->m_share &&
+        thd_ndb->m_handler->m_table_info)
+    {
+      modify_shared_stats(thd_ndb->m_handler->m_share, thd_ndb->m_handler->m_table_info);
+    }
+
+    /* Manual commit: Update all affected NDB_SHAREs found in 'open_tables' */
+    for (uint i= 0; i<thd_ndb->open_tables.records; i++)
+    {
+      THD_NDB_SHARE *thd_share=
+        (THD_NDB_SHARE*)my_hash_element(&thd_ndb->open_tables, i);
+      modify_shared_stats((NDB_SHARE*)thd_share->key, &thd_share->stat);
+    }
+  }
+
   ndb->closeTransaction(trans);
   thd_ndb->trans= NULL;
   thd_ndb->m_handler= NULL;
@@ -12315,8 +12386,22 @@ int ha_ndbcluster::update_stats(THD *thd
   struct Ndb_statistics stat;
   Thd_ndb *thd_ndb= get_thd_ndb(thd);
   DBUG_ENTER("ha_ndbcluster::update_stats");
-  if (do_read_stat || !m_share)
+  do
   {
+    if (m_share && !do_read_stat)
+    {
+      pthread_mutex_lock(&m_share->mutex);
+      stat= m_share->stat;
+      pthread_mutex_unlock(&m_share->mutex);
+
+      DBUG_ASSERT(stat.row_count != ~(ha_rows)0); // should never be invalid
+
+      /* Accept shared cached statistics if row_count is valid. */
+      if (stat.row_count != ~(ha_rows)0)
+        break;
+    }
+
+    /* Request statistics from datanodes */
     Ndb *ndb= thd_ndb->ndb;
     if (ndb->setDatabaseName(m_dbname))
     {
@@ -12328,25 +12413,25 @@ int ha_ndbcluster::update_stats(THD *thd
     {
       DBUG_RETURN(err);
     }
+
+    /* Update shared statistics with fresh data */
     if (m_share)
     {
       pthread_mutex_lock(&m_share->mutex);
       m_share->stat= stat;
       pthread_mutex_unlock(&m_share->mutex);
     }
+    break;
   }
-  else
+  while(0);
+
+  int no_uncommitted_rows_count= 0;
+  if (m_table_info && !thd_ndb->m_error)
   {
-    pthread_mutex_lock(&m_share->mutex);
-    stat= m_share->stat;
-    pthread_mutex_unlock(&m_share->mutex);
+    m_table_info->records= stat.row_count;
+    m_table_info->last_count= thd_ndb->count;
+    no_uncommitted_rows_count= m_table_info->no_uncommitted_rows_count;
   }
-  struct Ndb_local_table_statistics *local_info= m_table_info;
-  int no_uncommitted_rows_count;
-  if (thd_ndb->m_error || !local_info)
-    no_uncommitted_rows_count= 0;
-  else
-    no_uncommitted_rows_count= local_info->no_uncommitted_rows_count;
   stats.mean_rec_length= stat.row_size;
   stats.data_file_length= stat.fragment_memory;
   stats.records= stat.row_count + no_uncommitted_rows_count;
@@ -12366,6 +12451,35 @@ int ha_ndbcluster::update_stats(THD *thd
   DBUG_RETURN(0);
 }
 
+/**
+  Update 'row_count' in shared table statistcs if any rows where
+  inserted/deleted by the local transaction related to specified
+ 'local_stat'.
+  Should be called when transaction has succesfully commited its changes.
+*/
+static
+void modify_shared_stats(NDB_SHARE *share,
+                         Ndb_local_table_statistics *local_stat)
+{
+  if (local_stat->no_uncommitted_rows_count)
+  {
+    pthread_mutex_lock(&share->mutex);
+    DBUG_ASSERT(share->stat.row_count != ~(ha_rows)0);// should never be invalid
+    if (share->stat.row_count != ~(ha_rows)0)
+    {
+      DBUG_PRINT("info", ("Update row_count for %s, row_count: %lu, with:%d",
+                          share->table_name, (ulong) share->stat.row_count,
+                          local_stat->no_uncommitted_rows_count));
+      share->stat.row_count=
+        ((Int64)share->stat.row_count+local_stat->no_uncommitted_rows_count > 0)
+         ? share->stat.row_count+local_stat->no_uncommitted_rows_count
+         : 0;
+    }
+    pthread_mutex_unlock(&share->mutex);
+    local_stat->no_uncommitted_rows_count= 0;
+  }
+}
+
 /* If part_id contains a legal partition id, ndbstat returns the
    partition-statistics pertaining to that partition only.
    Otherwise, it returns the table-statistics,

=== modified file 'sql/ha_ndbcluster.h'
--- a/sql/ha_ndbcluster.h	2011-06-22 08:36:40 +0000
+++ b/sql/ha_ndbcluster.h	2011-06-23 13:43:00 +0000
@@ -985,6 +985,7 @@ private:
 
   int update_stats(THD *thd, bool do_read_stat, bool have_lock= FALSE,
                    uint part_id= ~(uint)0);
+  int add_handler_to_open_tables(THD*, Thd_ndb*, ha_ndbcluster* handler);
 };
 
 int ndbcluster_discover(THD* thd, const char* dbname, const char* name,

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-5.1-telco-7.1 branch (jonas:4258 to 4259) jonas oreland23 Jun