MDEV-17614: After-merge fix
MDEV-17614 flags INSERT…ON DUPLICATE KEY UPDATE unsafe for statement-based replication when there are multiple unique indexes. This correctly fixes something whose attempted fix in MySQL 5.7 in mysql/mysql-server@c93b0d9a97 caused lock conflicts. That change was reverted in MySQL 5.7.26 in mysql/mysql-server@066b6fdd43 (with a substantial amount of other changes). In MDEV-17073 we already disabled the unfortunate MySQL change when statement-based replication was not being used. Now, thanks to MDEV-17614, we can actually remove the change altogether. This reverts commit 8a346f31b913daa011085afec2b2d38450c73e00 (MDEV-17073) and mysql/mysql-server@c93b0d9a97 while keeping the test cases.
This commit is contained in:
parent
be33124c9d
commit
609ea2f37b
@ -1,51 +0,0 @@
|
||||
--- auto_increment_dup.result
|
||||
+++ auto_increment_dup,skip-log-bin.reject
|
||||
@@ -89,13 +89,14 @@
|
||||
SET DEBUG_SYNC='execute_command_after_close_tables SIGNAL continue';
|
||||
affected rows: 0
|
||||
INSERT INTO t1(k) VALUES (2), (4), (5) ON DUPLICATE KEY UPDATE c='2';
|
||||
-ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
+affected rows: 3
|
||||
+info: Records: 3 Duplicates: 0 Warnings: 0
|
||||
connection con1;
|
||||
#
|
||||
# 2 duplicates
|
||||
#
|
||||
-affected rows: 3
|
||||
-info: Records: 3 Duplicates: 0 Warnings: 0
|
||||
+affected rows: 4
|
||||
+info: Records: 3 Duplicates: 1 Warnings: 0
|
||||
connection default;
|
||||
#
|
||||
# 3 rows
|
||||
@@ -103,19 +104,21 @@
|
||||
SELECT * FROM t1 order by k;
|
||||
id k c
|
||||
1 1 NULL
|
||||
-2 2 NULL
|
||||
-3 3 NULL
|
||||
-affected rows: 3
|
||||
+4 2 1
|
||||
+2 3 NULL
|
||||
+5 4 NULL
|
||||
+6 5 NULL
|
||||
+affected rows: 5
|
||||
INSERT INTO t1(k) VALUES (2), (4), (5) ON DUPLICATE KEY UPDATE c='2';
|
||||
-affected rows: 4
|
||||
-info: Records: 3 Duplicates: 1 Warnings: 0
|
||||
+affected rows: 6
|
||||
+info: Records: 3 Duplicates: 3 Warnings: 0
|
||||
SELECT * FROM t1 order by k;
|
||||
id k c
|
||||
1 1 NULL
|
||||
-2 2 2
|
||||
-3 3 NULL
|
||||
-7 4 NULL
|
||||
-8 5 NULL
|
||||
+4 2 2
|
||||
+2 3 NULL
|
||||
+5 4 2
|
||||
+6 5 2
|
||||
affected rows: 5
|
||||
disconnect con1;
|
||||
disconnect con2;
|
@ -89,13 +89,14 @@ affected rows: 0
|
||||
SET DEBUG_SYNC='execute_command_after_close_tables SIGNAL continue';
|
||||
affected rows: 0
|
||||
INSERT INTO t1(k) VALUES (2), (4), (5) ON DUPLICATE KEY UPDATE c='2';
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
affected rows: 3
|
||||
info: Records: 3 Duplicates: 0 Warnings: 0
|
||||
connection con1;
|
||||
#
|
||||
# 2 duplicates
|
||||
#
|
||||
affected rows: 3
|
||||
info: Records: 3 Duplicates: 0 Warnings: 0
|
||||
affected rows: 4
|
||||
info: Records: 3 Duplicates: 1 Warnings: 0
|
||||
connection default;
|
||||
#
|
||||
# 3 rows
|
||||
@ -103,19 +104,21 @@ connection default;
|
||||
SELECT * FROM t1 order by k;
|
||||
id k c
|
||||
1 1 NULL
|
||||
2 2 NULL
|
||||
3 3 NULL
|
||||
affected rows: 3
|
||||
4 2 1
|
||||
2 3 NULL
|
||||
5 4 NULL
|
||||
6 5 NULL
|
||||
affected rows: 5
|
||||
INSERT INTO t1(k) VALUES (2), (4), (5) ON DUPLICATE KEY UPDATE c='2';
|
||||
affected rows: 4
|
||||
info: Records: 3 Duplicates: 1 Warnings: 0
|
||||
affected rows: 6
|
||||
info: Records: 3 Duplicates: 3 Warnings: 0
|
||||
SELECT * FROM t1 order by k;
|
||||
id k c
|
||||
1 1 NULL
|
||||
2 2 2
|
||||
3 3 NULL
|
||||
7 4 NULL
|
||||
8 5 NULL
|
||||
4 2 2
|
||||
2 3 NULL
|
||||
5 4 2
|
||||
6 5 2
|
||||
affected rows: 5
|
||||
disconnect con1;
|
||||
disconnect con2;
|
||||
|
@ -8,8 +8,6 @@
|
||||
--source include/have_debug_sync.inc
|
||||
--source include/innodb_binlog.inc
|
||||
|
||||
let $stmt= `SELECT @@GLOBAL.log_bin`;
|
||||
|
||||
set global transaction isolation level repeatable read;
|
||||
|
||||
CREATE TABLE t1(
|
||||
@ -84,13 +82,7 @@ SET DEBUG_SYNC='ha_write_row_end SIGNAL write_row_done WAIT_FOR continue';
|
||||
--reap
|
||||
|
||||
SET DEBUG_SYNC='execute_command_after_close_tables SIGNAL continue';
|
||||
if ($stmt) {
|
||||
--error ER_LOCK_WAIT_TIMEOUT
|
||||
INSERT INTO t1(k) VALUES (2), (4), (5) ON DUPLICATE KEY UPDATE c='2';
|
||||
}
|
||||
if (!$stmt) {
|
||||
INSERT INTO t1(k) VALUES (2), (4), (5) ON DUPLICATE KEY UPDATE c='2';
|
||||
}
|
||||
|
||||
--connection con1
|
||||
--echo #
|
||||
|
@ -15,4 +15,3 @@ rpl_get_master_version_and_clock : Bug#11766137 Jan 05 2011 joro Valgrind warnin
|
||||
rpl_partition_archive : MDEV-5077 2013-09-27 svoj Cannot exchange partition with archive table
|
||||
rpl_row_binlog_max_cache_size : MDEV-11092
|
||||
rpl_row_index_choice : MDEV-11666
|
||||
rpl_mdev_17614 : MDEV-17614/MDEV-17073 Unexpected lock conflict
|
||||
|
@ -3,19 +3,24 @@ include/master-slave.inc
|
||||
call mtr.add_suppression("Unsafe statement written to the binary log using statement format");
|
||||
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY , b INT,
|
||||
UNIQUE(b), c int) engine=innodb;
|
||||
connection slave;
|
||||
connection master;
|
||||
INSERT INTO t1 VALUES (1, 1, 1);
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES (2, 1, 2) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c);
|
||||
Warnings:
|
||||
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe
|
||||
connection master1;
|
||||
INSERT INTO t1 VALUES(2, 2, 3) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c);
|
||||
Warnings:
|
||||
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe
|
||||
connection master;
|
||||
COMMIT;
|
||||
SELECT * FROM t1;
|
||||
a b c
|
||||
1 1 2
|
||||
2 2 3
|
||||
connection slave;
|
||||
include/wait_for_slave_sql_error.inc [errno=1062]
|
||||
Last_SQL_Error = 'Error 'Duplicate entry '1' for key 'b'' on query. Default database: 'test'. Query: 'INSERT INTO t1 VALUES (2, 1, 2) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c)''
|
||||
#Different value from server
|
||||
@ -26,61 +31,85 @@ a b c
|
||||
stop slave;
|
||||
include/wait_for_slave_to_stop.inc
|
||||
reset slave;
|
||||
connection master;
|
||||
reset master;
|
||||
drop table t1;
|
||||
connection slave;
|
||||
start slave;
|
||||
include/wait_for_slave_to_start.inc
|
||||
connection master;
|
||||
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY auto_increment, b INT,
|
||||
UNIQUE(b), c int) engine=innodb;
|
||||
connection slave;
|
||||
connection master;
|
||||
INSERT INTO t1 VALUES (default, 1, 1);
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES (default, 1, 2) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c);
|
||||
connection master1;
|
||||
INSERT INTO t1 VALUES(default, 2, 3) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c);
|
||||
connection master;
|
||||
COMMIT;
|
||||
SELECT * FROM t1;
|
||||
a b c
|
||||
1 1 2
|
||||
3 2 3
|
||||
connection slave;
|
||||
#same data as master
|
||||
SELECT * FROM t1;
|
||||
a b c
|
||||
1 1 2
|
||||
3 2 3
|
||||
connection master;
|
||||
drop table t1;
|
||||
connection slave;
|
||||
connection master;
|
||||
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT,
|
||||
UNIQUE(b), c int, d int ) engine=innodb;
|
||||
connection slave;
|
||||
connection master;
|
||||
INSERT INTO t1 VALUES (1, 1, 1, 1);
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES (2, NULL, 2, 2) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c);
|
||||
Warnings:
|
||||
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe
|
||||
connection master1;
|
||||
INSERT INTO t1 VALUES(3, NULL, 2, 3) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c);
|
||||
Warnings:
|
||||
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe
|
||||
connection master;
|
||||
COMMIT;
|
||||
SELECT * FROM t1;
|
||||
a b c d
|
||||
1 1 1 1
|
||||
2 NULL 2 2
|
||||
3 NULL 2 3
|
||||
connection slave;
|
||||
#same data as master
|
||||
SELECT * FROM t1;
|
||||
a b c d
|
||||
1 1 1 1
|
||||
2 NULL 2 2
|
||||
3 NULL 2 3
|
||||
connection master;
|
||||
drop table t1;
|
||||
connection slave;
|
||||
connection master;
|
||||
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY auto_increment, b INT,
|
||||
UNIQUE(b), c int) engine=innodb;
|
||||
connection slave;
|
||||
connection master;
|
||||
INSERT INTO t1 VALUES (1, 1, 1);
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES (2, 1, 2) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c);
|
||||
connection master1;
|
||||
INSERT INTO t1 VALUES(2, 2, 3) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c);
|
||||
connection master;
|
||||
COMMIT;
|
||||
SELECT * FROM t1;
|
||||
a b c
|
||||
1 1 2
|
||||
2 2 3
|
||||
connection slave;
|
||||
include/wait_for_slave_sql_error.inc [errno=1062]
|
||||
Last_SQL_Error = 'Error 'Duplicate entry '1' for key 'b'' on query. Default database: 'test'. Query: 'INSERT INTO t1 VALUES (2, 1, 2) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c)''
|
||||
#Different value from server
|
||||
@ -91,8 +120,10 @@ a b c
|
||||
stop slave;
|
||||
include/wait_for_slave_to_stop.inc
|
||||
reset slave;
|
||||
connection master;
|
||||
reset master;
|
||||
drop table t1;
|
||||
connection slave;
|
||||
start slave;
|
||||
include/wait_for_slave_to_start.inc
|
||||
include/rpl_end.inc
|
||||
|
@ -4553,12 +4553,6 @@ extern "C" int thd_rpl_is_parallel(const MYSQL_THD thd)
|
||||
return thd->rgi_slave && thd->rgi_slave->is_parallel_exec;
|
||||
}
|
||||
|
||||
extern "C" int thd_rpl_stmt_based(const MYSQL_THD thd)
|
||||
{
|
||||
return thd &&
|
||||
!thd->is_current_stmt_binlog_format_row() &&
|
||||
!thd->is_current_stmt_binlog_disabled();
|
||||
}
|
||||
|
||||
/* Returns high resolution timestamp for the start
|
||||
of the current query. */
|
||||
|
@ -121,9 +121,6 @@ thd_is_replication_slave_thread(
|
||||
/*============================*/
|
||||
THD* thd); /*!< in: thread handle */
|
||||
|
||||
/** @return whether statement-based replication is active */
|
||||
extern "C" int thd_rpl_stmt_based(const THD* thd);
|
||||
|
||||
/******************************************************************//**
|
||||
Returns true if the transaction this thread is processing has edited
|
||||
non-transactional tables. Used by the deadlock detector when deciding
|
||||
|
@ -196,10 +196,6 @@ struct ins_node_t{
|
||||
entry_list and sys fields are stored here;
|
||||
if this is NULL, entry list should be created
|
||||
and buffers for sys fields in row allocated */
|
||||
dict_index_t* duplicate;
|
||||
/* This is the first index that reported
|
||||
DB_DUPLICATE_KEY. Used in the case of REPLACE
|
||||
or INSERT ... ON DUPLICATE UPDATE. */
|
||||
ulint magic_n;
|
||||
};
|
||||
|
||||
|
@ -684,11 +684,6 @@ que_thr_stop(
|
||||
trx->lock.wait_thr = thr;
|
||||
thr->state = QUE_THR_LOCK_WAIT;
|
||||
|
||||
} else if (trx->duplicates && trx->error_state == DB_DUPLICATE_KEY
|
||||
&& thd_rpl_stmt_based(trx->mysql_thd)) {
|
||||
|
||||
return(FALSE);
|
||||
|
||||
} else if (trx->error_state != DB_SUCCESS
|
||||
&& trx->error_state != DB_LOCK_WAIT) {
|
||||
|
||||
|
@ -88,7 +88,6 @@ ins_node_create(
|
||||
node->select = NULL;
|
||||
|
||||
node->trx_id = 0;
|
||||
node->duplicate = NULL;
|
||||
|
||||
node->entry_sys_heap = mem_heap_create(128);
|
||||
|
||||
@ -191,7 +190,6 @@ ins_node_set_new_row(
|
||||
node->state = INS_NODE_SET_IX_LOCK;
|
||||
node->index = NULL;
|
||||
node->entry = NULL;
|
||||
node->duplicate = NULL;
|
||||
|
||||
node->row = row;
|
||||
|
||||
@ -2320,12 +2318,6 @@ row_ins_duplicate_error_in_clust(
|
||||
true,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
|
||||
ulint lock_type =
|
||||
trx->isolation_level <= TRX_ISO_READ_COMMITTED
|
||||
|| (trx->mysql_thd
|
||||
&& !thd_rpl_stmt_based(trx->mysql_thd))
|
||||
? LOCK_REC_NOT_GAP : LOCK_ORDINARY;
|
||||
|
||||
/* We set a lock on the possible duplicate: this
|
||||
is needed in logical logging of MySQL to make
|
||||
sure that in roll-forward we get the same duplicate
|
||||
@ -2342,13 +2334,13 @@ row_ins_duplicate_error_in_clust(
|
||||
INSERT ON DUPLICATE KEY UPDATE). */
|
||||
|
||||
err = row_ins_set_exclusive_rec_lock(
|
||||
lock_type,
|
||||
LOCK_REC_NOT_GAP,
|
||||
btr_cur_get_block(cursor),
|
||||
rec, cursor->index, offsets, thr);
|
||||
} else {
|
||||
|
||||
err = row_ins_set_shared_rec_lock(
|
||||
lock_type,
|
||||
LOCK_REC_NOT_GAP,
|
||||
btr_cur_get_block(cursor), rec,
|
||||
cursor->index, offsets, thr);
|
||||
}
|
||||
@ -2363,7 +2355,10 @@ row_ins_duplicate_error_in_clust(
|
||||
|
||||
if (row_ins_dupl_error_with_rec(
|
||||
rec, entry, cursor->index, offsets)) {
|
||||
goto duplicate;
|
||||
duplicate:
|
||||
trx->error_info = cursor->index;
|
||||
err = DB_DUPLICATE_KEY;
|
||||
goto func_exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2406,10 +2401,7 @@ row_ins_duplicate_error_in_clust(
|
||||
|
||||
if (row_ins_dupl_error_with_rec(
|
||||
rec, entry, cursor->index, offsets)) {
|
||||
duplicate:
|
||||
trx->error_info = cursor->index;
|
||||
err = DB_DUPLICATE_KEY;
|
||||
goto func_exit;
|
||||
goto duplicate;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3023,46 +3015,6 @@ row_ins_sec_index_entry_low(
|
||||
&cursor, 0, __FILE__, __LINE__, &mtr);
|
||||
}
|
||||
|
||||
if (!(flags & BTR_NO_LOCKING_FLAG)
|
||||
&& dict_index_is_unique(index)
|
||||
&& thr_get_trx(thr)->duplicates
|
||||
&& thr_get_trx(thr)->isolation_level >= TRX_ISO_REPEATABLE_READ
|
||||
&& thd_rpl_stmt_based(thr_get_trx(thr)->mysql_thd)) {
|
||||
|
||||
/* In statement-based replication, when replicating a
|
||||
REPLACE statement or ON DUPLICATE KEY UPDATE clause, a
|
||||
gap lock is taken on the position of the to-be-inserted record,
|
||||
to avoid other concurrent transactions from inserting the same
|
||||
record. */
|
||||
|
||||
dberr_t err;
|
||||
const rec_t* rec = page_rec_get_next_const(
|
||||
btr_cur_get_rec(&cursor));
|
||||
|
||||
ut_ad(!page_rec_is_infimum(rec));
|
||||
|
||||
offsets = rec_get_offsets(rec, index, offsets, true,
|
||||
ULINT_UNDEFINED, &offsets_heap);
|
||||
|
||||
err = row_ins_set_exclusive_rec_lock(
|
||||
LOCK_GAP, btr_cur_get_block(&cursor), rec,
|
||||
index, offsets, thr);
|
||||
|
||||
switch (err) {
|
||||
case DB_SUCCESS:
|
||||
case DB_SUCCESS_LOCKED_REC:
|
||||
if (thr_get_trx(thr)->error_state != DB_DUPLICATE_KEY) {
|
||||
break;
|
||||
}
|
||||
/* Fall through (skip actual insert) after we have
|
||||
successfully acquired the gap lock. */
|
||||
default:
|
||||
goto func_exit;
|
||||
}
|
||||
}
|
||||
|
||||
ut_ad(thr_get_trx(thr)->error_state == DB_SUCCESS);
|
||||
|
||||
if (dup_chk_only) {
|
||||
goto func_exit;
|
||||
}
|
||||
@ -3578,13 +3530,6 @@ row_ins(
|
||||
|
||||
DBUG_PRINT("row_ins", ("table: %s", node->table->name.m_name));
|
||||
|
||||
trx_t* trx = thr_get_trx(thr);
|
||||
|
||||
if (node->duplicate) {
|
||||
ut_ad(thd_rpl_stmt_based(trx->mysql_thd));
|
||||
trx->error_state = DB_DUPLICATE_KEY;
|
||||
}
|
||||
|
||||
if (node->state == INS_NODE_ALLOC_ROW_ID) {
|
||||
|
||||
row_ins_alloc_row_id_step(node);
|
||||
@ -3610,91 +3555,7 @@ row_ins(
|
||||
if (node->index->type != DICT_FTS) {
|
||||
dberr_t err = row_ins_index_entry_step(node, thr);
|
||||
|
||||
switch (err) {
|
||||
case DB_SUCCESS:
|
||||
break;
|
||||
case DB_NO_REFERENCED_ROW:
|
||||
if (!dict_index_is_unique(node->index)) {
|
||||
DBUG_RETURN(err);
|
||||
}
|
||||
/* fall through */
|
||||
case DB_DUPLICATE_KEY:
|
||||
ut_ad(dict_index_is_unique(node->index));
|
||||
|
||||
if (trx->isolation_level
|
||||
>= TRX_ISO_REPEATABLE_READ
|
||||
&& trx->duplicates
|
||||
&& !node->table->is_temporary()
|
||||
&& thd_rpl_stmt_based(trx->mysql_thd)) {
|
||||
|
||||
/* When we are in REPLACE statement or
|
||||
INSERT .. ON DUPLICATE UPDATE
|
||||
statement, we process all the
|
||||
unique secondary indexes, even after we
|
||||
encounter a duplicate error. This is
|
||||
done to take necessary gap locks in
|
||||
secondary indexes to block concurrent
|
||||
transactions from inserting the
|
||||
searched records. */
|
||||
if (err == DB_NO_REFERENCED_ROW
|
||||
&& node->duplicate) {
|
||||
/* A foreign key check on a
|
||||
unique index may fail to
|
||||
find the record.
|
||||
|
||||
Consider as a example
|
||||
following:
|
||||
create table child(a int not null
|
||||
primary key, b int not null,
|
||||
c int,
|
||||
unique key (b),
|
||||
foreign key (b) references
|
||||
parent (id)) engine=innodb;
|
||||
|
||||
insert into child values
|
||||
(1,1,2);
|
||||
|
||||
insert into child(a) values
|
||||
(1) on duplicate key update
|
||||
c = 3;
|
||||
|
||||
Now primary key value 1
|
||||
naturally causes duplicate
|
||||
key error that will be
|
||||
stored on node->duplicate.
|
||||
If there was no duplicate
|
||||
key error, we should return
|
||||
the actual no referenced
|
||||
row error.
|
||||
|
||||
As value for
|
||||
column b used in both unique
|
||||
key and foreign key is not
|
||||
provided, server uses 0 as a
|
||||
search value. This is
|
||||
naturally, not found leading
|
||||
to DB_NO_REFERENCED_ROW.
|
||||
But, we should update the
|
||||
row with primay key value 1
|
||||
anyway.
|
||||
|
||||
Return the
|
||||
original DB_DUPLICATE_KEY
|
||||
error after
|
||||
placing all gaplocks. */
|
||||
err = DB_DUPLICATE_KEY;
|
||||
break;
|
||||
} else if (!node->duplicate) {
|
||||
/* Save 1st dup error. Ignore
|
||||
subsequent dup errors. */
|
||||
node->duplicate = node->index;
|
||||
trx->error_state
|
||||
= DB_DUPLICATE_KEY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
default:
|
||||
if (err != DB_SUCCESS) {
|
||||
DBUG_RETURN(err);
|
||||
}
|
||||
}
|
||||
@ -3711,31 +3572,13 @@ row_ins(
|
||||
node->index = dict_table_get_next_index(node->index);
|
||||
node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry);
|
||||
}
|
||||
|
||||
/* After encountering a duplicate key error, we process
|
||||
remaining indexes just to place gap locks and no actual
|
||||
insertion will take place. These gap locks are needed
|
||||
only for unique indexes. So skipping non-unique indexes. */
|
||||
if (node->duplicate) {
|
||||
ut_ad(thd_rpl_stmt_based(trx->mysql_thd));
|
||||
while (node->index
|
||||
&& !dict_index_is_unique(node->index)) {
|
||||
|
||||
node->index = dict_table_get_next_index(
|
||||
node->index);
|
||||
node->entry = UT_LIST_GET_NEXT(tuple_list,
|
||||
node->entry);
|
||||
}
|
||||
trx->error_state = DB_DUPLICATE_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
ut_ad(node->entry == NULL);
|
||||
|
||||
trx->error_info = node->duplicate;
|
||||
node->state = INS_NODE_ALLOC_ROW_ID;
|
||||
|
||||
DBUG_RETURN(node->duplicate ? DB_DUPLICATE_KEY : DB_SUCCESS);
|
||||
DBUG_RETURN(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/***********************************************************//**
|
||||
|
@ -1435,7 +1435,6 @@ error_exit:
|
||||
goto run_again;
|
||||
}
|
||||
|
||||
node->duplicate = NULL;
|
||||
trx->op_info = "";
|
||||
|
||||
if (blob_heap != NULL) {
|
||||
@ -1445,8 +1444,6 @@ error_exit:
|
||||
return(err);
|
||||
}
|
||||
|
||||
node->duplicate = NULL;
|
||||
|
||||
if (dict_table_has_fts_index(table)) {
|
||||
doc_id_t doc_id;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user