diff options
-rw-r--r-- | mysql-test/r/rpl_insert_id.result | 58 | ||||
-rw-r--r-- | mysql-test/r/rpl_known_bugs_detection.result | 133 | ||||
-rw-r--r-- | mysql-test/t/rpl_insert_id.test | 53 | ||||
-rw-r--r-- | mysql-test/t/rpl_known_bugs_detection-master.opt | 1 | ||||
-rw-r--r-- | mysql-test/t/rpl_known_bugs_detection.test | 90 | ||||
-rw-r--r-- | sql/log_event.cc | 37 | ||||
-rw-r--r-- | sql/log_event.h | 2 | ||||
-rw-r--r-- | sql/slave.cc | 64 | ||||
-rw-r--r-- | sql/slave.h | 1 | ||||
-rw-r--r-- | sql/sql_insert.cc | 20 |
10 files changed, 458 insertions, 1 deletions
diff --git a/mysql-test/r/rpl_insert_id.result b/mysql-test/r/rpl_insert_id.result index d133a2ae8ed..a5c8e17f67e 100644 --- a/mysql-test/r/rpl_insert_id.result +++ b/mysql-test/r/rpl_insert_id.result @@ -234,6 +234,64 @@ n b 2 100 3 350 drop table t1; +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b INT, +UNIQUE(b)); +INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10; +SELECT * FROM t1; +a b +1 10 +2 2 +SELECT * FROM t1; +a b +1 10 +2 2 +drop table t1; +CREATE TABLE t1 ( +id bigint(20) unsigned NOT NULL auto_increment, +field_1 int(10) unsigned NOT NULL, +field_2 varchar(255) NOT NULL, +field_3 varchar(255) NOT NULL, +PRIMARY KEY (id), +UNIQUE KEY field_1 (field_1, field_2) +); +CREATE TABLE t2 ( +field_a int(10) unsigned NOT NULL, +field_b varchar(255) NOT NULL, +field_c varchar(255) NOT NULL +); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (1, 'a', '1a'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (2, 'b', '2b'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (3, 'c', '3c'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (4, 'd', '4d'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (5, 'e', '5e'); +INSERT INTO t1 (field_1, field_2, field_3) +SELECT t2.field_a, t2.field_b, t2.field_c +FROM t2 +ON DUPLICATE KEY UPDATE +t1.field_3 = t2.field_c; +INSERT INTO t2 (field_a, field_b, field_c) VALUES (6, 'f', '6f'); +INSERT INTO t1 (field_1, field_2, field_3) +SELECT t2.field_a, t2.field_b, t2.field_c +FROM t2 +ON DUPLICATE KEY UPDATE +t1.field_3 = t2.field_c; +SELECT * FROM t1; +id field_1 field_2 field_3 +1 1 a 1a +2 2 b 2b +3 3 c 3c +4 4 d 4d +5 5 e 5e +6 6 f 6f +SELECT * FROM t1; +id field_1 field_2 field_3 +1 1 a 1a +2 2 b 2b +3 3 c 3c +4 4 d 4d +5 5 e 5e +6 6 f 6f +drop table t1, t2; DROP PROCEDURE IF EXISTS p1; DROP TABLE IF EXISTS t1, t2; SELECT LAST_INSERT_ID(0); diff --git a/mysql-test/r/rpl_known_bugs_detection.result b/mysql-test/r/rpl_known_bugs_detection.result new file mode 100644 index 00000000000..c23586c6f61 --- /dev/null +++ b/mysql-test/r/rpl_known_bugs_detection.result @@ -0,0 +1,133 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b INT, +UNIQUE(b)); +INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10; +SELECT * FROM t1; +a b +1 10 +2 2 +show slave status;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 1105 +Last_Error Error 'master may suffer from http://bugs.mysql.com/bug.php?id=24432 so slave stops; check error log on slave for more info' on query. Default database: 'test'. Query: 'INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10' +Skip_Counter 0 +Exec_Master_Log_Pos 238 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +SELECT * FROM t1; +a b +stop slave; +reset slave; +reset master; +drop table t1; +start slave; +CREATE TABLE t1 ( +id bigint(20) unsigned NOT NULL auto_increment, +field_1 int(10) unsigned NOT NULL, +field_2 varchar(255) NOT NULL, +field_3 varchar(255) NOT NULL, +PRIMARY KEY (id), +UNIQUE KEY field_1 (field_1, field_2) +); +CREATE TABLE t2 ( +field_a int(10) unsigned NOT NULL, +field_b varchar(255) NOT NULL, +field_c varchar(255) NOT NULL +); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (1, 'a', '1a'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (2, 'b', '2b'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (3, 'c', '3c'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (4, 'd', '4d'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (5, 'e', '5e'); +INSERT INTO t1 (field_1, field_2, field_3) +SELECT t2.field_a, t2.field_b, t2.field_c +FROM t2 +ON DUPLICATE KEY UPDATE +t1.field_3 = t2.field_c; +INSERT INTO t2 (field_a, field_b, field_c) VALUES (6, 'f', '6f'); +INSERT INTO t1 (field_1, field_2, field_3) +SELECT t2.field_a, t2.field_b, t2.field_c +FROM t2 +ON DUPLICATE KEY UPDATE +t1.field_3 = t2.field_c; +SELECT * FROM t1; +id field_1 field_2 field_3 +1 1 a 1a +2 2 b 2b +3 3 c 3c +4 4 d 4d +5 5 e 5e +6 6 f 6f +show slave status;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 1105 +Last_Error Error 'master may suffer from http://bugs.mysql.com/bug.php?id=24432 so slave stops; check error log on slave for more info' on query. Default database: 'test'. Query: 'INSERT INTO t1 (field_1, field_2, field_3) +SELECT t2.field_a, t2.field_b, t2.field_c +FROM t2 +ON DUPLICATE KEY UPDATE +t1.field_3 = t2.field_c' +Skip_Counter 0 +Exec_Master_Log_Pos 1270 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +SELECT * FROM t1; +id field_1 field_2 field_3 +drop table t1, t2; +drop table t1, t2; diff --git a/mysql-test/t/rpl_insert_id.test b/mysql-test/t/rpl_insert_id.test index 331a913256c..be2948e9678 100644 --- a/mysql-test/t/rpl_insert_id.test +++ b/mysql-test/t/rpl_insert_id.test @@ -246,6 +246,59 @@ connection master; drop table t1; # +# BUG#24432 "INSERT... ON DUPLICATE KEY UPDATE skips auto_increment values" +# + +# testcase with INSERT VALUES +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b INT, +UNIQUE(b)); +INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10; +SELECT * FROM t1; +sync_slave_with_master; +SELECT * FROM t1; +connection master; +drop table t1; + +# tescase with INSERT SELECT +CREATE TABLE t1 ( + id bigint(20) unsigned NOT NULL auto_increment, + field_1 int(10) unsigned NOT NULL, + field_2 varchar(255) NOT NULL, + field_3 varchar(255) NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY field_1 (field_1, field_2) +); +CREATE TABLE t2 ( + field_a int(10) unsigned NOT NULL, + field_b varchar(255) NOT NULL, + field_c varchar(255) NOT NULL +); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (1, 'a', '1a'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (2, 'b', '2b'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (3, 'c', '3c'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (4, 'd', '4d'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (5, 'e', '5e'); +# Updating table t1 based on values from table t2 +INSERT INTO t1 (field_1, field_2, field_3) +SELECT t2.field_a, t2.field_b, t2.field_c +FROM t2 +ON DUPLICATE KEY UPDATE +t1.field_3 = t2.field_c; +# Inserting new record into t2 +INSERT INTO t2 (field_a, field_b, field_c) VALUES (6, 'f', '6f'); +# Updating t1 again +INSERT INTO t1 (field_1, field_2, field_3) +SELECT t2.field_a, t2.field_b, t2.field_c +FROM t2 +ON DUPLICATE KEY UPDATE +t1.field_3 = t2.field_c; +SELECT * FROM t1; +sync_slave_with_master; +SELECT * FROM t1; +connection master; +drop table t1, t2; + +# # BUG#20339: stored procedure using LAST_INSERT_ID() does not # replicate statement-based # diff --git a/mysql-test/t/rpl_known_bugs_detection-master.opt b/mysql-test/t/rpl_known_bugs_detection-master.opt new file mode 100644 index 00000000000..d4ba386a1a0 --- /dev/null +++ b/mysql-test/t/rpl_known_bugs_detection-master.opt @@ -0,0 +1 @@ +--loose-debug=d,pretend_version_50034_in_binlog diff --git a/mysql-test/t/rpl_known_bugs_detection.test b/mysql-test/t/rpl_known_bugs_detection.test new file mode 100644 index 00000000000..4719716d4a1 --- /dev/null +++ b/mysql-test/t/rpl_known_bugs_detection.test @@ -0,0 +1,90 @@ +# Test to see if slave can detect certain known bugs present +# on the master, and appropriately decides to stop +# (assuming the bug is fixed in the slave, slave cannot of course +# imitate the bug, so it has to stop). + +source include/have_debug.inc; +source include/master-slave.inc; + +# +# This is to test that slave properly detects if +# master may suffer from: +# BUG#24432 "INSERT... ON DUPLICATE KEY UPDATE skips auto_increment values" +# (i.e. on master, INSERT ON DUPLICATE KEY UPDATE is used and manipulates +# an auto_increment column, and is binlogged statement-based). +# + +# testcase with INSERT VALUES +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b INT, +UNIQUE(b)); +sync_slave_with_master; +connection master; +INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10; +SELECT * FROM t1; +connection slave; +wait_for_slave_to_stop; +# show the error message +--replace_column 1 # 4 # 7 # 8 # 9 # 23 # 33 # +--query_vertical show slave status; +# show that it was not replicated +SELECT * FROM t1; + +# restart replication for the next testcase +stop slave; +reset slave; +connection master; +reset master; +drop table t1; +connection slave; +start slave; + +# testcase with INSERT SELECT +connection master; +CREATE TABLE t1 ( + id bigint(20) unsigned NOT NULL auto_increment, + field_1 int(10) unsigned NOT NULL, + field_2 varchar(255) NOT NULL, + field_3 varchar(255) NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY field_1 (field_1, field_2) +); +CREATE TABLE t2 ( + field_a int(10) unsigned NOT NULL, + field_b varchar(255) NOT NULL, + field_c varchar(255) NOT NULL +); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (1, 'a', '1a'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (2, 'b', '2b'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (3, 'c', '3c'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (4, 'd', '4d'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (5, 'e', '5e'); +sync_slave_with_master; +connection master; +# Updating table t1 based on values from table t2 +INSERT INTO t1 (field_1, field_2, field_3) +SELECT t2.field_a, t2.field_b, t2.field_c +FROM t2 +ON DUPLICATE KEY UPDATE +t1.field_3 = t2.field_c; +# Inserting new record into t2 +INSERT INTO t2 (field_a, field_b, field_c) VALUES (6, 'f', '6f'); +# Updating t1 again +INSERT INTO t1 (field_1, field_2, field_3) +SELECT t2.field_a, t2.field_b, t2.field_c +FROM t2 +ON DUPLICATE KEY UPDATE +t1.field_3 = t2.field_c; +SELECT * FROM t1; +connection slave; +wait_for_slave_to_stop; +# show the error message +--replace_column 1 # 4 # 7 # 8 # 9 # 23 # 33 # +--query_vertical show slave status; +# show that it was not replicated +SELECT * FROM t1; +connection master; +drop table t1, t2; +connection slave; +drop table t1, t2; + +# End of 5.0 tests diff --git a/sql/log_event.cc b/sql/log_event.cc index 657fd510e78..a14cd79461d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2047,6 +2047,8 @@ Start_log_event_v3::Start_log_event_v3(const char* buf, binlog_version= uint2korr(buf+ST_BINLOG_VER_OFFSET); memcpy(server_version, buf+ST_SERVER_VER_OFFSET, ST_SERVER_VER_LEN); + // prevent overrun if log is corrupted on disk + server_version[ST_SERVER_VER_LEN-1]= 0; created= uint4korr(buf+ST_CREATED_OFFSET); /* We use log_pos to mark if this was an artificial event or not */ artificial_event= (log_pos == 0); @@ -2170,6 +2172,8 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver) switch (binlog_ver) { case 4: /* MySQL 5.0 */ memcpy(server_version, ::server_version, ST_SERVER_VER_LEN); + DBUG_EXECUTE_IF("pretend_version_50034_in_binlog", + strmov(server_version, "5.0.34");); common_header_len= LOG_EVENT_HEADER_LEN; number_of_event_types= LOG_EVENT_TYPES; /* we'll catch my_malloc() error in is_valid() */ @@ -2241,6 +2245,7 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver) post_header_len= 0; /* will make is_valid() fail */ break; } + calc_server_version_split(); } @@ -2280,6 +2285,7 @@ Format_description_log_event(const char* buf, post_header_len= (uint8*) my_memdup((byte*)buf+ST_COMMON_HEADER_LEN_OFFSET+1, number_of_event_types* sizeof(*post_header_len), MYF(0)); + calc_server_version_split(); DBUG_VOID_RETURN; } @@ -2380,6 +2386,37 @@ int Format_description_log_event::exec_event(struct st_relay_log_info* rli) } #endif + +/** + Splits the event's 'server_version' string into three numeric pieces stored + into 'server_version_split': + X.Y.Zabc (X,Y,Z numbers, a not a digit) -> {X,Y,Z} + X.Yabc -> {X,Y,0} + Xabc -> {X,0,0} + 'server_version_split' is then used for lookups to find if the server which + created this event has some known bug. +*/ +void Format_description_log_event::calc_server_version_split() +{ + char *p= server_version, *r; + ulong number; + for (uint i= 0; i<=2; i++) + { + number= strtoul(p, &r, 10); + server_version_split[i]= (uchar)number; + DBUG_ASSERT(number < 256); // fit in uchar + p= r; + DBUG_ASSERT(!((i == 0) && (*r != '.'))); // should be true in practice + if (*r == '.') + p++; // skip the dot + } + DBUG_PRINT("info",("Format_description_log_event::server_version_split:" + " '%s' %d %d %d", server_version, + server_version_split[0], + server_version_split[1], server_version_split[2])); +} + + /************************************************************************** Load_log_event methods General note about Load_log_event: the binlogging of LOAD DATA INFILE is diff --git a/sql/log_event.h b/sql/log_event.h index fd2a5e5fb63..d3ebe6860f5 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1102,6 +1102,7 @@ public: uint8 number_of_event_types; /* The list of post-headers' lengthes */ uint8 *post_header_len; + uchar server_version_split[3]; Format_description_log_event(uint8 binlog_ver, const char* server_ver=0); @@ -1133,6 +1134,7 @@ public: */ return FORMAT_DESCRIPTION_HEADER_LEN; } + void calc_server_version_split(); }; diff --git a/sql/slave.cc b/sql/slave.cc index 8805f950d50..37c782a42c3 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -5165,6 +5165,70 @@ end: } +/** + Detects, based on master's version (as found in the relay log), if master + has a certain bug. + @param rli RELAY_LOG_INFO which tells the master's version + @param bug_id Number of the bug as found in bugs.mysql.com + @return TRUE if master has the bug, FALSE if it does not. +*/ +bool rpl_master_has_bug(RELAY_LOG_INFO *rli, uint bug_id) +{ + struct st_version_range_for_one_bug { + uint bug_id; + const uchar introduced_in[3]; // first version with bug + const uchar fixed_in[3]; // first version with fix + }; + static struct st_version_range_for_one_bug versions_for_all_bugs[]= + { + {24432, { 5, 0, 24 }, { 5, 0, 36 } }, + {24432, { 5, 1, 12 }, { 5, 1, 16 } } + }; + const uchar *master_ver= + rli->relay_log.description_event_for_exec->server_version_split; + + DBUG_ASSERT(sizeof(rli->relay_log.description_event_for_exec->server_version_split) == 3); + + for (uint i= 0; + i < sizeof(versions_for_all_bugs)/sizeof(*versions_for_all_bugs);i++) + { + const uchar *introduced_in= versions_for_all_bugs[i].introduced_in, + *fixed_in= versions_for_all_bugs[i].fixed_in; + if ((versions_for_all_bugs[i].bug_id == bug_id) && + (memcmp(introduced_in, master_ver, 3) <= 0) && + (memcmp(fixed_in, master_ver, 3) > 0)) + { + // a verbose message for the error log + slave_print_error(rli, ER_UNKNOWN_ERROR, + "According to the master's version ('%s')," + " it is probable that master suffers from this bug:" + " http://bugs.mysql.com/bug.php?id=%u" + " and thus replicating the current binary log event" + " may make the slave's data become different from the" + " master's data." + " To take no risk, slave refuses to replicate" + " this event and stops." + " We recommend that all updates be stopped on the" + " master and slave, that the data of both be" + " manually synchronized," + " that master's binary logs be deleted," + " that master be upgraded to a version at least" + " equal to '%d.%d.%d'. Then replication can be" + " restarted.", + rli->relay_log.description_event_for_exec->server_version, + bug_id, + fixed_in[0], fixed_in[1], fixed_in[2]); + // a short message for SHOW SLAVE STATUS (message length constraints) + my_printf_error(ER_UNKNOWN_ERROR, "master may suffer from" + " http://bugs.mysql.com/bug.php?id=%u" + " so slave stops; check error log on slave" + " for more info", MYF(0), bug_id); + return TRUE; + } + } + return FALSE; +} + #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION template class I_List_iterator<i_string>; template class I_List_iterator<i_string_pair>; diff --git a/sql/slave.h b/sql/slave.h index bbf450bab75..e7d4456ccd9 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -533,6 +533,7 @@ void table_rule_ent_hash_to_str(String* s, HASH* h); void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a); bool show_master_info(THD* thd, MASTER_INFO* mi); bool show_binlog_info(THD* thd); +bool rpl_master_has_bug(RELAY_LOG_INFO *rli, uint bug_id); /* See if the query uses any tables that should not be replicated */ bool tables_ok(THD* thd, TABLE_LIST* tables); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index c60d3c307d0..c5f1524c556 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -58,6 +58,7 @@ #include "sp_head.h" #include "sql_trigger.h" #include "sql_select.h" +#include "slave.h" static int check_null_fields(THD *thd,TABLE *entry); #ifndef EMBEDDED_LIBRARY @@ -468,6 +469,14 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, thd->cuted_fields = 0L; table->next_number_field=table->found_next_number_field; +#ifdef HAVE_REPLICATION + if (thd->slave_thread && + (info.handle_duplicates == DUP_UPDATE) && + (table->next_number_field != NULL) && + rpl_master_has_bug(&active_mi->rli, 24432)) + goto abort; +#endif + error=0; id=0; thd->proc_info="update"; @@ -1133,11 +1142,11 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) if (res == VIEW_CHECK_ERROR) goto before_trg_err; + table->file->restore_auto_increment(); if ((error=table->file->update_row(table->record[1],table->record[0]))) { if ((error == HA_ERR_FOUND_DUPP_KEY) && info->ignore) { - table->file->restore_auto_increment(); goto ok_or_after_trg_err; } goto err; @@ -2369,6 +2378,15 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) } restore_record(table,s->default_values); // Get empty record table->next_number_field=table->found_next_number_field; + +#ifdef HAVE_REPLICATION + if (thd->slave_thread && + (info.handle_duplicates == DUP_UPDATE) && + (table->next_number_field != NULL) && + rpl_master_has_bug(&active_mi->rli, 24432)) + DBUG_RETURN(1); +#endif + thd->cuted_fields=0; if (info.ignore || info.handle_duplicates != DUP_ERROR) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); |