Commit 84675ed9 authored by Yuchen Pei's avatar Yuchen Pei

MDEV-28152 Create sequence truncating out-of-bound max/minvalue

This is item 2 of MDEV-28152. When creating a sequence with a huge
minvalue / maxvalue, truncate it to the nearest valid value for the
type, i.e. LONGLONG_MAX - 1 for values >= LONGLONG_MAX and
LONGLONG_MIN + 1 for values <= LONGLONG_MIN
parent ce4a289f
......@@ -143,6 +143,66 @@ t1 CREATE SEQUENCE `t1` start with 10 minvalue -10 maxvalue 11 increment by 10 c
select * from t1;
next_not_cached_value minimum_value maximum_value start_value increment cache_size cycle_option cycle_count
10 -10 11 10 10 10 1 0
create or replace sequence t1 minvalue -999999999999999999999;
Warnings:
Note 1292 Truncated incorrect INTEGER value: 'MINVALUE'
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with -9223372036854775807 minvalue -9223372036854775807 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM
create or replace sequence t1 minvalue -9223372036854775808;
Warnings:
Note 1292 Truncated incorrect INTEGER value: 'MINVALUE'
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with -9223372036854775807 minvalue -9223372036854775807 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM
create or replace sequence t1 minvalue -9223372036854775807;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with -9223372036854775807 minvalue -9223372036854775807 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM
create or replace sequence t1 minvalue 9223372036854775805;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 9223372036854775805 minvalue 9223372036854775805 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM
create or replace sequence t1 minvalue 9223372036854775806;
ERROR HY000: Sequence 'test.t1' has out of range value for options
create or replace sequence t1 minvalue 9223372036854775807;
ERROR HY000: Sequence 'test.t1' has out of range value for options
create or replace sequence t1 minvalue 9223372036854775808;
ERROR HY000: Sequence 'test.t1' has out of range value for options
create or replace sequence t1 minvalue 9999999999999999999999;
ERROR HY000: Sequence 'test.t1' has out of range value for options
create or replace sequence t1 maxvalue -999999999999999999999 increment by -1;
ERROR HY000: Sequence 'test.t1' has out of range value for options
create or replace sequence t1 maxvalue -9223372036854775808 increment by -1;
ERROR HY000: Sequence 'test.t1' has out of range value for options
create or replace sequence t1 maxvalue -9223372036854775807 increment by -1;
ERROR HY000: Sequence 'test.t1' has out of range value for options
create or replace sequence t1 maxvalue -9223372036854775806 increment by -1;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with -9223372036854775806 minvalue -9223372036854775807 maxvalue -9223372036854775806 increment by -1 cache 1000 nocycle ENGINE=MyISAM
create or replace sequence t1 maxvalue 9223372036854775806;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM
create or replace sequence t1 maxvalue 9223372036854775807;
Warnings:
Note 1292 Truncated incorrect INTEGER value: 'MAXVALUE'
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM
create or replace sequence t1 maxvalue 9223372036854775808;
Warnings:
Note 1292 Truncated incorrect INTEGER value: 'MAXVALUE'
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM
create or replace sequence t1 maxvalue 9999999999999999999999;
Warnings:
Note 1292 Truncated incorrect INTEGER value: 'MAXVALUE'
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM
create or replace sequence t1 start with 10 NO MAXVALUE NO MINVALUE;
create or replace sequence t1 start with 10 maxvalue 10;
create or replace sequence t1 start with 10 minvalue 10;
......@@ -182,15 +242,11 @@ create or replace sequence t1 start with 10 min_value=1 NO MINVALUE;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NO MINVALUE' at line 1
create or replace sequence t1 start with 10 min_value=1 NO MINVALUE;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NO MINVALUE' at line 1
create sequence t1 start with 10 maxvalue=9223372036854775807;
ERROR HY000: Sequence 'test.t1' has out of range value for options
create sequence t1 start with 10 minvalue=-9223372036854775808;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '9223372036854775808' at line 1
create sequence t1 RESTART WITH 10;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'RESTART' at line 1
create or replace sequence t1 start with 10 NO MINVALUE minvalue=1;
drop sequence t1;
create sequence t1;
ERROR HY000: Option 'MINVALUE' used twice in statement
create or replace sequence t1;
show fields from t1;
Field Type Null Key Default Extra
next_not_cached_value bigint(21) NO NULL
......
......@@ -71,6 +71,41 @@ create or replace sequence t1 start with 10 minvalue=-10 maxvalue=11 cache=10 cy
show create sequence t1;
select * from t1;
# Truncating out-of-bound numbers for minvalue and maxvalue
create or replace sequence t1 minvalue -999999999999999999999;
show create sequence t1;
create or replace sequence t1 minvalue -9223372036854775808;
show create sequence t1;
create or replace sequence t1 minvalue -9223372036854775807;
show create sequence t1;
create or replace sequence t1 minvalue 9223372036854775805;
show create sequence t1;
--error ER_SEQUENCE_INVALID_DATA
create or replace sequence t1 minvalue 9223372036854775806;
--error ER_SEQUENCE_INVALID_DATA
create or replace sequence t1 minvalue 9223372036854775807;
--error ER_SEQUENCE_INVALID_DATA
create or replace sequence t1 minvalue 9223372036854775808;
--error ER_SEQUENCE_INVALID_DATA
create or replace sequence t1 minvalue 9999999999999999999999;
--error ER_SEQUENCE_INVALID_DATA
create or replace sequence t1 maxvalue -999999999999999999999 increment by -1;
--error ER_SEQUENCE_INVALID_DATA
create or replace sequence t1 maxvalue -9223372036854775808 increment by -1;
--error ER_SEQUENCE_INVALID_DATA
create or replace sequence t1 maxvalue -9223372036854775807 increment by -1;
create or replace sequence t1 maxvalue -9223372036854775806 increment by -1;
show create sequence t1;
create or replace sequence t1 maxvalue 9223372036854775806;
show create sequence t1;
create or replace sequence t1 maxvalue 9223372036854775807;
show create sequence t1;
create or replace sequence t1 maxvalue 9223372036854775808;
show create sequence t1;
create or replace sequence t1 maxvalue 9999999999999999999999;
show create sequence t1;
# NO MINVALUE, NO MAXVALUE
create or replace sequence t1 start with 10 NO MAXVALUE NO MINVALUE;
......@@ -114,21 +149,15 @@ create or replace sequence t1 maxvalue=13, increment= -1;
create or replace sequence t1 start with 10 min_value=1 NO MINVALUE;
--error ER_PARSE_ERROR
create or replace sequence t1 start with 10 min_value=1 NO MINVALUE;
--error ER_SEQUENCE_INVALID_DATA
create sequence t1 start with 10 maxvalue=9223372036854775807;
--error ER_PARSE_ERROR
create sequence t1 start with 10 minvalue=-9223372036854775808;
--error ER_PARSE_ERROR
create sequence t1 RESTART WITH 10;
# This should probably give an error
--error ER_DUP_ARGUMENT
create or replace sequence t1 start with 10 NO MINVALUE minvalue=1;
drop sequence t1;
#
# Test with LIST COLUMNS as first command
#
create sequence t1;
create or replace sequence t1;
show fields from t1;
flush tables;
show fields from t1;
......
......@@ -227,7 +227,7 @@ int ha_sequence::write_row(const uchar *buf)
int error= 0;
/* This is called from alter table */
tmp_seq.read_fields(table);
if (tmp_seq.check_and_adjust(0))
if (tmp_seq.check_and_adjust(thd, 0))
DBUG_RETURN(HA_ERR_SEQUENCE_INVALID_DATA);
sequence->copy(&tmp_seq);
if (likely(!(error= file->write_row(buf))))
......@@ -258,7 +258,7 @@ int ha_sequence::write_row(const uchar *buf)
DBUG_RETURN(ER_LOCK_WAIT_TIMEOUT);
tmp_seq.read_fields(table);
if (tmp_seq.check_and_adjust(0))
if (tmp_seq.check_and_adjust(thd, 0))
DBUG_RETURN(HA_ERR_SEQUENCE_INVALID_DATA);
/*
......
......@@ -82,7 +82,7 @@ static Field_definition sequence_structure[]=
true invalid
*/
bool sequence_definition::check_and_adjust(bool set_reserved_until)
bool sequence_definition::check_and_adjust(THD *thd, bool set_reserved_until)
{
longlong max_increment;
DBUG_ENTER("sequence_definition::check");
......@@ -104,6 +104,22 @@ bool sequence_definition::check_and_adjust(bool set_reserved_until)
if (!(used_fields & seq_field_used_max_value))
max_value= real_increment < 0 ? -1 : LONGLONG_MAX-1;
if (max_value == LONGLONG_MAX)
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_TRUNCATED_WRONG_VALUE,
ER_THD(thd, ER_TRUNCATED_WRONG_VALUE),
"INTEGER", "MAXVALUE");
max_value= LONGLONG_MAX - 1;
}
if (min_value == LONGLONG_MIN)
{
push_warning_printf(
thd, Sql_condition::WARN_LEVEL_NOTE, ER_TRUNCATED_WRONG_VALUE,
ER_THD(thd, ER_TRUNCATED_WRONG_VALUE), "INTEGER", "MINVALUE");
min_value= LONGLONG_MIN + 1;
}
if (!(used_fields & seq_field_used_start))
{
/* Use min_value or max_value for start depending on real_increment */
......@@ -993,7 +1009,7 @@ bool Sql_cmd_alter_sequence::execute(THD *thd)
/* Let check_and_adjust think all fields are used */
new_seq->used_fields= ~0;
if (new_seq->check_and_adjust(0))
if (new_seq->check_and_adjust(thd, 0))
{
my_error(ER_SEQUENCE_INVALID_DATA, MYF(0),
first_table->db.str,
......
......@@ -53,7 +53,7 @@ class sequence_definition :public Sql_alloc
bool cycle;
uint used_fields; // Which fields where used in CREATE
bool check_and_adjust(bool set_reserved_until);
bool check_and_adjust(THD *thd, bool set_reserved_until);
void store_fields(TABLE *table);
void read_fields(TABLE *table);
int write_initial_sequence(TABLE *table);
......
......@@ -198,6 +198,7 @@ void _CONCAT_UNDERSCORED(turn_parser_debug_on,yyparse)()
int num;
ulong ulong_num;
ulonglong ulonglong_number;
ulonglong minus_ulonglong_number;
longlong longlong_number;
uint sp_instr_addr;
......@@ -345,9 +346,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
*/
%ifdef MARIADB
%expect 82
%expect 84
%else
%expect 83
%expect 85
%endif
/*
......@@ -1465,6 +1466,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <ulonglong_number>
ulonglong_num real_ulonglong_num
%type <minus_ulonglong_number>
minus_ulonglong_num
%type <longlong_number>
longlong_num
......@@ -2419,7 +2423,7 @@ create:
{
LEX *lex= thd->lex;
if (unlikely(lex->create_info.seq_create_info->check_and_adjust(1)))
if (unlikely(lex->create_info.seq_create_info->check_and_adjust(thd, 1)))
{
my_error(ER_SEQUENCE_INVALID_DATA, MYF(0),
lex->first_select_lex()->table_list.first->db.str,
......@@ -2605,9 +2609,42 @@ sequence_defs:
;
sequence_def:
MINVALUE_SYM opt_equal longlong_num
MINVALUE_SYM opt_equal ulonglong_num
{
if (unlikely(Lex->create_info.seq_create_info->used_fields &
seq_field_used_min_value))
my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MINVALUE"));
if ($3 > (ulonglong) LONGLONG_MAX)
Lex->create_info.seq_create_info->min_value= LONGLONG_MAX;
else
Lex->create_info.seq_create_info->min_value= (longlong) $3;
Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value;
}
| MINVALUE_SYM opt_equal minus_ulonglong_num
{
Lex->create_info.seq_create_info->min_value= $3;
if (unlikely(Lex->create_info.seq_create_info->used_fields &
seq_field_used_min_value))
my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MINVALUE"));
if ($3 > (ulonglong) LONGLONG_MAX)
Lex->create_info.seq_create_info->min_value= LONGLONG_MIN;
else
Lex->create_info.seq_create_info->min_value= - (longlong) $3;
Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value;
}
| MINVALUE_SYM opt_equal DECIMAL_NUM
{
if (unlikely(Lex->create_info.seq_create_info->used_fields &
seq_field_used_min_value))
my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MINVALUE"));
Lex->create_info.seq_create_info->min_value= LONGLONG_MAX;
Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value;
}
| MINVALUE_SYM opt_equal '-' DECIMAL_NUM
{
if (unlikely(Lex->create_info.seq_create_info->used_fields &
seq_field_used_min_value))
my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MINVALUE"));
Lex->create_info.seq_create_info->min_value= LONGLONG_MIN;
Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value;
}
| NO_SYM MINVALUE_SYM
......@@ -2622,12 +2659,42 @@ sequence_def:
my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MINVALUE"));
Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value;
}
| MAXVALUE_SYM opt_equal longlong_num
| MAXVALUE_SYM opt_equal ulonglong_num
{
if (unlikely(Lex->create_info.seq_create_info->used_fields &
seq_field_used_max_value))
if (unlikely(Lex->create_info.seq_create_info->used_fields &
seq_field_used_max_value))
my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MAXVALUE"));
Lex->create_info.seq_create_info->max_value= $3;
if ($3 > (ulonglong) LONGLONG_MAX)
Lex->create_info.seq_create_info->max_value= LONGLONG_MAX;
else
Lex->create_info.seq_create_info->max_value= (longlong) $3;
Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value;
}
| MAXVALUE_SYM opt_equal minus_ulonglong_num
{
if (unlikely(Lex->create_info.seq_create_info->used_fields &
seq_field_used_max_value))
my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MAXVALUE"));
if ($3 > (ulonglong) LONGLONG_MAX)
Lex->create_info.seq_create_info->max_value= LONGLONG_MIN;
else
Lex->create_info.seq_create_info->max_value= - (longlong) $3;
Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value;
}
| MAXVALUE_SYM opt_equal DECIMAL_NUM
{
if (unlikely(Lex->create_info.seq_create_info->used_fields &
seq_field_used_max_value))
my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MAXVALUE"));
Lex->create_info.seq_create_info->max_value= LONGLONG_MAX;
Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value;
}
| MAXVALUE_SYM opt_equal '-' DECIMAL_NUM
{
if (unlikely(Lex->create_info.seq_create_info->used_fields &
seq_field_used_max_value))
my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MAXVALUE"));
Lex->create_info.seq_create_info->max_value= LONGLONG_MIN;
Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value;
}
| NO_SYM MAXVALUE_SYM
......@@ -12575,6 +12642,12 @@ ulonglong_num:
| opt_plus FLOAT_NUM { int error; $$= (ulonglong) my_strtoll10($2.str, (char**) 0, &error); }
;
minus_ulonglong_num:
'-' NUM { int error; $$= (ulonglong) my_strtoll10($2.str, (char**) 0, &error); }
| '-' ULONGLONG_NUM { int error; $$= (ulonglong) my_strtoll10($2.str, (char**) 0, &error); }
| '-' LONG_NUM { int error; $$= (ulonglong) my_strtoll10($2.str, (char**) 0, &error); }
;
real_ulonglong_num:
NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
| ULONGLONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
......
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