Skip to content

Commit d52ddae

Browse files
MDEV-22491 Support mariadb-check and CHECK TABLE with SEQUENCE
The check go through the following steps: 1. Run check on the underlying engine. If not ok, then return. 2. Check that there's only one row in the table, and 2.1 warn if more than one row 2.2 return HA_ADMIN_CORRUPT if fewer than one row (i.e. 0 rows) 3. If the sequence is not initialised (e.g. after an ALTER TABLE ... SEQUENCE=1), initialise the sequence by reading the sequence metadata from the table. This will also flush the next_free_value, i.e. set it to the next not cached value (SEQUENCE::reserved_until) 4. Check that the sequence metadata is valid, i.e. nothing out of order e.g. minvalue < maxvalue etc. If invalid it reports HA_ERR_SEQUENCE_INVALID_DATA 5. Check that the sequence has not been exhausted. It reports ER_SEQUENCE_RUN_OUT as a warning if and only if a SELECT NEXTVAL would do so Limitations: 1. The check is independent of flags, so the vanilla check is the same as CHECK ... EXTENDED or CHECK ... FOR UPGRADE etc. 2. When the check discovers invalid metadata from the table, subsequent SELECT NEXTVAL will carry on (or fail) without this piece of knowledge, independent of the CHECK. This is to ensure consistency, i.e. CHECK does not modify behaviour of SELECT, and if anything it makes more sense that SELECT reports HA_ERR_SEQUENCE_INVALID_DATA in this case, regardless of prior CHECK
1 parent 26ea37b commit d52ddae

File tree

10 files changed

+333
-12
lines changed

10 files changed

+333
-12
lines changed

mysql-test/suite/sql_sequence/aria.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ drop sequence t1;
3232
create sequence s1;
3333
check table s1;
3434
Table Op Msg_type Msg_text
35-
test.s1 checknote The storage engine for the table doesn't support check
35+
test.s1 checkstatus OK
3636
select next value for s1;
3737
next value for s1
3838
1
3939
flush tables;
4040
check table s1;
4141
Table Op Msg_type Msg_text
42-
test.s1 checknote The storage engine for the table doesn't support check
42+
test.s1 checkstatus OK
4343
select next value for s1;
4444
next value for s1
4545
1001

