mariadb/mysql-test/main/global_temporary_table.test
Nikita Malyavin ea291a59d2 MDEV-37718 Assertion '!thd->rgi_slave' failed on GTT DML
Assertion '!thd->rgi_slave' failed in open_global_temporary_table on
CREATE/ANALYZE GTT, also a SIGSEGV in the release build.

This is a result of a fact that some operations led to opening a child
table on slave. The bug can be split in two parts:

1. SELECT part of CREATE...SELECT is replicated. It was binlogged,
despite table_creation_was_logged=0 explicitly set. To avoid, fall to
the row logging path of create_select, i.e. log SHOW CREATE output, but
don't actually log rows.
The relevant changes are in sql_insert.cc

2. Admin commands like ANALYZE TABLE still create a child table on open,
but are binlogged. Binlogging them would be otherwise harmless, but
better to avoid it, until the commands are fully supported and make
sense.
For now, avoid binlogging them with lex->no_write_to_binlog=false.
2025-10-10 16:56:20 +02:00

917 lines
22 KiB
Text

--source include/have_partition.inc
--source include/have_innodb.inc
--source include/have_debug_sync.inc
--source include/not_embedded.inc
--disable_service_connection
--echo # Safety
set lock_wait_timeout= 5;
--error ER_PARSE_ERROR
create table t1 (x int, t text) on commit preserve rows;
create global temporary table t1 (x int, t text) on commit preserve rows;
select TABLE_TYPE from information_schema.tables where table_name = 't1';
--error ER_BAD_TABLE_ERROR
drop temporary table t1;
show create table t1;
flush tables;
show create table t1;
insert into t1 values(1, 'one');
select TABLE_TYPE from information_schema.tables where table_name = 't1';
show table status where temporary='Y';
let $show = query_get_value('show create table t1', 'Create Table', 1);
truncate t1;
let $show1 = query_get_value('show create table t1', 'Create Table', 1);
--if($show != $show1) {
--die SHOW CREATE output mismatch
--}
insert into t1 values(1, 'one');
select * from t1;
--connect (con1,localhost,root,,)
select * from t1 join t1 as t2;
insert into t1 values(2, 'two');
select * from t1;
select * from t1 join t1 as t2;
--connection default
select * from t1;
select * from t1 join t1 as t2;
--error ER_LOCK_WAIT_TIMEOUT
alter table t1 add y int;
--error ER_LOCK_WAIT_TIMEOUT
drop table t1;
--connection con1
set debug_sync= 'thread_end signal closed';
--disconnect con1
--connection default
set debug_sync= 'now wait_for closed';
--error ER_BAD_TABLE_ERROR
drop temporary table t1;
select * from t1;
--error ER_LOCK_WAIT_TIMEOUT
alter table t1 add j int;
--error ER_LOCK_WAIT_TIMEOUT
drop table t1;
truncate table t1;
alter table t1 add j int;
show create table t1;
drop table t1;
eval $show;
show create table t1;
drop table t1;
--error ER_NO_SUCH_TABLE
show create table t1;
create global temporary table t1 (x int, t text) on commit preserve rows;
show create table t1;
drop table t1;
create global temporary table t (x int) on commit delete rows;
insert into t values (1);
select * from t;
begin;
insert into t values (1);
select * from t;
commit;
select * from t;
--connect (con1,localhost,root,,)
select * from t;
insert into t values (1);
select * from t;
begin;
insert into t values (1);
select * from t;
commit;
select * from t;
set debug_sync= 'thread_end signal closed';
--disconnect con1
--connection default
set debug_sync= 'now wait_for closed';
drop table t;
create global temporary table t (x int) on commit PRESERVE rows;
insert into t values (1);
select * from t;
begin;
insert into t values (1);
select * from t;
commit;
select * from t;
--connect (con1,localhost,root,,)
select * from t;
insert into t values (1);
select * from t;
begin;
insert into t values (1);
select * from t;
commit;
select * from t;
set debug_sync= 'thread_end signal closed';
--disconnect con1
--connection default
set debug_sync= 'now wait_for closed';
--error ER_LOCK_WAIT_TIMEOUT
drop table t;
truncate t;
drop table t;
create global temporary table t (x int) on commit PRESERVE rows;
--connect (con1,localhost,root,,)
insert t values(1);
--connection default
--error ER_LOCK_WAIT_TIMEOUT
alter table t add j int;
--error ER_LOCK_WAIT_TIMEOUT
set statement lock_wait_timeout=0 for drop table t;
--connection con1
set debug_sync= 'thread_end signal closed';
--disconnect con1
--connection default
set debug_sync= 'now wait_for closed';
drop table t;
--error ER_FEATURE_NOT_SUPPORTED_WITH_PARTITIONING
create global temporary table t (x int) partition by hash(x);
--error ER_VERS_NOT_SUPPORTED
create global temporary table t (x int) with system versioning;
--error ER_CANNOT_ADD_FOREIGN
create global temporary table t (x int, y int, foreign key (x) references t(y));
create global temporary table t (x int);
--error ER_ALTER_OPERATION_NOT_SUPPORTED
alter table t force, lock=none, algorithm=copy;
--error ER_ALTER_OPERATION_NOT_SUPPORTED
alter table t rename column x to y, lock=none, algorithm=inplace;
drop table t;
--echo ### VIEWS
create global temporary table t (x int);
--connect (con1,localhost,root,,)
begin;
insert into t values(1);
--connection default
create view v as select * from t;
begin;
insert into t values(2);
select * from v;
--connection con1
select * from v;
commit;
--echo # Now table was truncated
select * from v;
--connection default
commit;
drop view v;
drop table t;
--echo ### AS SELECT
create global temporary table t1(x int) on commit preserve rows
as select 1 as 'x';
select * from t1;
create global temporary table t2 on commit preserve rows
as values(5),(6),(7);
select * from t2;
--connection con1
select * from t1;
select `5` as 'empty' from t2;
truncate t1;
truncate t2;
--connection default
truncate t1;
truncate t2;
drop table t1;
drop table t2;
create global temporary table t(x int) on commit delete rows
as select 1 as 'x';
--echo # Implicit commit deletes data
select * from t;
drop table t;
--error ER_DUP_ENTRY
create global temporary table t2(`5` int primary key)
comment='create ... as values(5),(5),(5) => duplicate'
as values(5),(5),(5);
select `5` as col from t2;
drop table t2;
--echo ### CREATE TABLE ... LIKE
create table t1(x int primary key);
create global temporary table t2 like t1;
show create table t2;
drop table t1;
create table t1 like t2;
show create table t1;
drop table t1;
create global temporary table t3 like t2;
show create table t3;
create temporary table t4 (d int);
create or replace temporary table t4 like t3; # MDEV-37719
drop table t4;
drop table t2;
drop table t3;
create global temporary table t2(x int primary key) on commit preserve rows;
create table t1 like t2;
show create table t1;
create global temporary table t3 like t2;
show create table t3;
create temporary table t4 like t2;
show create table t4;
truncate t2;
truncate t3;
drop table t1;
drop table t2;
drop table t3;
drop table t4;
create global temporary table gtt (c int) on commit preserve rows;
insert into gtt(c) values (1);
select * from gtt;
delete from gtt;
select * from gtt;
truncate table gtt;
drop table gtt;
--echo ### RENAME
create global temporary table t2(x int primary key) on commit preserve rows;
--connection con1
insert t2 values (1);
--connection default
--error ER_LOCK_WAIT_TIMEOUT
rename table t2 NOWAIT to tx;
--connection con1
truncate t2;
--connection default
select * from t2;
--error ER_LOCK_WAIT_TIMEOUT
rename table t2 to tx;
truncate t2;
rename table t2 to tx;
--error ER_NO_SUCH_TABLE
show create table t2;
show create table tx;
drop table tx;
--echo ### FLUSH
create global temporary table t(x int primary key) on commit preserve rows;
flush table t;
insert t values (1);
flush table t;
select * from t;
truncate t;
flush table t;
drop table t;
--echo # Multi-table DML
create table t(x int, txt text);
create global temporary table gtt(x int) on commit preserve rows;
insert t values (1, 'one'), (2,'two'), (3, 'three'), (4, 'four');
insert gtt values (2),(3),(5);
--connection con1
insert gtt values (4),(6);
--connection default
update t, gtt set t.txt= CONCAT(t.txt, ' tables') where t.x = gtt.x;
--connection con1
update t, gtt set t.txt= CONCAT(t.txt, ' databases') where t.x = gtt.x;
truncate gtt;
--connection default
select * from t;
truncate gtt;
drop table t;
drop table gtt;
create table t(x int);
lock table t write;
create or replace table t(x int);
create or replace global temporary table t(t text);
unlock table;
drop table t;
--echo ### PS Second execution
create global temporary table t(x int) on commit preserve rows;
insert into t values (1),(2),(3);
prepare stmt from 'update t set x = x + 1 where x > 2';
prepare ins_stmt from 'insert into t values (1),(2),(3)';
execute stmt;
execute stmt;
select * from t;
truncate table t;
insert into t values (1),(2),(3);
execute ins_stmt;
execute ins_stmt;
select * from t;
deallocate prepare stmt;
--connection con1
select * from t;
truncate t;
--connection default
truncate t;
drop table t;
create global temporary table t(x int) on commit preserve rows;
execute ins_stmt;
select * from t;
deallocate prepare ins_stmt;
prepare stmt from 'update t set x = x + 1 where x > 2';
prepare ins_stmt from 'insert into t values (1),(2),(3)';
insert into t values (1),(2),(3);
execute stmt;
execute stmt;
select * from t;
truncate table t;
execute ins_stmt;
execute ins_stmt;
select * from t;
--connection con1
select * from t;
truncate t;
--connection default
deallocate prepare stmt;
deallocate prepare ins_stmt;
truncate t;
drop table t;
--echo # Global temporary tables exist in the global tables namespace.
create global temporary table t(x int) on commit preserve rows;
insert t values (111);
create temporary table t(y int);
insert t values (222);
select * from t;
show create table t;
truncate t;
select * from t;
drop table t;
show create table t;
select * from t;
truncate table t;
drop table t;
create global temporary table t(x int) on commit preserve rows;
insert t values (1111);
create temporary table t(y int);
insert t values (222);
alter table t add z int;
select * from t;
rename table t to t1;
select * from t1;
drop table t1;
select * from t;
truncate t;
drop table t;
--echo # Invert the creation order: local temporary table is created first
create temporary table t(y int);
create global temporary table t(x int) on commit preserve rows select 1111 as x;
insert t values (222);
alter table t add z int;
select * from t;
rename table t to t1;
select * from t1;
select * from t;
drop table t1;
truncate t;
drop table t;
--echo # LOCK TABLES
create global temporary table t(x int) on commit preserve rows;
lock tables t write;
insert t values(1);
select * from t;
truncate t;
drop table t;
--error ER_NO_SUCH_TABLE
select * from t;
unlock tables;
create global temporary table t(x int) on commit preserve rows;
insert t values(1);
lock tables t write;
select * from t;
unlock tables;
truncate t;
drop table t;
--echo # Write lock works
create global temporary table t(x int) on commit preserve rows;
lock tables t write;
insert t values(1);
--connection con1
--error ER_LOCK_WAIT_TIMEOUT
set statement lock_wait_timeout= 0 for
select * from t nowait;
--error ER_LOCK_WAIT_TIMEOUT
lock tables t write nowait;
--connection default
truncate t;
drop table t;
--echo # Global descriptor is locked for read, but it allows inserting
--echo # into local copies
create global temporary table t(x int) on commit preserve rows;
lock tables t read;
insert t values(1);
--connection con1
select * from t;
--connection default
select * from t;
--connection con1
truncate t;
--connection default
truncate t;
unlock tables;
drop table t;
create global temporary table t(x int) on commit preserve rows;
lock tables t read;
--connection con1
lock tables t read nowait;
--connection default
insert t values(1);
--connection con1
select * from t;
--connection default
select * from t;
--connection con1
truncate t;
unlock tables;
--connection default
truncate t;
unlock tables;
drop table t;
--echo # mariabackup
create global temporary table t(x int) on commit preserve rows;
insert t values (1), (2), (3);
let $mysqldumpfile = $MYSQLTEST_VARDIR/tmp/mysqldumpfile.sql;
--exec $MYSQL_DUMP test t > $mysqldumpfile
truncate t;
drop table t;
--exec $MYSQL test < $mysqldumpfile
show create table t;
select * from t;
truncate t;
drop table t;
--echo # XA COMMIT/ROLLBACK
create global temporary table t(x int) on commit delete rows;
xa start "trx";
insert t values (1), (2), (3);
select * from t;
xa end "trx";
xa prepare "trx";
xa commit "trx";
select * from t;
xa start "trx";
insert t values (1), (2), (3);
select * from t;
xa end "trx";
xa rollback "trx";
select * from t;
drop table t;
--echo # MDEV-37594 Thread hang on TRUNCATE GTT after server_id change
set global server_id=100;
create global temporary table t(x int) on commit preserve rows;
insert t values (5),(6),(7);
set global server_id=1;
truncate t;
drop table t;
--echo # MDEV-37656 Thread hang in 'starting' state on FLUSH TABLES
create global temporary table t (x int key) on commit preserve rows;
select * from t;
lock table t write;
flush table t;
unlock tables;
truncate t;
drop table t;
--echo # MDEV-37369 SIGSEGV on NEXTVAL from Global temporary table
create global temporary table t(c int);
--error ER_NOT_SEQUENCE
select nextval(t);
drop table t;
--echo # MDEV-37383 crash in end_read_record after REPAIR of Global temporary table
create global temporary table t (c int) engine=innodb;
repair local table t;
delete from t;
truncate t;
drop table t;
create global temporary table t (c int) engine=innodb on commit preserve rows;
repair local table t;
delete from t;
truncate t;
drop table t;
create global temporary table t (c int) engine=innodb;
optimize table t;
analyze table t;
check table t;
delete from t;
drop table t;
create global temporary table t (c int) engine=innodb on commit preserve rows;
optimize table t;
analyze table t;
check table t;
delete from t;
truncate t;
drop table t;
--echo MDEV-37368 Assertion failed in close_thread_tables on UPDATE referring to bad field
create global temporary table t(c int);
--error ER_BAD_FIELD_ERROR
update t set foo= 1;
drop table t;
--echo MDEV-37378 SIGSEGV or Assertion failed on CREATE TRIGGER
create global temporary table t (c int);
--error ER_TRG_ON_VIEW_OR_TEMP_TABLE
create trigger tr after insert on t for each row insert into t values (1);
drop table t;
--echo # MDEV-37394 SIGSEGV in handler::ha_external_lock on CREATE GTT ... AS,
--echo # CREATE GTT ... ENGINE=INNODB SELECT, ASAN heap-use-after-free in unlock_external
create global temporary table t (c int) engine=innodb as select 1;
drop table t;
--echo # MDEV-37379 Assertion `index->is_readable()' failed on REPLACE DELAYED
--echo # DELAYED is transformed to a normal write when stmt logging is enabled.
set @save_binlog_format=@@global.binlog_format;
set global binlog_format=row;
create global temporary table t (c int) engine=innodb;
--error ER_DELAYED_NOT_SUPPORTED
replace delayed t values (0);
drop table t;
create global temporary table t (c int) engine=myisam;
--error ER_DELAYED_NOT_SUPPORTED
replace delayed t values (1);
drop table t;
set global binlog_format=@save_binlog_format;
--echo # MDEV-37381 SIGSEGV in mysql_ha_close_table after HANDLER OPEN of GTT
create global temporary table t (c int);
start transaction ;
handler t open as t;
insert t values(1),(2);
handler t read first;
commit;
--error ER_UNKNOWN_TABLE
handler t close;
drop table t;
create global temporary table t (c int);
start transaction ;
handler t open as t;
insert t values(1),(2);
handler t read first;
handler t close;
commit;
drop table t;
create global temporary table t (c int);
handler t open as t;
--error ER_TABLE_EXISTS_ERROR
create table t (c int);
--echo # The handler was closed on implicit commit after HANDLER OPEN
--error ER_UNKNOWN_TABLE
handler t close;
drop table t;
--echo MDEV-37382 SIGSEGV and UBSAN null-pointer-use in wait_while_table_is_used on CoR GTT
create global temporary table t(x int) on commit preserve rows;
insert t values(1);
--error ER_LOCK_WAIT_TIMEOUT
create or replace table t(y int);
truncate t;
create or replace table t(y int);
show create table t;
drop table t;
create global temporary table t (c int);
lock tables t write;
create or replace global temporary table t (c int);
show create table t;
select * from t;
drop table t;
create or replace global temporary table t (c int) on commit preserve rows;
show create table t;
insert t values(1);
--error ER_LOCK_WAIT_TIMEOUT
create or replace global temporary table t (d int);
truncate t;
create or replace global temporary table t (d int);
drop table t;
unlock tables;
--echo # Test CREATE...LIKE
create global temporary table t(x int) on commit preserve rows;
create table liker(y int);
insert t values(1);
--error ER_LOCK_WAIT_TIMEOUT
create or replace table t like liker;
truncate t;
create or replace table t like liker;
show create table t;
drop table t;
drop table liker;
create global temporary table t(x int) on commit preserve rows ;
create table liker(y int);
lock tables t write, liker write;
insert t values(1);
--error ER_LOCK_WAIT_TIMEOUT
create or replace table t like liker;
truncate t;
--error ER_CANT_CREATE_TABLE
create or replace table t like liker;
drop table t;
drop table liker;
unlock tables;
--echo # Test CREATE ... SELECT
create table t(x int);
create global temporary table src(x int) ;
insert src values(1);
--error ER_CANT_CREATE_TABLE
create or replace table t select * from src;
drop table t;
drop table src;
create table t(x int);
create global temporary table src(x int) ;
insert src values(1);
lock tables t write, src write;
--error ER_CANT_CREATE_TABLE
create or replace table t select * from src;
unlock tables;
drop table t;
drop table src;
create table t(x int);
create table src (yy int);
insert src values(1),(2);
lock tables t write, src write;
--error ER_CANT_CREATE_TABLE
create or replace global temporary table t on commit preserve rows select * from src;
unlock tables;
drop table t;
drop table src;
--echo # MDEV-37385 (duplicate) Thread hang on CoR where the original table is a GTT
create global temporary table t (c int) on commit preserve rows;
insert t values (1);
--error ER_LOCK_WAIT_TIMEOUT
create or replace table t (c int);
truncate t;
drop table t;
--echo # MDEV-37395 SIGSEGV on CREATE TABLE ... SELECT where source table is a GTT
create global temporary table t1 (c int);
create table t2 select * from t1;
drop table t2;
drop table t1;
--echo # MDEV-37384 SIGSEGV on CREATE GTT ... LIKE partitioned table
create table t1 (c int) partition by hash(c) partitions 3;
--error ER_FEATURE_NOT_SUPPORTED_WITH_PARTITIONING
create global temporary table t2 like t1;
drop table t1;
--echo # MDEV-37576 Assertion `!global_table.versioned()' failed after
--echo # ALTER TABLE GTT ADD SYSTEM VERSIONING
create global temporary table t (c int);
truncate t;
--error ER_VERS_NOT_SUPPORTED
alter table t add system versioning;
select * from t;
show create table t;
truncate t;
drop table t;
--echo # MDEV-37578 Assertion failed in TDC_element::flush on ALTER TABLE GTT DISCARD TABLESPACE
create global temporary table t (c int) engine=innodb;
lock tables t write;
--error ER_CANNOT_DISCARD_TEMPORARY_TABLE
alter table t discard tablespace;
unlock tables;
drop table t;
--echo # MDEV-37579 use-after-free in MDL_context::release_lock on FLUSH TABLE GTT
create global temporary table t (x int) on commit preserve rows engine=innodb;
set session transaction_read_only=1;
handler t open;
lock tables t read;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
lock tables t write;
flush table t;
set session transaction_read_only=0;
truncate t;
unlock tables;
drop table t;
--echo # MDEV-37597 InnoDB: Failing assertion: table->get_ref_count() == 0 in dict_sys_t::remove on UPDATE
create table t1 (c varchar(4096) unique) engine=innodb;
create global temporary table t2 like t1;
update t2 set c=0;
drop table t1;
drop table t2;
--echo MDEV-37595 Assertion '...' failed using HANDLER+mrg_myisam+GTT
create global temporary table t (x int) engine=mrg_myisam;
--error ER_ILLEGAL_HA
handler t open;
drop table t;
--echo # MDEV-37379 UBSAN invalid-bool-load on INSERT DELAYED GTT
set @save_binlog_format=@@global.binlog_format;
set global binlog_format=row;
create global temporary table t (x int) on commit preserve rows;
--error ER_DELAYED_NOT_SUPPORTED
insert delayed into t values ();
drop table t;
set global binlog_format=@save_binlog_format;
--echo # MDEV-37657 SIGSEGV in mysql_ha_flush on SHOW CREATE TABLE after HANDLER OPEN GTT
create global temporary table t (c int) engine=innodb on commit delete rows;
handler t open as a;
show create table t;
drop table t;
create global temporary table t (c int) on commit delete rows;
handler t open h;
--error ER_TABLE_EXISTS_ERROR
create table t (d int);
drop table t;
--echo # MDEV-37666 Global temporary table can be created w/ versioning using CREATE LIKE
create table t0 (x int, y int) with system versioning;
--error ER_VERS_NOT_SUPPORTED
create global temporary table t like t0;
drop table t0;
create table t0 (x int primary key, y int) engine=innodb;
create table t1 (x int primary key references t0(x)) engine=innodb;
--error ER_CANNOT_ADD_FOREIGN
create global temporary table t like t1;
drop table t1;
drop table t0;
--echo # MDEV-37667 SIGSEGV on ALTER on locked GTT in low memory env
set @save_max_session_mem_used= @@max_session_mem_used;
set max_session_mem_used= 8192;
create global temporary table t (t text);
--error ER_OPTION_PREVENTS_STATEMENT
insert t values (0);
lock table t write;
--error ER_OPTION_PREVENTS_STATEMENT
alter table t add z int;
drop table t;
unlock tables;
set max_session_mem_used= @save_max_session_mem_used;
--echo # MDEV-37668 SIGSEGV on DROP TABLE GTT under LOCK TABLES and different server_id
create global temporary table t (x int) on commit preserve rows as select 1 'a';
create global temporary table t2 (x int key) on commit preserve rows;
set session server_id=10;
lock tables t2 as a1 write,t as a5 write;
--error ER_LOCK_WAIT_TIMEOUT
drop table t;
truncate t;
drop table t;
unlock tables;
drop table t2;
--echo MDEV-37681 SIGSEGV on TRUNCATE GTT after failed RENAME under LOCK TABLE
create global temporary table t (c int) on commit preserve rows;
lock table t write;
select * from t;
connection default;
--error ER_LOCK_WAIT_TIMEOUT
alter table t add x int;
truncate t;
drop table t;
create global temporary table t (c int) on commit preserve rows;
--connection con1
select * from t;
connection default;
--error ER_LOCK_WAIT_TIMEOUT
alter table t add x int;
--connection con1
truncate t;
--connection default
drop table t;
--echo # MDEV-37694 ASAN heap-use-after-free in check_column_name on CoR ... LIKE
create table t1 (a int key);
create global temporary table t (x int) on commit delete rows;
create or replace table t1 like t;
drop table t;
drop table t1;
--echo # MDEV-37693 use-after-free in mysql_ha_flush after 2nd HANDLER OPEN execution
create global temporary table t (x int) on commit preserve rows;
begin;
select * from t;
handler t open;
--let $con_id = `select connection_id()`
set debug_sync= "before_lock_tables_takes_lock signal kill wait_for lock";
send load index into cache t key(primary);
--connection con1
set debug_sync= "now wait_for kill";
eval kill query $con_id;
--echo # set debug_sync= "now signal lock"; -- not needed, as KILL breaks the waiting
connection default;
reap;
handler t open;
select 1;
rollback;
truncate t;
drop table t;
--echo # MDEV-37596 enforce_storage_engine has an effect on child global temporary tables
create global temporary table t (t text) engine=myisam;
set session enforce_storage_engine=innodb;
insert t values ('qwe');
set session enforce_storage_engine=memory;
insert t values ('asdf');
drop table t;
--disconnect con1