diff options
author | unknown <guilhem@mysql.com> | 2006-07-05 14:41:35 +0200 |
---|---|---|
committer | unknown <guilhem@mysql.com> | 2006-07-05 14:41:35 +0200 |
commit | 4e9d7d6c4bfec9fc803b0db9624d255c25319bfb (patch) | |
tree | 9e992ea7bc522bfb397096a73d752ca0f1ab5b05 /sql/handler.h | |
parent | 57e7bc551300b224404b3ce1a5498917f9ead689 (diff) | |
download | mariadb-git-4e9d7d6c4bfec9fc803b0db9624d255c25319bfb.tar.gz |
Fix for BUG#20188 "REPLACE or ON DUPLICATE KEY UPDATE in
auto_increment breaks binlog":
if slave's table had a higher auto_increment counter than master's (even
though all rows of the two tables were identical), then in some cases,
REPLACE and INSERT ON DUPLICATE KEY UPDATE failed to replicate
statement-based (it inserted different values on slave from on master).
write_record() contained a "thd->next_insert_id=0" to force an adjustment
of thd->next_insert_id after the update or replacement. But it is this
assigment introduced indeterminism of the statement on the slave, thus
the bug. For ON DUPLICATE, we replace that assignment by a call to
handler::adjust_next_insert_id_after_explicit_value() which is deterministic
(does not depend on slave table's autoinc counter). For REPLACE, this
assignment can simply be removed (as REPLACE can't insert a number larger
than thd->next_insert_id).
We also move a too early restore_auto_increment() down to when we really know
that we can restore the value.
mysql-test/r/rpl_insert_id.result:
result update, without the bugfix, slave's "3 350" were "4 350".
mysql-test/t/rpl_insert_id.test:
test for BUG#20188 "REPLACE or ON DUPLICATE KEY UPDATE in
auto_increment breaks binlog".
There is, in this order:
- a test of the bug for the case of REPLACE
- a test of basic ON DUPLICATE KEY UPDATE functionality which was not
tested before
- a test of the bug for the case of ON DUPLICATE KEY UPDATE
sql/handler.cc:
the adjustment of next_insert_id if inserting a big explicit value, is
moved to a separate method to be used elsewhere.
sql/handler.h:
see handler.cc
sql/sql_insert.cc:
restore_auto_increment() means "I know I won't use this autogenerated
autoincrement value, you are free to reuse it for next row". But we were
calling restore_auto_increment() in the case of REPLACE: if write_row() fails
inserting the row, we don't know that we won't use the value, as we are going to
try again by doing internally an UPDATE of the existing row, or a DELETE
of the existing row and then an INSERT. So I move restore_auto_increment()
further down, when we know for sure we failed all possibilities for the row.
Additionally, in case of REPLACE, we don't need to reset THD::next_insert_id:
the value of thd->next_insert_id will be suitable for the next row.
In case of ON DUPLICATE KEY UPDATE, resetting thd->next_insert_id is also
wrong (breaks statement-based binlog), but cannot simply be removed, as
thd->next_insert_id must be adjusted if the explicit value exceeds it.
We now do the adjustment by calling
handler::adjust_next_insert_id_after_explicit_value() (which, contrary to
thd->next_insert_id=0, does not depend on the slave table's autoinc counter,
and so is deterministic).
Diffstat (limited to 'sql/handler.h')
-rw-r--r-- | sql/handler.h | 1 |
1 files changed, 1 insertions, 0 deletions
diff --git a/sql/handler.h b/sql/handler.h index 31aac075a5e..ee4bd239657 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -563,6 +563,7 @@ public: {} virtual ~handler(void) { /* TODO: DBUG_ASSERT(inited == NONE); */ } int ha_open(const char *name, int mode, int test_if_locked); + void adjust_next_insert_id_after_explicit_value(ulonglong nr); bool update_auto_increment(); virtual void print_error(int error, myf errflag); virtual bool get_error_message(int error, String *buf); |