mysql-test/suite/sql_sequence/binlog.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Table Op Msg_type Msg_text
2323
test.s1 repair status OK
2424
check table s1;
2525
Table Op Msg_type Msg_text
26-
test.s1 checknote The storage engine for the table doesn't support check
26+
test.s1 checkstatus OK
2727
rename table s1 to tmp_s;
2828
rename table tmp_s to s1;
2929
drop sequence s1;
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
create sequence s;
2+
call mtr.add_suppression("ha_myisam");
3+
call mtr.add_suppression("Checking table");
4+
check table s;
5+
Table Op Msg_type Msg_text
6+
test.s check error Size of datafile is: 4 Should be: 58
7+
test.s check error Corrupt
8+
drop table s;
9+
create sequence s;
10+
insert into s values (3,1,9223372036854775806,1,1,1000,0,0);
11+
select * from s;
12+
next_not_cached_value minimum_value maximum_value start_value increment cache_size cycle_option cycle_count
13+
3 1 9223372036854775806 1 1 1000 0 0
14+
check table s;
15+
Table Op Msg_type Msg_text
16+
test.s check status OK
17+
select nextval(s);
18+
nextval(s)
19+
3
20+
drop sequence s;
21+
CREATE SEQUENCE s;
22+
ALTER TABLE s sequence=0;
23+
insert into s values (3,1,9223372036854775806,1,1,1000,0,0);
24+
FLUSH TABLES;
25+
CHECK TABLE s;
26+
Table Op Msg_type Msg_text
27+
test.s check Warning More than one row in the table
28+
test.s check status OK
29+
DROP SEQUENCE s;
30+
CREATE SEQUENCE s;
31+
ALTER TABLE s sequence=0;
32+
delete from s;
33+
FLUSH TABLES;
34+
CHECK TABLE s;
35+
Table Op Msg_type Msg_text
36+
test.s check Error Fewer than one row in the table
37+
test.s check error Corrupt
38+
DROP SEQUENCE s;
39+
CREATE SEQUENCE s;
40+
ALTER TABLE s sequence=0;
41+
update s set minimum_value=200, maximum_value=100;
42+
FLUSH TABLES;
43+
CHECK TABLE s;
44+
Table Op Msg_type Msg_text
45+
test.s check Error Sequence 'test.s' has out of range value for options
46+
test.s check error Corrupt
47+
DROP SEQUENCE s;
48+
create sequence s minvalue 13 maxvalue 15 increment by 4;
49+
check table s;
50+
Table Op Msg_type Msg_text
51+
test.s check status OK
52+
select nextval(s);
53+
nextval(s)
54+
13
55+
check table s;
56+
Table Op Msg_type Msg_text
57+
test.s check Warning Sequence 'test.s' has run out
58+
test.s check status OK
59+
alter sequence s cycle;
60+
check table s;
61+
Table Op Msg_type Msg_text
62+
test.s check status OK
63+
alter sequence s nocycle;
64+
check table s;
65+
Table Op Msg_type Msg_text
66+
test.s check Warning Sequence 'test.s' has run out
67+
test.s check status OK
68+
alter sequence s increment by 1;
69+
check table s;
70+
Table Op Msg_type Msg_text
71+
test.s check Warning Sequence 'test.s' has run out
72+
test.s check status OK
73+
alter sequence s increment by 4;
74+
select nextval(s);
75+
ERROR HY000: Sequence 'test.s' has run out
76+
alter sequence s cycle;
77+
check table s;
78+
Table Op Msg_type Msg_text
79+
test.s check status OK
80+
alter sequence s maxvalue 23 nocycle;
81+
check table s;
82+
Table Op Msg_type Msg_text
83+
test.s check status OK
84+
alter sequence s maxvalue 15;
85+
check table s;
86+
Table Op Msg_type Msg_text
87+
test.s check Warning Sequence 'test.s' has run out
88+
test.s check status OK
89+
drop sequence s;
90+
create sequence s minvalue 13 maxvalue 20 increment by 1;
91+
select nextval(s);
92+
nextval(s)
93+
13
94+
check table s;
95+
Table Op Msg_type Msg_text
96+
test.s check status OK
97+
select nextval(s);
98+
nextval(s)
99+
14
100+
drop sequence s;
101+
create sequence s minvalue 13 maxvalue 20 increment by 1;
102+
select nextval(s);
103+
nextval(s)
104+
13
105+
alter table s sequence=0;
106+
alter table s sequence=1;
107+
check table s;
108+
Table Op Msg_type Msg_text
109+
test.s check Warning Sequence 'test.s' has run out
110+
test.s check status OK
111+
select nextval(s);
112+
ERROR HY000: Sequence 'test.s' has run out
113+
drop sequence s;
114+
create sequence s;
115+
update s set minimum_value=500, maximum_value=200;
116+
ERROR HY000: Storage engine SEQUENCE of the table `test`.`s` doesn't have this option
117+
drop sequence s;
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
--source include/have_innodb.inc
2+
3+
# Check failure of underlying engine
4+
create sequence s;
5+
let $datadir= `select @@datadir`;
6+
remove_file $datadir/test/s.MYD;
7+
write_file $datadir/test/s.MYD;
8+
foo
9+
EOF
10+
call mtr.add_suppression("ha_myisam");
11+
call mtr.add_suppression("Checking table");
12+
check table s;
13+
drop table s;
14+
15+
# Insert a row into a sequence table updates that row
16+
create sequence s;
17+
insert into s values (3,1,9223372036854775806,1,1,1000,0,0);
18+
select * from s;
19+
# ok
20+
check table s;
21+
--disable_ps2_protocol
22+
select nextval(s);
23+
--enable_ps2_protocol
24+
drop sequence s;
25+
26+
# More than one row
27+
let $datadir=`select @@datadir`;
28+
CREATE SEQUENCE s;
29+
copy_file $datadir/test/s.frm $datadir/test/s1.frm;
30+
ALTER TABLE s sequence=0;
31+
insert into s values (3,1,9223372036854775806,1,1,1000,0,0);
32+
FLUSH TABLES;
33+
remove_file $datadir/test/s.frm;
34+
move_file $datadir/test/s1.frm $datadir/test/s.frm;
35+
CHECK TABLE s;
36+
DROP SEQUENCE s;
37+
38+
# Fewer than one row
39+
let $datadir=`select @@datadir`;
40+
CREATE SEQUENCE s;
41+
copy_file $datadir/test/s.frm $datadir/test/s1.frm;
42+
ALTER TABLE s sequence=0;
43+
delete from s;
44+
FLUSH TABLES;
45+
remove_file $datadir/test/s.frm;
46+
move_file $datadir/test/s1.frm $datadir/test/s.frm;
47+
CHECK TABLE s;
48+
DROP SEQUENCE s;
49+
50+
# Wrong metadata (minvalue > maxvalue)
51+
let $datadir=`select @@datadir`;
52+
CREATE SEQUENCE s;
53+
copy_file $datadir/test/s.frm $datadir/test/s1.frm;
54+
ALTER TABLE s sequence=0;
55+
update s set minimum_value=200, maximum_value=100;
56+
FLUSH TABLES;
57+
remove_file $datadir/test/s.frm;
58+
move_file $datadir/test/s1.frm $datadir/test/s.frm;
59+
CHECK TABLE s;
60+
DROP SEQUENCE s;
61+
62+
# Sequence run out tests.
63+
#
64+
# General principle: CHECK TABLE of a sequence table returns OK with a
65+
# warning of ER_SEQUENCE_RUN_OUT if a SELECT NEXTVAL of the sequence
66+
# in place of the CHECK TABLE statement would report
67+
# ER_SEQUENCE_RUN_OUT.
68+
create sequence s minvalue 13 maxvalue 15 increment by 4;
69+
check table s;
70+
--disable_ps2_protocol
71+
select nextval(s);
72+
--enable_ps2_protocol
73+
check table s;
74+
alter sequence s cycle;
75+
check table s;
76+
alter sequence s nocycle;
77+
check table s;
78+
# Still get run out because next_free_value has not changed. same
79+
# would happen with a SELECT NEXTVAL(s) statement without the
80+
# preceding check table statement.
81+
alter sequence s increment by 1;
82+
check table s;
83+
alter sequence s increment by 4;
84+
# If all_values_used is true, and then we make sequence cycle, check
85+
# table will be ok without warning, as expected. this is because the
86+
# ALTER SEQUENCE statement causes all_values_used to be reset.
87+
--disable_ps2_protocol
88+
--error ER_SEQUENCE_RUN_OUT
89+
select nextval(s);
90+
--enable_ps2_protocol
91+
alter sequence s cycle;
92+
check table s;
93+
alter sequence s maxvalue 23 nocycle;
94+
check table s;
95+
alter sequence s maxvalue 15;
96+
check table s;
97+
drop sequence s;
98+
99+
# CHECK TABLE calls sequence_definition::check_and_adjust() with
100+
# adjust_next=false, so that there will be no flushing of
101+
# next_free_value in this call, hence no running out
102+
create sequence s minvalue 13 maxvalue 20 increment by 1;
103+
--disable_ps2_protocol
104+
select nextval(s);
105+
--enable_ps2_protocol
106+
check table s;
107+
--disable_ps2_protocol
108+
select nextval(s);
109+
--enable_ps2_protocol
110+
drop sequence s;
111+
112+
# Without the CHECK TABLE statement below, the ALTER TABLE ...
113+
# SEQUENCE=1 statement would still cause flushing in subsequent SELECT
114+
# NEXTVAL statement (initialized == SQUENCE:SQL_UNITIALIZED =>
115+
# read_initial_value() => => sequence_defitinion::adjust_values()),
116+
# resulting in sequence running out.
117+
118+
# Same effect takes place with ALTER SEQUENCE, though different cause:
119+
# in ALTER SEQUENCE, sequence_defitinion::adjust_values() is called in
120+
# sequence_definition::check_and_adjust() which is called in
121+
# Sql_cmd_alter_sequence::execute()
122+
create sequence s minvalue 13 maxvalue 20 increment by 1;
123+
--disable_ps2_protocol
124+
select nextval(s);
125+
--enable_ps2_protocol
126+
alter table s sequence=0;
127+
alter table s sequence=1;
128+
check table s;
129+
--disable_ps2_protocol
130+
--error ER_SEQUENCE_RUN_OUT
131+
select nextval(s);
132+
--enable_ps2_protocol
133+
drop sequence s;
134+
135+
# UPDATE is banned by the storage engine - no need to check.
136+
create sequence s;
137+
--error ER_ILLEGAL_HA
138+
update s set minimum_value=500, maximum_value=200;
139+
drop sequence s;

