diff --git a/mysql-test/suite/sql_sequence/auto_increment.result b/mysql-test/suite/sql_sequence/auto_increment.result index 72bd54a9186..eab2d0dccea 100644 --- a/mysql-test/suite/sql_sequence/auto_increment.result +++ b/mysql-test/suite/sql_sequence/auto_increment.result @@ -31,8 +31,6 @@ set global auto_increment_increment= default, auto_increment_offset= default; # # MDEV-28152 Features for sequence # -call mtr.add_suppression("signed integer overflow: 42 \\+ 9223372036854775800 cannot be represented in type 'long long int'"); -call mtr.add_suppression("signed integer overflow: 9223372036854775800 \\+ 100000 cannot be represented in type 'long long int'"); set global auto_increment_increment= 100; set global auto_increment_offset= 42; create sequence s as bigint unsigned start with 9223372036854775800 increment 0; @@ -43,6 +41,10 @@ select next value for s; next value for s 9223372036854775942 drop sequence s; +set global auto_increment_increment= 100; +set global auto_increment_offset= 5; +create sequence s as bigint start with -9223372036854775805 minvalue -9223372036854775807 maxvalue -9223372036854775800 increment 0; +drop sequence s; set global auto_increment_increment= default, auto_increment_offset= default; # # End of 11.4 tests diff --git a/mysql-test/suite/sql_sequence/auto_increment.test b/mysql-test/suite/sql_sequence/auto_increment.test index 85064fa5a5b..0d23eba759a 100644 --- a/mysql-test/suite/sql_sequence/auto_increment.test +++ b/mysql-test/suite/sql_sequence/auto_increment.test @@ -34,16 +34,19 @@ set global auto_increment_increment= default, auto_increment_offset= default; --echo # MDEV-28152 Features for sequence --echo # -# These overflows of signed long long are ok because we are using them -# to represent unsigned long long: -call mtr.add_suppression("signed integer overflow: 42 \\+ 9223372036854775800 cannot be represented in type 'long long int'"); -call mtr.add_suppression("signed integer overflow: 9223372036854775800 \\+ 100000 cannot be represented in type 'long long int'"); set global auto_increment_increment= 100; set global auto_increment_offset= 42; create sequence s as bigint unsigned start with 9223372036854775800 increment 0; select next value for s; select next value for s; drop sequence s; + +set global auto_increment_increment= 100; +set global auto_increment_offset= 5; +# Test underflow +create sequence s as bigint start with -9223372036854775805 minvalue -9223372036854775807 maxvalue -9223372036854775800 increment 0; +drop sequence s; + set global auto_increment_increment= default, auto_increment_offset= default; --enable_ps2_protocol diff --git a/mysql-test/suite/sql_sequence/next.result b/mysql-test/suite/sql_sequence/next.result index a032479e2d4..7b715b8ce6a 100644 --- a/mysql-test/suite/sql_sequence/next.result +++ b/mysql-test/suite/sql_sequence/next.result @@ -826,7 +826,6 @@ alter sequence t1 cycle; select next value for t1; next value for t1 4294967294 -call mtr.add_suppression("signed integer overflow: -9223372036854775807 \\+ -1000 cannot be represented in type 'long long int'"); create or replace sequence t1 as bigint start with -9223372036854775807 increment -1; select next value for t1; next value for t1 diff --git a/mysql-test/suite/sql_sequence/next.test b/mysql-test/suite/sql_sequence/next.test index 649fe2224e4..fab35dd3e7c 100644 --- a/mysql-test/suite/sql_sequence/next.test +++ b/mysql-test/suite/sql_sequence/next.test @@ -462,12 +462,8 @@ select next value for t1; alter sequence t1 cycle; select next value for t1; -# This overflow caused by the first disjunction bleow is unavoidable and -# taken care of by the second disjunction: -# if (value + increment < min_value || value < min_value - increment) -call mtr.add_suppression("signed integer overflow: -9223372036854775807 \\+ -1000 cannot be represented in type 'long long int'"); - create or replace sequence t1 as bigint start with -9223372036854775807 increment -1; + select next value for t1; --error ER_SEQUENCE_RUN_OUT select next value for t1; diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc index ec77a7abbe7..19715ad97fd 100644 --- a/sql/sql_sequence.cc +++ b/sql/sql_sequence.cc @@ -743,8 +743,11 @@ void sequence_definition::adjust_values(longlong next_value) global_system_variables.auto_increment_increment); /* - Ensure that next_free_value has the right offset, so that we - can generate a serie by just adding real_increment. + Ensure that next_free_value has the right offset, so that we can + generate a serie by just adding real_increment. The goal is to + adjust next_free_value upwards such that + + next_free_value % real_increment == offset */ off= next_free_value % real_increment; if (off < 0) @@ -760,15 +763,18 @@ void sequence_definition::adjust_values(longlong next_value) need to cast to_add. */ if ((is_unsigned && - (ulonglong) next_free_value > (ulonglong) max_value - to_add) || - (is_unsigned && - (ulonglong) next_free_value + to_add > (ulonglong) max_value) || - (!is_unsigned && next_free_value > max_value - to_add) || - (!is_unsigned && next_free_value + to_add > max_value)) + ((ulonglong) next_free_value > (ulonglong) max_value - to_add || + (ulonglong) next_free_value + to_add > (ulonglong) max_value || + (ulonglong) next_free_value > (ulonglong) max_value)) || + (!is_unsigned && + (next_free_value > (longlong) ((ulonglong) max_value - to_add) || + (longlong) ((ulonglong) next_free_value + to_add) > max_value || + next_free_value > max_value))) next_free_value= max_value+1; else { - next_free_value+= to_add; + next_free_value= + (longlong) ((ulonglong) next_free_value + (ulonglong) to_add); if (is_unsigned) DBUG_ASSERT((ulonglong) next_free_value % real_increment == (ulonglong) offset); @@ -898,7 +904,7 @@ longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error) next_free_value= increment_value(next_free_value, real_increment); if (within_bound(res_value, reserved_until, reserved_until, - real_increment > 0)) + real_increment > 0)) { write_unlock(table); DBUG_RETURN(res_value); diff --git a/sql/sql_sequence.h b/sql/sql_sequence.h index 1306f0f0982..7e916d7776e 100644 --- a/sql/sql_sequence.h +++ b/sql/sql_sequence.h @@ -205,32 +205,48 @@ private: (ulonglong) max_value - (ulonglong) increment || /* in case max_value - increment underflows */ (ulonglong) value + (ulonglong) increment > - (ulonglong) max_value) - value= max_value + 1; + (ulonglong) max_value || + /* in case both overflow and underflow happens (very + rarely, if not impossible) */ + (ulonglong) value > (ulonglong) max_value) + /* Cast to ulonglong then back, in case max_value == + LONGLONG_MAX as a ulonglong */ + value= (longlong) ((ulonglong) max_value + 1); else - value+= increment; + value = (longlong) ((ulonglong) value + (ulonglong) increment); } else { if ((ulonglong) value - (ulonglong) (-increment) < (ulonglong) min_value || (ulonglong) value < - (ulonglong) min_value + (ulonglong) (-increment)) - value= min_value - 1; + (ulonglong) min_value + (ulonglong) (-increment) || + (ulonglong) value < (ulonglong) min_value) + /* Cast to ulonglong then back, in case min_value == + LONGLONG_MAX + 1 as a ulonglong */ + value= (longlong) ((ulonglong) min_value - 1); else - value+= increment; + value = (longlong) ((ulonglong) value - (ulonglong) (-increment)); } } else if (increment > 0) { - if (value > max_value - increment || value + increment > max_value) + if (value > + (longlong) ((ulonglong) max_value - (ulonglong) increment) || + (longlong) ((ulonglong) value + (ulonglong) increment) > + max_value || + value > max_value) value= max_value + 1; else value+= increment; } else { - if (value <= min_value || value + increment < min_value) + if ((longlong) ((ulonglong) value + (ulonglong) increment) < + min_value || + value < + (longlong) ((ulonglong) min_value - (ulonglong) increment) || + value < min_value) value= min_value - 1; else value+= increment;