summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnnamalai Gurusami <annamalai.gurusami@oracle.com>2012-05-10 10:18:31 +0530
committerAnnamalai Gurusami <annamalai.gurusami@oracle.com>2012-05-10 10:18:31 +0530
commit391ea219c21a66e24ea9985ca2581f75bbd7c8f5 (patch)
tree580214744faf4f74ab2647bd5e28f971bba9107f
parent074ce71e9022246fa466bbe28f6d15941a3d4cf3 (diff)
downloadmariadb-git-391ea219c21a66e24ea9985ca2581f75bbd7c8f5.tar.gz
Bug #14007649 65111: INNODB SOMETIMES FAILS TO UPDATE ROWS INSERTED
BY A CONCURRENT TRANSACTIO The member function QUICK_RANGE_SELECT::init_ror_merged_scan() performs a table handler clone. Innodb does not provide a clone operation. The ha_innobase::clone() is not there. The handler::clone() does not take care of the ha_innobase->prebuilt->select_lock_type. Because of this what happens is that for one index we do a locking read, and for the other index we were doing a non-locking (consistent) read. The patch introduces ha_innobase::clone() member function. It is implemented similar to ha_myisam::clone(). It calls the base class handler::clone() and then does any additional operation required. I am setting the ha_innobase->prebuilt->select_lock_type correctly. rb://1060 approved by Marko
-rw-r--r--mysql-test/suite/innodb/r/innodb_bug14007649.result56
-rw-r--r--mysql-test/suite/innodb/t/innodb_bug14007649.test58
-rw-r--r--mysql-test/suite/innodb_plugin/r/innodb_bug14007649.result56
-rw-r--r--mysql-test/suite/innodb_plugin/t/innodb_bug14007649.test58
-rw-r--r--storage/innobase/btr/btr0cur.c2
-rw-r--r--storage/innobase/handler/ha_innodb.cc24
-rw-r--r--storage/innobase/handler/ha_innodb.h1
-rw-r--r--storage/innodb_plugin/btr/btr0cur.c2
-rw-r--r--storage/innodb_plugin/handler/ha_innodb.cc25
-rw-r--r--storage/innodb_plugin/handler/ha_innodb.h1
10 files changed, 283 insertions, 0 deletions
diff --git a/mysql-test/suite/innodb/r/innodb_bug14007649.result b/mysql-test/suite/innodb/r/innodb_bug14007649.result
new file mode 100644
index 00000000000..1f802dcd146
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb_bug14007649.result
@@ -0,0 +1,56 @@
+create table t1 (
+rowid int,
+f1 int,
+f2 int,
+key i1 (f1, f2),
+key i2 (f2)) engine=innodb;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `rowid` int(11) DEFAULT NULL,
+ `f1` int(11) DEFAULT NULL,
+ `f2` int(11) DEFAULT NULL,
+ KEY `i1` (`f1`,`f2`),
+ KEY `i2` (`f2`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+insert into `t1` (rowid, f1, f2) values (1, 1, 10), (2, 1, NULL);
+start transaction with consistent snapshot;
+start transaction;
+update t1 set f2 = 4 where f1 = 1 and f2 is null;
+(b) Number of rows updated:
+select row_count();
+row_count()
+1
+insert into t1 values (3, 1, null);
+(b) After update and insert query.
+select rowid, f1, f2 from t1;
+rowid f1 f2
+1 1 10
+2 1 4
+3 1 NULL
+commit;
+(a) Before the update statement is executed.
+select rowid, f1, f2 from t1;
+rowid f1 f2
+1 1 10
+2 1 NULL
+SET SESSION debug="+d,bug14007649";
+update t1 set f2 = 6 where f1 = 1 and f2 is null;
+(a) Number of rows updated:
+select row_count();
+row_count()
+1
+(a) After the update statement is executed.
+select rowid, f1, f2 from t1;
+rowid f1 f2
+1 1 10
+2 1 NULL
+3 1 6
+commit;
+"The trx with consistent snapshot ended."
+select rowid, f1, f2 from t1;
+rowid f1 f2
+1 1 10
+2 1 4
+3 1 6
+drop table t1;
diff --git a/mysql-test/suite/innodb/t/innodb_bug14007649.test b/mysql-test/suite/innodb/t/innodb_bug14007649.test
new file mode 100644
index 00000000000..2832bd41f3c
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb_bug14007649.test
@@ -0,0 +1,58 @@
+--source include/have_innodb.inc
+--source include/have_debug.inc
+
+create table t1 (
+ rowid int,
+ f1 int,
+ f2 int,
+ key i1 (f1, f2),
+ key i2 (f2)) engine=innodb;
+
+show create table t1;
+insert into `t1` (rowid, f1, f2) values (1, 1, 10), (2, 1, NULL);
+
+connect (a,localhost,root,,);
+connect (b,localhost,root,,);
+
+connection a;
+start transaction with consistent snapshot;
+
+connection b;
+start transaction;
+update t1 set f2 = 4 where f1 = 1 and f2 is null;
+
+-- echo (b) Number of rows updated:
+select row_count();
+
+insert into t1 values (3, 1, null);
+
+-- echo (b) After update and insert query.
+select rowid, f1, f2 from t1;
+
+commit;
+
+connection a;
+
+-- echo (a) Before the update statement is executed.
+select rowid, f1, f2 from t1;
+
+SET SESSION debug="+d,bug14007649";
+update t1 set f2 = 6 where f1 = 1 and f2 is null;
+
+-- echo (a) Number of rows updated:
+select row_count();
+
+-- echo (a) After the update statement is executed.
+select rowid, f1, f2 from t1;
+
+commit;
+
+--echo "The trx with consistent snapshot ended."
+
+select rowid, f1, f2 from t1;
+
+connection default;
+disconnect a;
+disconnect b;
+
+drop table t1;
diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug14007649.result b/mysql-test/suite/innodb_plugin/r/innodb_bug14007649.result
new file mode 100644
index 00000000000..1f802dcd146
--- /dev/null
+++ b/mysql-test/suite/innodb_plugin/r/innodb_bug14007649.result
@@ -0,0 +1,56 @@
+create table t1 (
+rowid int,
+f1 int,
+f2 int,
+key i1 (f1, f2),
+key i2 (f2)) engine=innodb;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `rowid` int(11) DEFAULT NULL,
+ `f1` int(11) DEFAULT NULL,
+ `f2` int(11) DEFAULT NULL,
+ KEY `i1` (`f1`,`f2`),
+ KEY `i2` (`f2`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+insert into `t1` (rowid, f1, f2) values (1, 1, 10), (2, 1, NULL);
+start transaction with consistent snapshot;
+start transaction;
+update t1 set f2 = 4 where f1 = 1 and f2 is null;
+(b) Number of rows updated:
+select row_count();
+row_count()
+1
+insert into t1 values (3, 1, null);
+(b) After update and insert query.
+select rowid, f1, f2 from t1;
+rowid f1 f2
+1 1 10
+2 1 4
+3 1 NULL
+commit;
+(a) Before the update statement is executed.
+select rowid, f1, f2 from t1;
+rowid f1 f2
+1 1 10
+2 1 NULL
+SET SESSION debug="+d,bug14007649";
+update t1 set f2 = 6 where f1 = 1 and f2 is null;
+(a) Number of rows updated:
+select row_count();
+row_count()
+1
+(a) After the update statement is executed.
+select rowid, f1, f2 from t1;
+rowid f1 f2
+1 1 10
+2 1 NULL
+3 1 6
+commit;
+"The trx with consistent snapshot ended."
+select rowid, f1, f2 from t1;
+rowid f1 f2
+1 1 10
+2 1 4
+3 1 6
+drop table t1;
diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug14007649.test b/mysql-test/suite/innodb_plugin/t/innodb_bug14007649.test
new file mode 100644
index 00000000000..e1d27ecd742
--- /dev/null
+++ b/mysql-test/suite/innodb_plugin/t/innodb_bug14007649.test
@@ -0,0 +1,58 @@
+--source include/have_innodb_plugin.inc
+--source include/have_debug.inc
+
+create table t1 (
+ rowid int,
+ f1 int,
+ f2 int,
+ key i1 (f1, f2),
+ key i2 (f2)) engine=innodb;
+
+show create table t1;
+insert into `t1` (rowid, f1, f2) values (1, 1, 10), (2, 1, NULL);
+
+connect (a,localhost,root,,);
+connect (b,localhost,root,,);
+
+connection a;
+start transaction with consistent snapshot;
+
+connection b;
+start transaction;
+update t1 set f2 = 4 where f1 = 1 and f2 is null;
+
+-- echo (b) Number of rows updated:
+select row_count();
+
+insert into t1 values (3, 1, null);
+
+-- echo (b) After update and insert query.
+select rowid, f1, f2 from t1;
+
+commit;
+
+connection a;
+
+-- echo (a) Before the update statement is executed.
+select rowid, f1, f2 from t1;
+
+SET SESSION debug="+d,bug14007649";
+update t1 set f2 = 6 where f1 = 1 and f2 is null;
+
+-- echo (a) Number of rows updated:
+select row_count();
+
+-- echo (a) After the update statement is executed.
+select rowid, f1, f2 from t1;
+
+commit;
+
+--echo "The trx with consistent snapshot ended."
+
+select rowid, f1, f2 from t1;
+
+connection default;
+disconnect a;
+disconnect b;
+
+drop table t1;
diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c
index c09d6408fa0..4678ea8cd22 100644
--- a/storage/innobase/btr/btr0cur.c
+++ b/storage/innobase/btr/btr0cur.c
@@ -2792,6 +2792,8 @@ btr_estimate_n_rows_in_range(
n_rows = n_rows * 2;
}
+ DBUG_EXECUTE_IF("bug14007649", return(n_rows););
+
/* Do not estimate the number of rows in the range
to over 1 / 2 of the estimated rows in the whole
table */
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 6576016501f..8ed082037f0 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -3180,6 +3180,30 @@ table_opened:
DBUG_RETURN(0);
}
+handler*
+ha_innobase::clone(
+/*===============*/
+ const char* name, /*!< in: table name */
+ MEM_ROOT* mem_root) /*!< in: memory context */
+{
+ ha_innobase* new_handler;
+
+ DBUG_ENTER("ha_innobase::clone");
+
+ new_handler = static_cast<ha_innobase*>(handler::clone(name,
+ mem_root));
+ if (new_handler) {
+ DBUG_ASSERT(new_handler->prebuilt != NULL);
+ DBUG_ASSERT(new_handler->user_thd == user_thd);
+ DBUG_ASSERT(new_handler->prebuilt->trx == prebuilt->trx);
+
+ new_handler->prebuilt->select_lock_type
+ = prebuilt->select_lock_type;
+ }
+
+ DBUG_RETURN(new_handler);
+}
+
uint
ha_innobase::max_supported_key_part_length() const
{
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
index 8b91f7d4c51..93229ad9185 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -117,6 +117,7 @@ class ha_innobase: public handler
const key_map *keys_to_use_for_scanning() { return &key_map_full; }
int open(const char *name, int mode, uint test_if_locked);
+ handler* clone(const char *name, MEM_ROOT *mem_root);
int close(void);
double scan_time();
double read_time(uint index, uint ranges, ha_rows rows);
diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c
index b67da53ec8a..223b976dea7 100644
--- a/storage/innodb_plugin/btr/btr0cur.c
+++ b/storage/innodb_plugin/btr/btr0cur.c
@@ -3194,6 +3194,8 @@ btr_estimate_n_rows_in_range(
n_rows = n_rows * 2;
}
+ DBUG_EXECUTE_IF("bug14007649", return(n_rows););
+
/* Do not estimate the number of rows in the range
to over 1 / 2 of the estimated rows in the whole
table */
diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc
index ca6788999ae..2207f9d009d 100644
--- a/storage/innodb_plugin/handler/ha_innodb.cc
+++ b/storage/innodb_plugin/handler/ha_innodb.cc
@@ -3890,6 +3890,31 @@ table_opened:
}
UNIV_INTERN
+handler*
+ha_innobase::clone(
+/*===============*/
+ const char* name, /*!< in: table name */
+ MEM_ROOT* mem_root) /*!< in: memory context */
+{
+ ha_innobase* new_handler;
+
+ DBUG_ENTER("ha_innobase::clone");
+
+ new_handler = static_cast<ha_innobase*>(handler::clone(name,
+ mem_root));
+ if (new_handler) {
+ DBUG_ASSERT(new_handler->prebuilt != NULL);
+ DBUG_ASSERT(new_handler->user_thd == user_thd);
+ DBUG_ASSERT(new_handler->prebuilt->trx == prebuilt->trx);
+
+ new_handler->prebuilt->select_lock_type
+ = prebuilt->select_lock_type;
+ }
+
+ DBUG_RETURN(new_handler);
+}
+
+UNIV_INTERN
uint
ha_innobase::max_supported_key_part_length() const
{
diff --git a/storage/innodb_plugin/handler/ha_innodb.h b/storage/innodb_plugin/handler/ha_innodb.h
index f7a5456b1a7..15cc4a77b6f 100644
--- a/storage/innodb_plugin/handler/ha_innodb.h
+++ b/storage/innodb_plugin/handler/ha_innodb.h
@@ -132,6 +132,7 @@ class ha_innobase: public handler
const key_map* keys_to_use_for_scanning();
int open(const char *name, int mode, uint test_if_locked);
+ handler* clone(const char *name, MEM_ROOT *mem_root);
int close(void);
double scan_time();
double read_time(uint index, uint ranges, ha_rows rows);