mysql-test/suite/sql_sequence/other.result

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
create sequence s1 engine=innodb;
55
check table s1;
66
Table Op Msg_type Msg_text
7-
test.s1 checknote The storage engine for the table doesn't support check
7+
test.s1 checkstatus OK
88
select next value for s1;
99
next value for s1
1010
1
1111
flush tables;
1212
check table s1;
1313
Table Op Msg_type Msg_text
14-
test.s1 checknote The storage engine for the table doesn't support check
14+
test.s1 checkstatus OK
1515
select next value for s1;
1616
next value for s1
1717
1001
@@ -32,7 +32,7 @@ Table Op Msg_type Msg_text
3232
test.s1 repair status OK
3333
check table s1;
3434
Table Op Msg_type Msg_text
35-
test.s1 checknote The storage engine for the table doesn't support check
35+
test.s1 checkstatus OK
3636
select next value for s1;
3737
next value for s1
3838
1001

sql/ha_sequence.cc

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,50 @@ void ha_sequence::print_error(int error, myf errflag)
420420
DBUG_VOID_RETURN;
421421
}
422422

423+
int ha_sequence::check(THD* thd, HA_CHECK_OPT* check_opt)
424+
{
425+
DBUG_ENTER("ha_sequence::check");
426+
/* Check the underlying engine */
427+
if (int ret= file->check(thd, check_opt))
428+
DBUG_RETURN(ret);
429+
/* Check number of rows */
430+
if ((file->table_flags() & HA_STATS_RECORDS_IS_EXACT))
431+
{
432+
if (file->stats.records > 1)
433+
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
434+
ER_SEQUENCE_TABLE_HAS_TOO_MANY_ROWS,
435+
ER_THD(thd, ER_SEQUENCE_TABLE_HAS_TOO_MANY_ROWS));
436+
else if (file->stats.records == 0)
437+
{
438+
my_error(ER_SEQUENCE_TABLE_HAS_TOO_FEW_ROWS, MYF(0));
439+
DBUG_RETURN(HA_ADMIN_CORRUPT);
440+
}
441+
}
442+
/*
443+
Initialise the sequence from the table if needed.
444+
*/
445+
if (sequence->initialized == SEQUENCE::SEQ_UNINTIALIZED)
446+
{
447+
if (sequence->read_stored_values(table))
448+
DBUG_RETURN(HA_ADMIN_FAILED);
449+
else
450+
sequence->initialized= SEQUENCE::SEQ_READY_TO_USE;
451+
}
452+
DBUG_ASSERT(sequence->initialized == SEQUENCE::SEQ_READY_TO_USE);
453+
/* Check and adjust sequence state */
454+
if (sequence->check_and_adjust(thd, false, /*adjust_next=*/false))
455+
{
456+
print_error(HA_ERR_SEQUENCE_INVALID_DATA, MYF(0));
457+
DBUG_RETURN(HA_ADMIN_CORRUPT);
458+
}
459+
/* Check value not exhausted */
460+
if (sequence->has_run_out())
461+
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
462+
ER_SEQUENCE_RUN_OUT, ER_THD(thd, ER_SEQUENCE_RUN_OUT),
463+
table->s->db.str, table->s->table_name.str);
464+
DBUG_RETURN(0);
465+
}
466+
423467
/*****************************************************************************
424468
Sequence plugin interface
425469
*****************************************************************************/

sql/ha_sequence.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ class ha_sequence :public handler
159159
{ return file->is_crashed(); }
160160
void column_bitmaps_signal() override
161161
{ return file->column_bitmaps_signal(); }
162+
int check(THD* thd, HA_CHECK_OPT* check_opt) override;
162163

163164
/* New methods */
164165
void register_original_handler(handler *file_arg)

sql/share/errmsg-utf8.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12308,3 +12308,7 @@ ER_LATITUDE_OUT_OF_RANGE
1230812308
eng "Latitude %f is out of range in function %s. It must be within [-90.000000, 90.000000]."
1230912309
ER_GIS_DIFFERENT_SRIDS_AGGREGATION
1231012310
eng "Arguments to function %s contains geometries with different SRIDs: %d and %d. All geometries must have the same SRID."
12311+
ER_SEQUENCE_TABLE_HAS_TOO_FEW_ROWS
12312+
eng "Fewer than one row in the table"
12313+
ER_SEQUENCE_TABLE_HAS_TOO_MANY_ROWS
12314+
eng "More than one row in the table"

0 commit comments

Comments
 (0)