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
This commit is contained in:
parent
074ce71e90
commit
391ea219c2
56
mysql-test/suite/innodb/r/innodb_bug14007649.result
Normal file
56
mysql-test/suite/innodb/r/innodb_bug14007649.result
Normal file
@ -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;
|
58
mysql-test/suite/innodb/t/innodb_bug14007649.test
Normal file
58
mysql-test/suite/innodb/t/innodb_bug14007649.test
Normal file
@ -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;
|
56
mysql-test/suite/innodb_plugin/r/innodb_bug14007649.result
Normal file
56
mysql-test/suite/innodb_plugin/r/innodb_bug14007649.result
Normal file
@ -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;
|
58
mysql-test/suite/innodb_plugin/t/innodb_bug14007649.test
Normal file
58
mysql-test/suite/innodb_plugin/t/innodb_bug14007649.test
Normal file
@ -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;
|
@ -2792,6 +2792,8 @@ btr_estimate_n_rows_in_range(
|
|||||||
n_rows = n_rows * 2;
|
n_rows = n_rows * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DBUG_EXECUTE_IF("bug14007649", return(n_rows););
|
||||||
|
|
||||||
/* Do not estimate the number of rows in the range
|
/* Do not estimate the number of rows in the range
|
||||||
to over 1 / 2 of the estimated rows in the whole
|
to over 1 / 2 of the estimated rows in the whole
|
||||||
table */
|
table */
|
||||||
|
@ -3180,6 +3180,30 @@ table_opened:
|
|||||||
DBUG_RETURN(0);
|
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
|
uint
|
||||||
ha_innobase::max_supported_key_part_length() const
|
ha_innobase::max_supported_key_part_length() const
|
||||||
{
|
{
|
||||||
|
@ -117,6 +117,7 @@ class ha_innobase: public handler
|
|||||||
const key_map *keys_to_use_for_scanning() { return &key_map_full; }
|
const key_map *keys_to_use_for_scanning() { return &key_map_full; }
|
||||||
|
|
||||||
int open(const char *name, int mode, uint test_if_locked);
|
int open(const char *name, int mode, uint test_if_locked);
|
||||||
|
handler* clone(const char *name, MEM_ROOT *mem_root);
|
||||||
int close(void);
|
int close(void);
|
||||||
double scan_time();
|
double scan_time();
|
||||||
double read_time(uint index, uint ranges, ha_rows rows);
|
double read_time(uint index, uint ranges, ha_rows rows);
|
||||||
|
@ -3194,6 +3194,8 @@ btr_estimate_n_rows_in_range(
|
|||||||
n_rows = n_rows * 2;
|
n_rows = n_rows * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DBUG_EXECUTE_IF("bug14007649", return(n_rows););
|
||||||
|
|
||||||
/* Do not estimate the number of rows in the range
|
/* Do not estimate the number of rows in the range
|
||||||
to over 1 / 2 of the estimated rows in the whole
|
to over 1 / 2 of the estimated rows in the whole
|
||||||
table */
|
table */
|
||||||
|
@ -3889,6 +3889,31 @@ table_opened:
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
UNIV_INTERN
|
||||||
uint
|
uint
|
||||||
ha_innobase::max_supported_key_part_length() const
|
ha_innobase::max_supported_key_part_length() const
|
||||||
|
@ -132,6 +132,7 @@ class ha_innobase: public handler
|
|||||||
const key_map* keys_to_use_for_scanning();
|
const key_map* keys_to_use_for_scanning();
|
||||||
|
|
||||||
int open(const char *name, int mode, uint test_if_locked);
|
int open(const char *name, int mode, uint test_if_locked);
|
||||||
|
handler* clone(const char *name, MEM_ROOT *mem_root);
|
||||||
int close(void);
|
int close(void);
|
||||||
double scan_time();
|
double scan_time();
|
||||||
double read_time(uint index, uint ranges, ha_rows rows);
|
double read_time(uint index, uint ranges, ha_rows rows);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user