#At file:///export/home/x/mysql-5.5-runtime-bug50619/ based on revid:jon.hauglid@stripped
3179 Jon Olav Hauglid 2010-11-10
Bug #50619 assert in handler::update_auto_increment
This assert could happen during subsequent inserts if -1 had
already been inserted into an auto increment column.
The root cause of the problem is that auto increment values are
internally stored unsigned while auto increment column types can
be signed values. When an explict value is set for the auto
increment column, the internal auto increment value is reset to
the explicit value + 1. However, if the explicit value is -1,
converting this value to unsigned and adding 1 will yield 0 as
a result (due to overflow). Since 0 would be outside the reserved
auto increment interval for the insert (auto increment values
should start at 1), the assert would be triggered.
This patch fixes the problem by checking if the explicit value
is negative. If this is the case, auto increment values are not
reset.
Test case added to auto_increment.test.
modified:
mysql-test/r/auto_increment.result
mysql-test/t/auto_increment.test
sql/handler.cc
sql/handler.h
=== modified file 'mysql-test/r/auto_increment.result'
--- a/mysql-test/r/auto_increment.result 2010-08-18 09:35:41 +0000
+++ b/mysql-test/r/auto_increment.result 2010-11-10 15:05:22 +0000
@@ -476,3 +476,16 @@ SELECT a FROM t2;
a
2
DROP TABLE t1, t2;
+#
+# Bug#50619 assert in handler::update_auto_increment
+#
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (pk INT AUTO_INCREMENT, PRIMARY KEY (pk));
+INSERT INTO t1 VALUES (-1);
+CREATE TRIGGER tr1 BEFORE DELETE ON t1 FOR EACH ROW SET @aux = 1 ;
+REPLACE INTO t1 (pk) VALUES (NULL), (-1);
+SELECT * FROM t1;
+pk
+-1
+1
+DROP TABLE t1;
=== modified file 'mysql-test/t/auto_increment.test'
--- a/mysql-test/t/auto_increment.test 2010-08-18 09:35:41 +0000
+++ b/mysql-test/t/auto_increment.test 2010-11-10 15:05:22 +0000
@@ -342,3 +342,20 @@ SELECT a FROM t2;
DROP TABLE t1, t2;
+
+--echo #
+--echo # Bug#50619 assert in handler::update_auto_increment
+--echo #
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (pk INT AUTO_INCREMENT, PRIMARY KEY (pk));
+INSERT INTO t1 VALUES (-1);
+CREATE TRIGGER tr1 BEFORE DELETE ON t1 FOR EACH ROW SET @aux = 1 ;
+# This caused an assert
+REPLACE INTO t1 (pk) VALUES (NULL), (-1);
+SELECT * FROM t1;
+
+DROP TABLE t1;
=== modified file 'sql/handler.cc'
--- a/sql/handler.cc 2010-10-18 11:27:52 +0000
+++ b/sql/handler.cc 2010-11-10 15:05:22 +0000
@@ -2204,14 +2204,14 @@ compute_next_insert_id(ulonglong nr,stru
}
-void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr)
+void handler::adjust_next_insert_id_after_explicit_value(longlong nr)
{
/*
If we have set THD::next_insert_id previously and plan to insert an
explicitely-specified value larger than this, we need to increase
THD::next_insert_id to be greater than the explicit value.
*/
- if ((next_insert_id > 0) && (nr >= next_insert_id))
+ if ((next_insert_id > 0) && (nr >=0) && ((ulonglong)nr >= next_insert_id))
set_next_insert_id(compute_next_insert_id(nr, &table->in_use->variables));
}
@@ -2348,7 +2348,7 @@ int handler::update_auto_increment()
*/
DBUG_ASSERT(next_insert_id >= auto_inc_interval_for_cur_row.minimum());
- if ((nr= table->next_number_field->val_int()) != 0 ||
+ if ((table->next_number_field->val_int() != 0) ||
(table->auto_increment_field_not_null &&
thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO))
{
@@ -2358,7 +2358,8 @@ int handler::update_auto_increment()
the last NULL needs to insert 3764, not the value of the first NULL plus
1).
*/
- adjust_next_insert_id_after_explicit_value(nr);
+ adjust_next_insert_id_after_explicit_value(
+ table->next_number_field->val_int());
insert_id_for_cur_row= 0; // didn't generate anything
DBUG_RETURN(0);
}
=== modified file 'sql/handler.h'
--- a/sql/handler.h 2010-10-06 14:34:28 +0000
+++ b/sql/handler.h 2010-11-10 15:05:22 +0000
@@ -1358,7 +1358,7 @@ public:
int ha_drop_partitions(const char *path);
int ha_rename_partitions(const char *path);
- void adjust_next_insert_id_after_explicit_value(ulonglong nr);
+ void adjust_next_insert_id_after_explicit_value(longlong nr);
int update_auto_increment();
void print_keydup_error(uint key_nr, const char *msg);
virtual void print_error(int error, myf errflag);
Attachment: [text/bzr-bundle] bzr/jon.hauglid@oracle.com-20101110150522-bg2nayj2r2pxor2m.bundle