Bug#20573

  "strict mode: inserts autogenerated auto_increment value bigger than max"
  Strict mode should fail if autoincrement value is out of range
parent 6509ad6e
...@@ -357,8 +357,10 @@ enum ha_base_keytype { ...@@ -357,8 +357,10 @@ enum ha_base_keytype {
#define HA_ERR_TABLE_DEF_CHANGED 159 /* The table changed in storage engine */ #define HA_ERR_TABLE_DEF_CHANGED 159 /* The table changed in storage engine */
#define HA_ERR_TABLE_NEEDS_UPGRADE 160 /* The table changed in storage engine */ #define HA_ERR_TABLE_NEEDS_UPGRADE 160 /* The table changed in storage engine */
#define HA_ERR_TABLE_READONLY 161 /* The table is not writable */ #define HA_ERR_TABLE_READONLY 161 /* The table is not writable */
#define HA_ERR_AUTOINC_READ_FAILED 162/* Failed to get the next autoinc value */
#define HA_ERR_AUTOINC_ERANGE 163 /* Failed to set the row autoinc value */
#define HA_ERR_LAST 161 /*Copy last error nr.*/ #define HA_ERR_LAST 163 /*Copy last error nr.*/
/* Add error numbers before HA_ERR_LAST and change it accordingly. */ /* Add error numbers before HA_ERR_LAST and change it accordingly. */
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1) #define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)
......
#
# Test for strict-mode autoincrement
#
set @org_mode=@@sql_mode;
eval create table t1
(
`a` tinyint(4) NOT NULL auto_increment,
primary key (`a`)
) engine = $type ;
set @@sql_mode='strict_all_tables';
--error ER_WARN_DATA_OUT_OF_RANGE
insert into t1 values(1000);
select count(*) from t1;
set auto_increment_increment=1000;
set auto_increment_offset=700;
--error ER_WARN_DATA_OUT_OF_RANGE
insert into t1 values(null);
select count(*) from t1;
set @@sql_mode=@org_mode;
insert into t1 values(null);
select * from t1;
drop table t1;
# End of test
set @org_mode=@@sql_mode;
create table t1
(
`a` tinyint(4) NOT NULL auto_increment,
primary key (`a`)
) engine = 'MYISAM' ;
set @@sql_mode='strict_all_tables';
insert into t1 values(1000);
ERROR 22003: Out of range value adjusted for column 'a' at row 1
select count(*) from t1;
count(*)
0
set auto_increment_increment=1000;
set auto_increment_offset=700;
insert into t1 values(null);
ERROR 22003: Out of range value adjusted for column 'a' at row 1
select count(*) from t1;
count(*)
0
set @@sql_mode=@org_mode;
insert into t1 values(null);
Warnings:
Warning 1264 Out of range value adjusted for column 'a' at row 1
select * from t1;
a
127
drop table t1;
set @org_mode=@@sql_mode;
create table t1
(
`a` tinyint(4) NOT NULL auto_increment,
primary key (`a`)
) engine = 'InnoDB' ;
set @@sql_mode='strict_all_tables';
insert into t1 values(1000);
ERROR 22003: Out of range value adjusted for column 'a' at row 1
select count(*) from t1;
count(*)
0
set auto_increment_increment=1000;
set auto_increment_offset=700;
insert into t1 values(null);
ERROR 22003: Out of range value adjusted for column 'a' at row 1
select count(*) from t1;
count(*)
0
set @@sql_mode=@org_mode;
insert into t1 values(null);
Warnings:
Warning 1264 Out of range value adjusted for column 'a' at row 1
select * from t1;
a
127
drop table t1;
set @org_mode=@@sql_mode;
create table t1
(
`a` tinyint(4) NOT NULL auto_increment,
primary key (`a`)
) engine = 'MEMORY' ;
set @@sql_mode='strict_all_tables';
insert into t1 values(1000);
ERROR 22003: Out of range value adjusted for column 'a' at row 1
select count(*) from t1;
count(*)
0
set auto_increment_increment=1000;
set auto_increment_offset=700;
insert into t1 values(null);
ERROR 22003: Out of range value adjusted for column 'a' at row 1
select count(*) from t1;
count(*)
0
set @@sql_mode=@org_mode;
insert into t1 values(null);
Warnings:
Warning 1264 Out of range value adjusted for column 'a' at row 1
select * from t1;
a
127
drop table t1;
set @org_mode=@@sql_mode;
create table t1
(
`a` tinyint(4) NOT NULL auto_increment,
primary key (`a`)
) engine = 'BDB' ;
set @@sql_mode='strict_all_tables';
insert into t1 values(1000);
ERROR 22003: Out of range value adjusted for column 'a' at row 1
select count(*) from t1;
count(*)
0
set auto_increment_increment=1000;
set auto_increment_offset=700;
insert into t1 values(null);
ERROR 22003: Out of range value adjusted for column 'a' at row 1
select count(*) from t1;
count(*)
0
set @@sql_mode=@org_mode;
insert into t1 values(null);
Warnings:
Warning 1264 Out of range value adjusted for column 'a' at row 1
select * from t1;
a
127
drop table t1;
set @org_mode=@@sql_mode;
create table t1
(
`a` tinyint(4) NOT NULL auto_increment,
primary key (`a`)
) engine = 'NDB' ;
set @@sql_mode='strict_all_tables';
insert into t1 values(1000);
ERROR 22003: Out of range value adjusted for column 'a' at row 1
select count(*) from t1;
count(*)
0
set auto_increment_increment=1000;
set auto_increment_offset=700;
insert into t1 values(null);
ERROR 22003: Out of range value adjusted for column 'a' at row 1
select count(*) from t1;
count(*)
0
set @@sql_mode=@org_mode;
insert into t1 values(null);
Warnings:
Warning 1264 Out of range value adjusted for column 'a' at row 1
select * from t1;
a
127
drop table t1;
#
# Bug#20573 Strict mode auto-increment
#
let $type= 'MYISAM' ;
--source include/strict_autoinc.inc
# end of test
-- source include/have_innodb.inc
#
# Bug#20573 Strict mode auto-increment
#
let $type= 'InnoDB' ;
--source include/strict_autoinc.inc
# end of test
#
# Bug#20573 Strict mode auto-increment
#
let $type= 'MEMORY' ;
--source include/strict_autoinc.inc
# end of test
-- source include/have_bdb.inc
#
# Bug#20573 Strict mode auto-increment
#
let $type= 'BDB' ;
--source include/strict_autoinc.inc
# end of test
-- source include/have_ndb.inc
#
# Bug#20573 Strict mode auto-increment
#
let $type= 'NDB' ;
--source include/strict_autoinc.inc
# end of test
...@@ -953,7 +953,10 @@ int ha_berkeley::write_row(byte * record) ...@@ -953,7 +953,10 @@ int ha_berkeley::write_row(byte * record)
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time(); table->timestamp_field->set_time();
if (table->next_number_field && record == table->record[0]) if (table->next_number_field && record == table->record[0])
update_auto_increment(); {
if ((error= update_auto_increment()))
DBUG_RETURN(error);
}
if ((error=pack_row(&row, record,1))) if ((error=pack_row(&row, record,1)))
DBUG_RETURN(error); /* purecov: inspected */ DBUG_RETURN(error); /* purecov: inspected */
......
...@@ -176,7 +176,10 @@ int ha_heap::write_row(byte * buf) ...@@ -176,7 +176,10 @@ int ha_heap::write_row(byte * buf)
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time(); table->timestamp_field->set_time();
if (table->next_number_field && buf == table->record[0]) if (table->next_number_field && buf == table->record[0])
update_auto_increment(); {
if ((res= update_auto_increment()))
return res;
}
res= heap_write(file,buf); res= heap_write(file,buf);
if (!res && (++records_changed*HEAP_STATS_UPDATE_THRESHOLD > if (!res && (++records_changed*HEAP_STATS_UPDATE_THRESHOLD >
file->s->records)) file->s->records))
......
...@@ -3252,7 +3252,8 @@ ha_innobase::write_row( ...@@ -3252,7 +3252,8 @@ ha_innobase::write_row(
/* We must use the handler code to update the auto-increment /* We must use the handler code to update the auto-increment
value to be sure that we increment it correctly. */ value to be sure that we increment it correctly. */
update_auto_increment(); if ((error= update_auto_increment()))
goto func_exit;
auto_inc_used = 1; auto_inc_used = 1;
} }
......
...@@ -316,7 +316,11 @@ int ha_myisam::write_row(byte * buf) ...@@ -316,7 +316,11 @@ int ha_myisam::write_row(byte * buf)
or a new row, then update the auto_increment value in the record. or a new row, then update the auto_increment value in the record.
*/ */
if (table->next_number_field && buf == table->record[0]) if (table->next_number_field && buf == table->record[0])
update_auto_increment(); {
int error;
if ((error= update_auto_increment()))
return error;
}
return mi_write(file,buf); return mi_write(file,buf);
} }
......
...@@ -139,7 +139,11 @@ int ha_myisammrg::write_row(byte * buf) ...@@ -139,7 +139,11 @@ int ha_myisammrg::write_row(byte * buf)
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time(); table->timestamp_field->set_time();
if (table->next_number_field && buf == table->record[0]) if (table->next_number_field && buf == table->record[0])
update_auto_increment(); {
int error;
if ((error= update_auto_increment()))
return error;
}
return myrg_write(file,buf); return myrg_write(file,buf);
} }
......
...@@ -2130,9 +2130,11 @@ int ha_ndbcluster::write_row(byte *record) ...@@ -2130,9 +2130,11 @@ int ha_ndbcluster::write_row(byte *record)
if (has_auto_increment) if (has_auto_increment)
{ {
THD *thd= table->in_use; THD *thd= table->in_use;
int error;
m_skip_auto_increment= FALSE; m_skip_auto_increment= FALSE;
update_auto_increment(); if ((error= update_auto_increment()))
DBUG_RETURN(error);
/* Ensure that handler is always called for auto_increment values */ /* Ensure that handler is always called for auto_increment values */
thd->next_insert_id= 0; thd->next_insert_id= 0;
m_skip_auto_increment= !auto_increment_column_changed; m_skip_auto_increment= !auto_increment_column_changed;
......
...@@ -429,6 +429,8 @@ static int ha_init_errors(void) ...@@ -429,6 +429,8 @@ static int ha_init_errors(void)
SETMSG(HA_ERR_TABLE_DEF_CHANGED, ER(ER_TABLE_DEF_CHANGED)); SETMSG(HA_ERR_TABLE_DEF_CHANGED, ER(ER_TABLE_DEF_CHANGED));
SETMSG(HA_ERR_TABLE_NEEDS_UPGRADE, ER(ER_TABLE_NEEDS_UPGRADE)); SETMSG(HA_ERR_TABLE_NEEDS_UPGRADE, ER(ER_TABLE_NEEDS_UPGRADE));
SETMSG(HA_ERR_TABLE_READONLY, ER(ER_OPEN_AS_READONLY)); SETMSG(HA_ERR_TABLE_READONLY, ER(ER_OPEN_AS_READONLY));
SETMSG(HA_ERR_AUTOINC_READ_FAILED, ER(ER_AUTOINC_READ_FAILED));
SETMSG(HA_ERR_AUTOINC_ERANGE, ER(ER_WARN_DATA_OUT_OF_RANGE));
/* Register the error messages for use with my_error(). */ /* Register the error messages for use with my_error(). */
return my_error_register(errmsgs, HA_ERR_FIRST, HA_ERR_LAST); return my_error_register(errmsgs, HA_ERR_FIRST, HA_ERR_LAST);
...@@ -1542,7 +1544,10 @@ prev_insert_id(ulonglong nr, struct system_variables *variables) ...@@ -1542,7 +1544,10 @@ prev_insert_id(ulonglong nr, struct system_variables *variables)
RETURN RETURN
0 ok 0 ok
1 get_auto_increment() was called and returned ~(ulonglong) 0 HA_ERR_AUTOINC_READ_FAILED
get_auto_increment() was called and returned ~(ulonglong) 0
HA_ERR_AUTOINC_ERANGE
storing value in field caused strict mode failure.
IMPLEMENTATION IMPLEMENTATION
...@@ -1586,13 +1591,12 @@ prev_insert_id(ulonglong nr, struct system_variables *variables) ...@@ -1586,13 +1591,12 @@ prev_insert_id(ulonglong nr, struct system_variables *variables)
thd->next_insert_id is cleared after it's been used for a statement. thd->next_insert_id is cleared after it's been used for a statement.
*/ */
bool handler::update_auto_increment() int handler::update_auto_increment()
{ {
ulonglong nr; ulonglong nr;
THD *thd= table->in_use; THD *thd= table->in_use;
struct system_variables *variables= &thd->variables; struct system_variables *variables= &thd->variables;
bool auto_increment_field_not_null; bool auto_increment_field_not_null;
bool result= 0;
DBUG_ENTER("handler::update_auto_increment"); DBUG_ENTER("handler::update_auto_increment");
/* /*
...@@ -1616,7 +1620,7 @@ bool handler::update_auto_increment() ...@@ -1616,7 +1620,7 @@ bool handler::update_auto_increment()
if (!(nr= thd->next_insert_id)) if (!(nr= thd->next_insert_id))
{ {
if ((nr= get_auto_increment()) == ~(ulonglong) 0) if ((nr= get_auto_increment()) == ~(ulonglong) 0)
result= 1; // Mark failure DBUG_RETURN(HA_ERR_AUTOINC_READ_FAILED); // Mark failure
if (variables->auto_increment_increment != 1) if (variables->auto_increment_increment != 1)
nr= next_insert_id(nr-1, variables); nr= next_insert_id(nr-1, variables);
...@@ -1636,6 +1640,7 @@ bool handler::update_auto_increment() ...@@ -1636,6 +1640,7 @@ bool handler::update_auto_increment()
if (likely(!table->next_number_field->store((longlong) nr, TRUE))) if (likely(!table->next_number_field->store((longlong) nr, TRUE)))
thd->insert_id((ulonglong) nr); thd->insert_id((ulonglong) nr);
else else
if (thd->killed != THD::KILL_BAD_DATA) /* did we fail strict mode? */
{ {
/* /*
overflow of the field; we'll use the max value, however we try to overflow of the field; we'll use the max value, however we try to
...@@ -1646,6 +1651,8 @@ bool handler::update_auto_increment() ...@@ -1646,6 +1651,8 @@ bool handler::update_auto_increment()
if (unlikely(table->next_number_field->store((longlong) nr, TRUE))) if (unlikely(table->next_number_field->store((longlong) nr, TRUE)))
thd->insert_id(nr= table->next_number_field->val_int()); thd->insert_id(nr= table->next_number_field->val_int());
} }
else
DBUG_RETURN(HA_ERR_AUTOINC_ERANGE);
/* /*
We can't set next_insert_id if the auto-increment key is not the We can't set next_insert_id if the auto-increment key is not the
...@@ -1666,7 +1673,7 @@ bool handler::update_auto_increment() ...@@ -1666,7 +1673,7 @@ bool handler::update_auto_increment()
/* Mark that we generated a new value */ /* Mark that we generated a new value */
auto_increment_column_changed=1; auto_increment_column_changed=1;
DBUG_RETURN(result); DBUG_RETURN(0);
} }
/* /*
...@@ -1864,6 +1871,12 @@ void handler::print_error(int error, myf errflag) ...@@ -1864,6 +1871,12 @@ void handler::print_error(int error, myf errflag)
case HA_ERR_TABLE_READONLY: case HA_ERR_TABLE_READONLY:
textno= ER_OPEN_AS_READONLY; textno= ER_OPEN_AS_READONLY;
break; break;
case HA_ERR_AUTOINC_READ_FAILED:
textno= ER_AUTOINC_READ_FAILED;
break;
case HA_ERR_AUTOINC_ERANGE:
textno= ER_WARN_DATA_OUT_OF_RANGE;
break;
default: default:
{ {
/* The error was "unknown" to this function. /* The error was "unknown" to this function.
......
...@@ -565,7 +565,7 @@ class handler :public Sql_alloc ...@@ -565,7 +565,7 @@ class handler :public Sql_alloc
virtual ~handler(void) { /* TODO: DBUG_ASSERT(inited == NONE); */ } virtual ~handler(void) { /* TODO: DBUG_ASSERT(inited == NONE); */ }
int ha_open(const char *name, int mode, int test_if_locked); int ha_open(const char *name, int mode, int test_if_locked);
void adjust_next_insert_id_after_explicit_value(ulonglong nr); void adjust_next_insert_id_after_explicit_value(ulonglong nr);
bool update_auto_increment(); int update_auto_increment();
virtual void print_error(int error, myf errflag); virtual void print_error(int error, myf errflag);
virtual bool get_error_message(int error, String *buf); virtual bool get_error_message(int error, String *buf);
uint get_dup_key(int error); uint get_dup_key(int error);
......
...@@ -5623,3 +5623,5 @@ ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA ...@@ -5623,3 +5623,5 @@ ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA
eng "Triggers can not be created on system tables" eng "Triggers can not be created on system tables"
ER_REMOVED_SPACES ER_REMOVED_SPACES
eng "Leading spaces are removed from name '%s'" eng "Leading spaces are removed from name '%s'"
ER_AUTOINC_READ_FAILED
eng "Failed to read auto-increment value from storage engine"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment