mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
7bec41d25d
We add an extra condition that makes the inequality testing in SEQUENCE::increment_value() mathematically watertight, and we cast to and from unsigned in potential underflow and overflow addition and subtractions to avoid undefined behaviour. Let's start by distinguishing between c++ expressions and mathematical expressions. by c++ expression I mean an expression with the outcome determined by the compiler/runtime. by mathematical expression I mean an expression whose value is mathematically determined. So a c++ expression -9223372036854775806 - 1000 at worst can evaluate to any value due to underflow. A mathematical expression -9223372036854775806 - 1000 evaluates to -9223372036854776806. The problem boils down to how to write a c++ expression equivalent to an mathematical expression x + y < z where x and z can take any values of long long int, and y < 0 is also a long long int. Ideally we want to avoid underflow, but I'm not sure how this can be done. The correct c++ form should be (x + y < z || x < z - y || x < z). Let M=9223372036854775808 i.e. LONGLONG_MAX + 1. We have -M < x < M - 1 -M < y < 0 -M < z < M - 1 Let's consider the case where x + y < z is true as a mathematical expression. If the first disjunct underflows, i.e. the mathematical expression x + y < -M. If the arbitrary value resulting from the underflow causes the c++ expression to hold too, then we are done. Otherwise we move onto the next expression x < z - y. If there's no overflow in z - y then we are done. If there's overflow i.e. z - y > M - 1, and the c++ expression evals to false, then we are onto x < z. There's no over or underflow here, and it will eval to true. To see this, note that x + y < -M means x < -M - y < -M - (-M) = 0 z - y > M - 1 means z > y + M - 1 > - M + M - 1 = -1 so x < z. Now let's consider the case where x + y < z is false as a mathematical expression. The first disjunct will not underflow in this case, so we move to (x < z - y). This will not overflow. To see this, note that x + y >= z means z - y <= x < M - 1 So it evals to false too. And the third disjunct x < z also evals to false because x >= z - y > z. I suspect that in either case the expression x < z does not determine the final value of the disjunction in the vast majority cases, which is why we leave it as the final one in case of the rare cases of both an underflow and an overflow happening. Here's an example of both underflow and overflow happening and the added inequality x < z saves the day: x = - M / 2 y = - M / 2 - 1 z = M / 2 x + y evals to M - 1 which is > z z - y evals to - M + 1 which is < x We can do the same to test x + y > z where the increment y is positive: (x > z - y || x + y > z || x > z) And the same analysis applies to unsigned cases.
484 lines
13 KiB
Text
484 lines
13 KiB
Text
--source include/have_sequence.inc
|
|
--source include/have_innodb.inc
|
|
|
|
#
|
|
# Test sequence generation
|
|
#
|
|
|
|
--disable_ps2_protocol
|
|
CREATE SEQUENCE t1 start with 1 minvalue 1 maxvalue 10 increment by 1 cache 2 cycle;
|
|
show create table t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
|
|
select NEXT VALUE for t1,seq from seq_1_to_20;
|
|
|
|
drop sequence t1;
|
|
|
|
CREATE SEQUENCE t1 minvalue 1 maxvalue 10 increment by -1 cache 2 cycle engine=aria;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
select next value for t1;
|
|
select next_not_cached_value,cycle_count from t1;
|
|
|
|
select NEXT VALUE for t1,seq from seq_1_to_20;
|
|
|
|
drop sequence t1;
|
|
|
|
CREATE SEQUENCE t1 start with 8 minvalue 1 maxvalue 10 increment by 1 cache 2 nocycle;
|
|
select next value for t1;
|
|
select next value for t1;
|
|
select next value for t1;
|
|
select previous value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
select previous value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
drop sequence t1;
|
|
|
|
create sequence s1 start with 1 cache 2 maxvalue 5;
|
|
select next value for s1;
|
|
select next value for s1;
|
|
select next value for s1;
|
|
select next value for s1;
|
|
select next value for s1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for s1;
|
|
drop sequence s1;
|
|
|
|
#
|
|
# Test that flush tables jumps to next next_not_cached_value
|
|
#
|
|
|
|
CREATE SEQUENCE t1 start with 1 minvalue 1 maxvalue 100 increment by 1 cache 10;
|
|
select next value for t1;
|
|
select * from t1;
|
|
flush tables;
|
|
select next value for t1;
|
|
select nextval(t1);
|
|
drop sequence t1;
|
|
|
|
#
|
|
# Test currval/previous
|
|
#
|
|
|
|
CREATE SEQUENCE t9 start with 1 minvalue 1 maxvalue 10 increment by 1 cache 5 cycle;
|
|
select previous value for t9;
|
|
select next value for t9;
|
|
select previous value for t9, lastval(t9);
|
|
select next value for t9;
|
|
select previous value for t9, lastval(t9);
|
|
select seq, previous value for t9, NEXT VALUE for t9, previous value for t9 from seq_1_to_20;
|
|
select * from t9;
|
|
drop sequence t9;
|
|
|
|
#
|
|
# CACHE = 0 should be same as CACHE = 1
|
|
#
|
|
CREATE SEQUENCE s1 cache=0;
|
|
select * from s1;
|
|
select next value for s1;
|
|
select next_not_cached_value from s1;
|
|
select next value for s1;
|
|
select next_not_cached_value from s1;
|
|
DROP SEQUENCE s1;
|
|
CREATE SEQUENCE s1 cache=1;
|
|
select next_not_cached_value from s1;
|
|
select next value for s1;
|
|
select next_not_cached_value from s1;
|
|
select next value for s1;
|
|
select next_not_cached_value from s1;
|
|
DROP SEQUENCE s1;
|
|
CREATE SEQUENCE s1 cache=2;
|
|
select next_not_cached_value from s1;
|
|
select next value for s1;
|
|
select next_not_cached_value from s1;
|
|
select next value for s1;
|
|
select next_not_cached_value from s1;
|
|
DROP SEQUENCE s1;
|
|
|
|
#
|
|
# Negative increment for sequence
|
|
#
|
|
|
|
CREATE SEQUENCE s1;
|
|
select next value for s1;
|
|
select next value for s1;
|
|
select next value for s1;
|
|
select next value for s1;
|
|
alter sequence s1 increment -2;
|
|
select * from s1;
|
|
select next value for s1;
|
|
select next value for s1;
|
|
alter sequence s1 restart 6;
|
|
select next value for s1;
|
|
select next value for s1;
|
|
select next value for s1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for s1;
|
|
DROP SEQUENCE s1;
|
|
|
|
#
|
|
# Check what happens when one refers to a sequence that has been closed/deleted
|
|
#
|
|
|
|
CREATE SEQUENCE t1 start with 1 minvalue 1 maxvalue 10 increment by 1 cache 5 cycle;
|
|
select next value for t1;
|
|
select previous value for t1;
|
|
flush tables;
|
|
select previous value for t1;
|
|
drop sequence t1;
|
|
--error ER_UNKNOWN_SEQUENCES
|
|
select previous value for t1;
|
|
CREATE SEQUENCE t1 start with 5 minvalue 1 maxvalue 10 increment by 1 cache 5 cycle;
|
|
select previous value for t1;
|
|
select next value for t1;
|
|
select previous value for t1;
|
|
drop sequence t1;
|
|
|
|
# This failed in an early build
|
|
|
|
CREATE or replace SEQUENCE s1 MINVALUE 1 MAXVALUE 9999999999
|
|
INCREMENT BY 1 START WITH 3984356 CACHE 20 CYCLE engine=innodb;
|
|
show create table s1;
|
|
select * from s1;
|
|
select NEXT VALUE FOR s1;
|
|
select NEXT VALUE FOR s1;
|
|
select NEXT VALUE FOR s1;
|
|
select * from s1;
|
|
FLUSH TABLES;
|
|
select * from s1;
|
|
select NEXT VALUE FOR s1;
|
|
select * from s1;
|
|
drop sequence s1;
|
|
|
|
#
|
|
# Explain
|
|
#
|
|
|
|
CREATE SEQUENCE t1 start with 5 minvalue 1 maxvalue 10 increment by 1 cache 5 cycle;
|
|
explain select next value for t1;
|
|
explain select next value for t1, minimum_value from t1;
|
|
drop table t1;
|
|
|
|
#
|
|
# Using insert with NEXT VALUE
|
|
#
|
|
|
|
CREATE SEQUENCE s1;
|
|
CREATE TABLE t1 (a int);
|
|
insert into t1 values (next value for s1);
|
|
insert into t1 values (next value for s1);
|
|
select * from t1;
|
|
drop table t1,s1;
|
|
|
|
#
|
|
# Using update with NEXT VALUE
|
|
#
|
|
|
|
CREATE SEQUENCE s1;
|
|
CREATE TABLE t1 (a int primary key auto_increment, b int default 0) engine=myisam;
|
|
insert into t1 values (),(),(),(),(),(),();
|
|
update t1 set b= next value for s1 where a <= 3;
|
|
select * from t1;
|
|
drop table t1,s1;
|
|
|
|
#
|
|
# NO CACHE and InnoDB
|
|
#
|
|
|
|
CREATE OR REPLACE SEQUENCE s1 MINVALUE 1 MAXVALUE 9999999999 INCREMENT BY 1 START WITH 3984356 nocache CYCLE engine='innodb';
|
|
select * from s1;
|
|
select next value for s1;
|
|
explain extended select next value for s1;
|
|
explain extended select previous value for s1;
|
|
drop sequence s1;
|
|
|
|
#
|
|
# Some error testing
|
|
#
|
|
|
|
create table t1 (a int);
|
|
--error ER_NOT_SEQUENCE
|
|
select next value for t1;
|
|
drop table t1;
|
|
|
|
create sequence t1;
|
|
select next value for t1;
|
|
--error ER_BAD_FIELD_ERROR
|
|
select next value for t1, minimum_value;
|
|
drop sequence t1;
|
|
|
|
--echo #
|
|
--echo # MDEV-12854 Synchronize CREATE..SELECT data type and result set metadata data type for INT functions
|
|
--echo #
|
|
|
|
--enable_metadata
|
|
--disable_ps_protocol
|
|
CREATE SEQUENCE s1;
|
|
SELECT
|
|
NEXT VALUE FOR s1,
|
|
PREVIOUS VALUE FOR s1;
|
|
DROP SEQUENCE s1;
|
|
--enable_ps_protocol
|
|
--disable_metadata
|
|
|
|
--echo #
|
|
--echo # MDEV-13720 ER_NOT_SEQUENCE for temporary table
|
|
--echo #
|
|
|
|
create temporary table tmp (i int);
|
|
--error ER_NOT_SEQUENCE
|
|
select next value for tmp;
|
|
drop table tmp;
|
|
|
|
--echo #
|
|
--echo # Test negative numbers
|
|
--echo #
|
|
|
|
create sequence s start with 1 minvalue=-1000 maxvalue=1000 increment -1;
|
|
select next value for s;
|
|
select next value for s;
|
|
flush tables;
|
|
select next value for s;
|
|
drop sequence s;
|
|
|
|
--echo #
|
|
--echo # MDEV-23823 NEXT VALUE crash on locked view
|
|
--echo #
|
|
CREATE VIEW v AS SELECT 1;
|
|
LOCK TABLE v READ;
|
|
--error ER_NOT_SEQUENCE
|
|
SELECT NEXT VALUE FOR v;
|
|
|
|
--echo #
|
|
--echo # MDEV-24018: SIGSEGV in Item_func_nextval::update_table on SELECT SETVAL
|
|
--echo #
|
|
--error ER_NOT_SEQUENCE
|
|
SELECT SETVAL (v,0);
|
|
|
|
UNLOCK TABLES;
|
|
DROP VIEW v;
|
|
|
|
--echo #
|
|
--echo # MDEV-28152 Features for sequence
|
|
--echo #
|
|
|
|
create or replace sequence t1 as tinyint unsigned minvalue 1 maxvalue 2;
|
|
show create sequence t1;
|
|
show create table t1;
|
|
select * from t1;
|
|
select next value for t1;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as tinyint unsigned minvalue 1 maxvalue 2 cycle;
|
|
show create sequence t1;
|
|
show create table t1;
|
|
select * from t1;
|
|
select next value for t1;
|
|
select next value for t1;
|
|
select next value for t1;
|
|
|
|
--disable_ps_protocol
|
|
create or replace sequence t1 minvalue -23 maxvalue 99999 as tinyint;
|
|
--enable_ps_protocol
|
|
show create sequence t1;
|
|
show create table t1;
|
|
select * from t1;
|
|
select next value for t1;
|
|
select next value for t1;
|
|
select next value for t1;
|
|
|
|
#test previous value for bigint unsigned
|
|
create or replace sequence t1 as bigint unsigned start with 18446744073709551614;
|
|
select previous value for t1;
|
|
select next value for t1;
|
|
select previous value for t1;
|
|
|
|
create or replace sequence t1 as tinyint start with 126;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as tinyint unsigned start with 254;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as smallint start with 32766;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as smallint unsigned start with 65534;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as mediumint start with 8388606;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as mediumint unsigned start with 16777214;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as int start with 2147483646;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as int unsigned start with 4294967294;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as bigint start with 9223372036854775806;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as bigint unsigned start with 18446744073709551614;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as tinyint start with -127 increment -1;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as tinyint unsigned start with 1 increment -1;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as smallint start with -32767 increment -1;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as smallint unsigned start with 1 increment -1;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as mediumint start with -8388607 increment -1;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as mediumint unsigned start with 1 increment -1;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as int start with -2147483647 increment -1;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as int unsigned start with 1 increment -1;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
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;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
create or replace sequence t1 as bigint unsigned start with 1 increment -1;
|
|
select next value for t1;
|
|
--error ER_SEQUENCE_RUN_OUT
|
|
select next value for t1;
|
|
alter sequence t1 cycle;
|
|
select next value for t1;
|
|
|
|
drop sequence t1;
|
|
|
|
--echo #
|
|
--echo # End of 11.4 tests
|
|
--echo #
|