Commit f69ea459 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);
......
......@@ -1466,7 +1466,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
ulonglong_num real_ulonglong_num
%type <longlong_number>
longlong_num
sequence_value_num sequence_truncated_value_num
%type <choice> choice
......@@ -2419,7 +2419,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,8 +2605,11 @@ sequence_defs:
;
sequence_def:
MINVALUE_SYM opt_equal longlong_num
MINVALUE_SYM opt_equal sequence_truncated_value_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= $3;
Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value;
}
......@@ -2622,10 +2625,10 @@ 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 sequence_truncated_value_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;
Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value;
......@@ -2642,7 +2645,7 @@ sequence_def:
my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MAXVALUE"));
Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value;
}
| START_SYM opt_with longlong_num
| START_SYM opt_with sequence_value_num
{
if (unlikely(Lex->create_info.seq_create_info->used_fields &
seq_field_used_start))
......@@ -2650,7 +2653,7 @@ sequence_def:
Lex->create_info.seq_create_info->start= $3;
Lex->create_info.seq_create_info->used_fields|= seq_field_used_start;
}
| INCREMENT_SYM opt_by longlong_num
| INCREMENT_SYM opt_by sequence_value_num
{
if (unlikely(Lex->create_info.seq_create_info->used_fields &
seq_field_used_increment))
......@@ -2658,7 +2661,7 @@ sequence_def:
Lex->create_info.seq_create_info->increment= $3;
Lex->create_info.seq_create_info->used_fields|= seq_field_used_increment;
}
| CACHE_SYM opt_equal longlong_num
| CACHE_SYM opt_equal sequence_value_num
{
if (unlikely(Lex->create_info.seq_create_info->used_fields &
seq_field_used_cache))
......@@ -2702,7 +2705,7 @@ sequence_def:
my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "RESTART"));
Lex->create_info.seq_create_info->used_fields|= seq_field_used_restart;
}
| RESTART_SYM opt_with longlong_num
| RESTART_SYM opt_with sequence_value_num
{
if (unlikely(Lex->sql_command != SQLCOM_ALTER_SEQUENCE))
{
......@@ -9728,17 +9731,17 @@ column_default_non_parenthesized_expr:
if (unlikely(!($$= Lex->create_item_func_lastval(thd, $3))))
MYSQL_YYABORT;
}
| SETVAL_SYM '(' table_ident ',' longlong_num ')'
| SETVAL_SYM '(' table_ident ',' sequence_value_num ')'
{
if (unlikely(!($$= Lex->create_item_func_setval(thd, $3, $5, 0, 1))))
MYSQL_YYABORT;
}
| SETVAL_SYM '(' table_ident ',' longlong_num ',' bool ')'
| SETVAL_SYM '(' table_ident ',' sequence_value_num ',' bool ')'
{
if (unlikely(!($$= Lex->create_item_func_setval(thd, $3, $5, 0, $7))))
MYSQL_YYABORT;
}
| SETVAL_SYM '(' table_ident ',' longlong_num ',' bool ',' ulonglong_num ')'
| SETVAL_SYM '(' table_ident ',' sequence_value_num ',' bool ',' ulonglong_num ')'
{
if (unlikely(!($$= Lex->create_item_func_setval(thd, $3, $5, $9, $7))))
MYSQL_YYABORT;
......@@ -12560,11 +12563,31 @@ real_ulong_num:
| dec_num_error { MYSQL_YYABORT; }
;
longlong_num:
sequence_value_num:
opt_plus NUM { int error; $$= (longlong) my_strtoll10($2.str, (char**) 0, &error); }
| opt_plus LONG_NUM { int error; $$= (longlong) my_strtoll10($2.str, (char**) 0, &error); }
| '-' NUM { int error; $$= -(longlong) my_strtoll10($2.str, (char**) 0, &error); }
| '-' LONG_NUM { int error; $$= -(longlong) my_strtoll10($2.str, (char**) 0, &error); }
| '-' ULONGLONG_NUM
{
int error;
const ulonglong abs= my_strtoll10($2.str, (char**) 0, &error);
if (abs == 1 + (ulonglong) LONGLONG_MAX)
$$= LONGLONG_MIN;
else
thd->parse_error(ER_DATA_OUT_OF_RANGE);
}
;
sequence_truncated_value_num:
opt_plus NUM { int error; $$= (longlong) my_strtoll10($2.str, (char**) 0, &error); }
| LONG_NUM { int error; $$= (longlong) my_strtoll10($1.str, (char**) 0, &error); }
| opt_plus LONG_NUM { int error; $$= (longlong) my_strtoll10($2.str, (char**) 0, &error); }
| opt_plus ULONGLONG_NUM { $$= LONGLONG_MAX; }
| opt_plus DECIMAL_NUM { $$= LONGLONG_MAX; }
| '-' NUM { int error; $$= -(longlong) my_strtoll10($2.str, (char**) 0, &error); }
| '-' LONG_NUM { int error; $$= -(longlong) my_strtoll10($2.str, (char**) 0, &error); }
| '-' ULONGLONG_NUM { $$= LONGLONG_MIN; }
| '-' DECIMAL_NUM { $$= LONGLONG_MIN; }
;
ulonglong_num:
......
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