# Tests for various concurrency-related aspects of CREATE TABLE ... SELECT # and CREATE TABLE like implementation. # # Note that we do not test general CREATE TABLE ... SELECT/LIKE functionality # here as it is already covered by create.test. We are more interested in # extreme cases. # # This test takes rather long time so let us run it only in --big-test mode --source include/big_test.inc --source include/not_valgrind.inc # We need the Debug Sync Facility. --source include/have_debug_sync.inc # Some of tests below also use binlog to check that statements are # executed and logged in correct order --source include/force_binlog_format_statement.inc # Save the initial number of concurrent sessions. --source include/count_sessions.inc # Create auxilliary connections connect (addconroot1, localhost, root,,); connect (addconroot2, localhost, root,,); connect (addconroot3, localhost, root,,); connection default; --disable_warnings drop table if exists t1,t2,t3,t4,t5; --enable_warnings set debug_sync='RESET'; # # Tests for concurrency problems in CREATE TABLE ... SELECT # # We introduce delays between various stages of table creation # and check that other statements dealing with this table cannot # interfere during those delays. # # What happens in situation when other statement messes with # table to be created before it is created ? # Concurrent CREATE TABLE set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send create table t1 (j char(5)); connection addconroot2; let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "create table t1 (j char(5))"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --error ER_TABLE_EXISTS_ERROR --reap connection default; show create table t1; drop table t1; # Concurrent CREATE TABLE ... SELECT set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send create table t1 select 'Test' as j; connection addconroot2; # Wait until the above CREATE TABLE t1 is blocked due to CREATE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "create table t1 select 'Test' as j"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --error ER_TABLE_EXISTS_ERROR --reap connection default; show create table t1; drop table t1; # Concurrent CREATE TABLE LIKE create table t3 (j char(5)); set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send create table t1 like t3; connection addconroot2; # Wait until the above CREATE TABLE t1 is blocked due to CREATE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "create table t1 like t3"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --error ER_TABLE_EXISTS_ERROR --reap connection default; show create table t1; drop table t1; # Concurrent RENAME TABLE set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send rename table t3 to t1; connection addconroot2; # Wait until the above RENAME TABLE is blocked due to CREATE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "rename table t3 to t1"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --error ER_TABLE_EXISTS_ERROR --reap connection default; show create table t1; drop table t1; # Concurrent ALTER TABLE RENAME set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send alter table t3 rename to t1 connection addconroot2; # Wait until the above ALTER TABLE RENAME is blocked due to CREATE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "alter table t3 rename to t1"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --error ER_TABLE_EXISTS_ERROR --reap connection default; show create table t1; drop table t1; # Concurrent ALTER TABLE RENAME which also adds column set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send alter table t3 rename to t1, add k int connection addconroot2; # Wait until the above ALTER TABLE RENAME is blocked due to CREATE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "alter table t3 rename to t1, add k int"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --error ER_TABLE_EXISTS_ERROR --reap connection default; show create table t1; drop table t1,t3; # What happens if other statement sneaks in after the table # creation but before its opening ? set debug_sync='create_table_select_before_open SIGNAL parked WAIT_FOR go'; connection default; # Concurrent DROP TABLE set debug_sync='create_table_select_before_open SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send drop table t1; connection addconroot2; # Wait until the above DROP TABLE is blocked due to CREATE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "drop table t1"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --reap connection default; # Concurrent RENAME TABLE set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send rename table t1 to t2; connection addconroot2; # Wait until the above RENAME TABLE is blocked due to CREATE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "rename table t1 to t2"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --reap connection default; drop table t2; # Concurrent SELECT set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send select * from t1; connection addconroot2; # Wait until the above SELECT is blocked due to CREATE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "select * from t1"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --reap connection default; drop table t1; # Concurrent INSERT set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send insert into t1 values (2); connection addconroot2; # Wait until the above INSERT is blocked due to CREATE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "insert into t1 values (2)"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --reap connection default; select * from t1; drop table t1; # Concurrent CREATE TRIGGER set @a:=0; set debug_sync='create_table_select_before_create SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send create trigger t1_bi before insert on t1 for each row set @a:=1; connection addconroot2; # Wait until the above CREATE TRIGGER is blocked due to CREATE TABLE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "create trigger t1_bi before insert on t1 for each row set @a:=1"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --reap connection default; select @a; drop table t1; # Okay, now the same tests for the potential gap between open and lock set debug_sync='create_table_select_before_lock SIGNAL parked WAIT_FOR go'; # Concurrent DROP TABLE --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send drop table t1; connection addconroot2; # Wait until the above DROP TABLE is blocked due to CREATE TABLE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "drop table t1"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --reap connection default; # Concurrent RENAME TABLE set debug_sync='create_table_select_before_lock SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send rename table t1 to t2; connection addconroot2; # Wait until the above RENAME TABLE is blocked due to CREATE TABLE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "rename table t1 to t2"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --reap connection default; drop table t2; # Concurrent SELECT set debug_sync='create_table_select_before_lock SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send select * from t1; connection addconroot2; # Wait until the above SELECT is blocked due to CREATE TABLE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "select * from t1"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --reap connection default; drop table t1; # Concurrent INSERT set debug_sync='create_table_select_before_lock SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send insert into t1 values (2); connection addconroot2; # Wait until the above INSERT INTO t1 is blocked due to CREATE TABLE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "insert into t1 values (2)"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --reap connection default; select * from t1; drop table t1; # Concurrent CREATE TRIGGER set @a:=0; set debug_sync='create_table_select_before_lock SIGNAL parked WAIT_FOR go'; --send create table t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send create trigger t1_bi before insert on t1 for each row set @a:=1; connection addconroot2; # Wait until the above CREATE TRIGGER is blocked due to CREATE TABLE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "create trigger t1_bi before insert on t1 for each row set @a:=1"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --reap connection default; select @a; drop table t1; # Concurrent DROP TABLE set debug_sync='create_table_select_before_check_if_exists SIGNAL parked WAIT_FOR go'; --send create table if not exists t1 select 1 as i; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send drop table t1; connection addconroot2; # Wait until the above DROP TABLE is blocked due to CREATE TABLE let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "drop table t1"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --reap connection default; # Concurrent CREATE TRIGGER create table t1 (i int); set @a:=0; set debug_sync='create_table_select_before_check_if_exists SIGNAL parked WAIT_FOR go'; --send create table if not exists t1 select 1 as i; connection addconroot1; create trigger t1_bi before insert on t1 for each row set @a:=1; connection default; --reap connection default; select @a; select * from t1; drop table t1; # Tests for possible concurrency issues with CREATE TABLE ... LIKE # # Bug #18950 "create table like does not obtain LOCK_open" # Bug #23667 "CREATE TABLE LIKE is not isolated from alteration by other # connections" # # Again the idea of this test is that we introduce artificial delays on # various stages of table creation and check that concurrent statements # for tables from CREATE TABLE ... LIKE are not interfering. --disable_warnings drop table if exists t1,t2; --enable_warnings set debug_sync='RESET'; # What happens if some statements sneak in right after we have # acquired locks and opened source table ? create table t1 (i int); set debug_sync='create_table_like_after_open SIGNAL parked WAIT_FOR go'; # Reset binlog to have clear start reset master; --send create table t2 like t1; connection addconroot1; set debug_sync='now WAIT_FOR parked'; # DML on source table should be allowed to run concurrently insert into t1 values (1); # And DDL should wait --send drop table t1; connection addconroot2; let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "drop table t1"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --reap connection default; show create table t2; drop table t2; # Let us check that statements were executed/binlogged in correct order source include/show_binlog_events.inc; # Now check the gap between table creation and binlogging create table t1 (i int); set debug_sync='create_table_like_before_binlog SIGNAL parked WAIT_FOR go'; reset master; --send create table t2 like t1; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send insert into t2 values (1); connection addconroot2; let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "insert into t2 values (1)"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --reap connection default; drop table t2; set debug_sync='create_table_like_before_binlog SIGNAL parked WAIT_FOR go'; --send create table t2 like t1; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send drop table t2; connection addconroot2; let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "drop table t2"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --reap connection default; set debug_sync='create_table_like_before_binlog SIGNAL parked WAIT_FOR go'; --send create table t2 like t1; connection addconroot1; set debug_sync='now WAIT_FOR parked'; --send drop table t1; connection addconroot2; let $wait_condition= select count(*) = 1 from information_schema.processlist where state = "Waiting for table metadata lock" and info = "drop table t1"; --source include/wait_condition.inc set debug_sync='now SIGNAL go'; connection default; --reap connection addconroot1; --reap connection default; drop table t2; disconnect addconroot1; disconnect addconroot2; disconnect addconroot3; set debug_sync='RESET'; source include/show_binlog_events.inc; --echo # --echo # WL#6390: Use new DD API for handling non-partitioned tables --echo # Test limits on number of columns. See also comment_column2.test --echo # and view.test for additional coverage. --echo # # # InnoDB has separate internal limits let $colnum= 1016; let $str= c text; while ($colnum) { let $str= c$colnum int, $str; dec $colnum; } --eval CREATE TABLE t1 ($str) engine= innodb; --error ER_TOO_MANY_FIELDS ALTER TABLE t1 ADD COLUMN too_much int; DROP TABLE t1; let $str= c1017 int, $str; --error ER_TOO_MANY_FIELDS --eval CREATE TABLE t1 ($str) engine= innodb; --echo # --echo # Tests for limitations related to ENUMs and SETs --echo # --echo # --echo # 1: Max number of ENUM/SET columns # # InnoDB has separate internal limits let $colnum= 1016; let $str= c1017 ENUM('a'); while ($colnum) { let $str= c$colnum ENUM('a$colnum'), $str; dec $colnum; } --eval CREATE TABLE t1 ($str) engine= innodb --error ER_TOO_MANY_FIELDS ALTER TABLE t1 ADD COLUMN too_much ENUM('a9999'); DROP TABLE t1; let $str= $str, too_much ENUM('a9999'); --error ER_TOO_MANY_FIELDS --eval CREATE TABLE t1 ($str) engine= innodb # # InnoDB has separate internal limits let $colnum= 1016; let $str= c1017 SET('a'); while ($colnum) { let $str= c$colnum SET('a$colnum'), $str; dec $colnum; } --eval CREATE TABLE t1 ($str) engine= innodb --error ER_TOO_MANY_FIELDS ALTER TABLE t1 ADD COLUMN too_much SET('a9999'); DROP TABLE t1; let $str= $str, too_much SET('a9999'); --error ER_TOO_MANY_FIELDS --eval CREATE TABLE t1 ($str) engine= innodb --echo # --echo # 2: Max number of elements in ENUM let $elenum= 65534; let $str= col ENUM('a0'; while ($elenum) { let $str= $str, 'a$elenum'; dec $elenum; } --eval CREATE TABLE t1 ($str)) INSERT INTO t1 values ('a0'), ('a1'), ('a2'); SELECT * FROM t1; DROP TABLE t1; --error ER_TOO_BIG_ENUM --eval CREATE TABLE t1 ($str, 'too_much')) --echo # --echo # 3: Max ENUM/SET value length let $iter=25; let $str_250=; while ($iter) { let $str_250=0123456789$str_250; dec $iter; } --eval CREATE TABLE t1 (col ENUM('12345$str_250')) --error ER_TOO_LONG_SET_ENUM_VALUE --eval ALTER TABLE t1 ADD COLUMN col2 ENUM('123456$str_250') DROP TABLE t1; --error ER_TOO_LONG_SET_ENUM_VALUE --eval CREATE TABLE t1 (col ENUM('123456$str_250')) --eval CREATE TABLE t1 (col SET('12345$str_250')) --error ER_TOO_LONG_SET_ENUM_VALUE --eval ALTER TABLE t1 ADD COLUMN col2 SET('123456$str_250') DROP TABLE t1; --error ER_TOO_LONG_SET_ENUM_VALUE --eval CREATE TABLE t1 (col SET('123456$str_250')) # Check that all connections opened by test cases in this file are really # gone so execution of other tests won't be affected by their presence. --source include/wait_until_count_sessions.inc --source include/restore_default_binlog_format.inc