diff --git a/mysql-test/suite/sql_sequence/alter.result b/mysql-test/suite/sql_sequence/alter.result index 36cef2a3914..eb419609823 100644 --- a/mysql-test/suite/sql_sequence/alter.result +++ b/mysql-test/suite/sql_sequence/alter.result @@ -419,3 +419,73 @@ DROP SEQUENCE s2; # # End of 10.6 tests # +# +# MDEV-36032 Check when doing ALTER TABLE table_name sequence=1 that table can be a sequence +# +create sequence s; +alter table s sequence=0; +insert into s values (3,1,9223372036854775806,1,1,1000,0,0); +alter table s sequence=1; +ERROR HY000: More than one row in the table +drop table s; +create sequence s; +alter table s sequence=0; +delete from s; +insert into s values (2,500,200,1,1,1000,0,0); +select * from s; +next_not_cached_value minimum_value maximum_value start_value increment cache_size cycle_option cycle_count +2 500 200 1 1 1000 0 0 +alter table s sequence=1; +ERROR HY000: Sequence 'test.s' has out of range value for options +check table s; +Table Op Msg_type Msg_text +test.s check status OK +select * from s; +next_not_cached_value minimum_value maximum_value start_value increment cache_size cycle_option cycle_count +2 500 200 1 1 1000 0 0 +check table s; +Table Op Msg_type Msg_text +test.s check status OK +drop table s; +CREATE TABLE `s` ( +# `next_not_cached_value` bigint(21) NOT NULL, +`minimum_value` bigint(21) NOT NULL, +`maximum_value` bigint(21) NOT NULL, +`start_value` bigint(21) NOT NULL COMMENT 'start value when sequences is created or value if RESTART is used', +`increment` bigint(21) NOT NULL COMMENT 'increment value', +`cache_size` bigint(21) unsigned NOT NULL, +`cycle_option` tinyint(1) unsigned NOT NULL COMMENT '0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed', +`cycle_count` bigint(21) NOT NULL COMMENT 'How many cycles have been done' +) ENGINE=innodb; +alter table s sequence=1; +ERROR HY000: Sequence 'test.s' table structure is invalid (Wrong number of columns) +drop table s; +create sequence s; +alter table s drop column next_not_cached_value; +ERROR HY000: Sequence 'test.s' table structure is invalid (Wrong number of columns) +drop sequence s; +CREATE TABLE `s1` ( +`next_not_cached_value` bigint(21) NOT NULL, +`minimum_value` bigint(21) NOT NULL, +`maximum_value` bigint(21) NOT NULL, +`start_value` bigint(21) NOT NULL COMMENT 'start value when sequences is created or value if RESTART is used', +`increment` bigint(21) NOT NULL COMMENT 'increment value', +`cache_size` bigint(21) unsigned NOT NULL, +`cycle_option` tinyint(1) unsigned NOT NULL COMMENT '0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed', +`cycle_count` bigint(21) NOT NULL COMMENT 'How many cycles have been done' +) ENGINE=innodb; +alter table s1 sequence=1; +ERROR HY000: Fewer than one row in the table +alter table s1 sequence=0; +insert into s1 values (1,1,9223372036854775806,1,1,1000,0,0); +alter table s1 sequence=1; +alter table s1 sequence=0; +insert into s1 values (2,1,9223372036854775806,1,1,1000,0,0); +alter table s1 sequence=1; +ERROR HY000: More than one row in the table +alter table s1 sequence=0; +insert into s1 values (3,1,9223372036854775806,1,1,1000,0,0); +alter table s1 sequence=1; +ERROR HY000: More than one row in the table +drop table s1; +# End of 10.11 tests diff --git a/mysql-test/suite/sql_sequence/alter.test b/mysql-test/suite/sql_sequence/alter.test index 9ac22b644e8..2bb2e1f62af 100644 --- a/mysql-test/suite/sql_sequence/alter.test +++ b/mysql-test/suite/sql_sequence/alter.test @@ -295,3 +295,84 @@ DROP SEQUENCE s2; --echo # --echo # End of 10.6 tests --echo # + +--echo # +--echo # MDEV-36032 Check when doing ALTER TABLE table_name sequence=1 that table can be a sequence +--echo # + +## Too many rows +create sequence s; +alter table s sequence=0; +insert into s values (3,1,9223372036854775806,1,1,1000,0,0); +--error ER_SEQUENCE_TABLE_HAS_TOO_MANY_ROWS +alter table s sequence=1; +drop table s; + +## Insert a wrong row (min > max) +create sequence s; +alter table s sequence=0; +delete from s; +insert into s values (2,500,200,1,1,1000,0,0); +select * from s; +--error ER_SEQUENCE_INVALID_DATA +alter table s sequence=1; +check table s; +select * from s; +check table s; +drop table s; + +## Invalid table structure (already implemented before MDEV-36032) +CREATE TABLE `s` ( + # `next_not_cached_value` bigint(21) NOT NULL, + `minimum_value` bigint(21) NOT NULL, + `maximum_value` bigint(21) NOT NULL, + `start_value` bigint(21) NOT NULL COMMENT 'start value when sequences is created or value if RESTART is used', + `increment` bigint(21) NOT NULL COMMENT 'increment value', + `cache_size` bigint(21) unsigned NOT NULL, + `cycle_option` tinyint(1) unsigned NOT NULL COMMENT '0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed', + `cycle_count` bigint(21) NOT NULL COMMENT 'How many cycles have been done' +) ENGINE=innodb; +--error ER_SEQUENCE_INVALID_TABLE_STRUCTURE +alter table s sequence=1; +drop table s; + +## Altering a sequence table to a wrong structure is detected (already +## implemented before MDEV-36032) +create sequence s; +--error ER_SEQUENCE_INVALID_TABLE_STRUCTURE +alter table s drop column next_not_cached_value; +drop sequence s; + +## Create a normal table then alter to sequence +CREATE TABLE `s1` ( +`next_not_cached_value` bigint(21) NOT NULL, +`minimum_value` bigint(21) NOT NULL, +`maximum_value` bigint(21) NOT NULL, +`start_value` bigint(21) NOT NULL COMMENT 'start value when sequences is created or value if RESTART is used', +`increment` bigint(21) NOT NULL COMMENT 'increment value', +`cache_size` bigint(21) unsigned NOT NULL, +`cycle_option` tinyint(1) unsigned NOT NULL COMMENT '0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed', +`cycle_count` bigint(21) NOT NULL COMMENT 'How many cycles have been done' +) ENGINE=innodb; + +--error ER_SEQUENCE_TABLE_HAS_TOO_FEW_ROWS +alter table s1 sequence=1; +# (for coverage) alter a non sequence table with sequence=0 +alter table s1 sequence=0; +insert into s1 values (1,1,9223372036854775806,1,1,1000,0,0); +alter table s1 sequence=1; + +alter table s1 sequence=0; +insert into s1 values (2,1,9223372036854775806,1,1,1000,0,0); +--error ER_SEQUENCE_TABLE_HAS_TOO_MANY_ROWS +alter table s1 sequence=1; + +# (for coverage) alter a non sequence table with sequence=0 +alter table s1 sequence=0; +insert into s1 values (3,1,9223372036854775806,1,1,1000,0,0); +--error ER_SEQUENCE_TABLE_HAS_TOO_MANY_ROWS +alter table s1 sequence=1; + +drop table s1; + +--echo # End of 10.11 tests diff --git a/sql/handler.cc b/sql/handler.cc index 85358db6f15..705fd0370e0 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -5454,6 +5454,9 @@ handler::check_if_supported_inplace_alter(TABLE *altered_table, (table->s->row_type != create_info->row_type)) DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); + if (create_info->sequence) + DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); + uint table_changes= (ha_alter_info->handler_flags & ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE) ? IS_EQUAL_PACK_LENGTH : IS_EQUAL_YES; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index e7cbb87824c..93224d9c1b3 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -10758,3 +10758,7 @@ ER_CM_OPTION_MISSING_REQUIREMENT eng "CHANGE MASTER TO option '%s=%s' is missing requirement %s" ER_SLAVE_STATEMENT_TIMEOUT 70100 eng "Slave log event execution was interrupted (slave_max_statement_time exceeded)" +ER_SEQUENCE_TABLE_HAS_TOO_FEW_ROWS + eng "Fewer than one row in the table" +ER_SEQUENCE_TABLE_HAS_TOO_MANY_ROWS + eng "More than one row in the table" diff --git a/sql/sql_table.cc b/sql/sql_table.cc index d9ba09fd2a2..41978063f33 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -12154,6 +12154,16 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, bool ignore, Create_field *def; copy_end=copy; to->s->default_fields= 0; + if (to->s->table_type == TABLE_TYPE_SEQUENCE && + from->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT && + from->file->stats.records != 1) + { + if (from->file->stats.records > 1) + my_error(ER_SEQUENCE_TABLE_HAS_TOO_MANY_ROWS, MYF(0)); + else + my_error(ER_SEQUENCE_TABLE_HAS_TOO_FEW_ROWS, MYF(0)); + goto err; + } for (Field **ptr=to->field ; *ptr ; ptr++) { def=it++; @@ -12337,6 +12347,12 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, bool ignore, else to->next_number_field->reset(); } + if (to->s->table_type == TABLE_TYPE_SEQUENCE && found_count == 1) + { + my_error(ER_SEQUENCE_TABLE_HAS_TOO_MANY_ROWS, MYF(0)); + error= 1; + break; + } error= to->file->ha_write_row(to->record[0]); to->auto_increment_field_not_null= FALSE; if (unlikely(error)) @@ -12356,6 +12372,12 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, bool ignore, thd->get_stmt_da()->inc_current_row_for_warning(); } + if (to->s->table_type == TABLE_TYPE_SEQUENCE && found_count == 0) + { + my_error(ER_SEQUENCE_TABLE_HAS_TOO_FEW_ROWS, MYF(0)); + error= 1; + } + THD_STAGE_INFO(thd, stage_enabling_keys); thd_progress_next_stage(thd);