1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

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
This commit is contained in:
Yuchen Pei
2025-05-02 10:44:45 +10:00
parent 26ea37be5d
commit d52ddae57b
10 changed files with 333 additions and 12 deletions

View File

@ -0,0 +1,139 @@
--source include/have_innodb.inc
# Check failure of underlying engine
create sequence s;
let $datadir= `select @@datadir`;
remove_file $datadir/test/s.MYD;
write_file $datadir/test/s.MYD;
foo
EOF
call mtr.add_suppression("ha_myisam");
call mtr.add_suppression("Checking table");
check table s;
drop table s;
# Insert a row into a sequence table updates that row
create sequence s;
insert into s values (3,1,9223372036854775806,1,1,1000,0,0);
select * from s;
# ok
check table s;
--disable_ps2_protocol
select nextval(s);
--enable_ps2_protocol
drop sequence s;
# More than one row
let $datadir=`select @@datadir`;
CREATE SEQUENCE s;
copy_file $datadir/test/s.frm $datadir/test/s1.frm;
ALTER TABLE s sequence=0;
insert into s values (3,1,9223372036854775806,1,1,1000,0,0);
FLUSH TABLES;
remove_file $datadir/test/s.frm;
move_file $datadir/test/s1.frm $datadir/test/s.frm;
CHECK TABLE s;
DROP SEQUENCE s;
# Fewer than one row
let $datadir=`select @@datadir`;
CREATE SEQUENCE s;
copy_file $datadir/test/s.frm $datadir/test/s1.frm;
ALTER TABLE s sequence=0;
delete from s;
FLUSH TABLES;
remove_file $datadir/test/s.frm;
move_file $datadir/test/s1.frm $datadir/test/s.frm;
CHECK TABLE s;
DROP SEQUENCE s;
# Wrong metadata (minvalue > maxvalue)
let $datadir=`select @@datadir`;
CREATE SEQUENCE s;
copy_file $datadir/test/s.frm $datadir/test/s1.frm;
ALTER TABLE s sequence=0;
update s set minimum_value=200, maximum_value=100;
FLUSH TABLES;
remove_file $datadir/test/s.frm;
move_file $datadir/test/s1.frm $datadir/test/s.frm;
CHECK TABLE s;
DROP SEQUENCE s;
# Sequence run out tests.
#
# General principle: CHECK TABLE of a sequence table returns OK with a
# warning of ER_SEQUENCE_RUN_OUT if a SELECT NEXTVAL of the sequence
# in place of the CHECK TABLE statement would report
# ER_SEQUENCE_RUN_OUT.
create sequence s minvalue 13 maxvalue 15 increment by 4;
check table s;
--disable_ps2_protocol
select nextval(s);
--enable_ps2_protocol
check table s;
alter sequence s cycle;
check table s;
alter sequence s nocycle;
check table s;
# Still get run out because next_free_value has not changed. same
# would happen with a SELECT NEXTVAL(s) statement without the
# preceding check table statement.
alter sequence s increment by 1;
check table s;
alter sequence s increment by 4;
# If all_values_used is true, and then we make sequence cycle, check
# table will be ok without warning, as expected. this is because the
# ALTER SEQUENCE statement causes all_values_used to be reset.
--disable_ps2_protocol
--error ER_SEQUENCE_RUN_OUT
select nextval(s);
--enable_ps2_protocol
alter sequence s cycle;
check table s;
alter sequence s maxvalue 23 nocycle;
check table s;
alter sequence s maxvalue 15;
check table s;
drop sequence s;
# CHECK TABLE calls sequence_definition::check_and_adjust() with
# adjust_next=false, so that there will be no flushing of
# next_free_value in this call, hence no running out
create sequence s minvalue 13 maxvalue 20 increment by 1;
--disable_ps2_protocol
select nextval(s);
--enable_ps2_protocol
check table s;
--disable_ps2_protocol
select nextval(s);
--enable_ps2_protocol
drop sequence s;
# Without the CHECK TABLE statement below, the ALTER TABLE ...
# SEQUENCE=1 statement would still cause flushing in subsequent SELECT
# NEXTVAL statement (initialized == SQUENCE:SQL_UNITIALIZED =>
# read_initial_value() => => sequence_defitinion::adjust_values()),
# resulting in sequence running out.
# Same effect takes place with ALTER SEQUENCE, though different cause:
# in ALTER SEQUENCE, sequence_defitinion::adjust_values() is called in
# sequence_definition::check_and_adjust() which is called in
# Sql_cmd_alter_sequence::execute()
create sequence s minvalue 13 maxvalue 20 increment by 1;
--disable_ps2_protocol
select nextval(s);
--enable_ps2_protocol
alter table s sequence=0;
alter table s sequence=1;
check table s;
--disable_ps2_protocol
--error ER_SEQUENCE_RUN_OUT
select nextval(s);
--enable_ps2_protocol
drop sequence s;
# UPDATE is banned by the storage engine - no need to check.
create sequence s;
--error ER_ILLEGAL_HA
update s set minimum_value=500, maximum_value=200;
drop sequence s;