Merge 10.2 into 10.3

This commit is contained in:
Marko Mäkelä 2018-05-29 17:34:49 +03:00
commit a3539bbb2a
76 changed files with 1593 additions and 343 deletions

View File

@ -949,6 +949,8 @@ pthread_handler_t connection_thread(void *arg)
end_thread:
cn->query_done= 1;
mysql_close(cn->mysql);
cn->mysql= 0;
mysql_thread_end();
pthread_exit(0);
return 0;

View File

@ -2175,6 +2175,66 @@ t1 CREATE TABLE `t1` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8
DROP TABLE t1;
#
# MDEV-15308
# Assertion `ha_alter_info->alter_info->drop_list.elements > 0' failed
# in ha_innodb::prepare_inplace_alter_table
#
CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP COLUMN b;
Warnings:
Note 1091 Can't DROP FOREIGN KEY `fk`; check that it exists
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
ALTER TABLE t1 DROP INDEX IF EXISTS fk, DROP COLUMN b;
Warnings:
Note 1091 Can't DROP INDEX `fk`; check that it exists
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT, c INT, KEY(c)) ENGINE=InnoDB;
ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP COLUMN c;
Warnings:
Note 1091 Can't DROP FOREIGN KEY `fk`; check that it exists
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT, c INT, KEY c1(c)) ENGINE=InnoDB;
ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP INDEX c1;
Warnings:
Note 1091 Can't DROP FOREIGN KEY `fk`; check that it exists
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL,
`c` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
ALTER TABLE t1 DROP INDEX IF EXISTS fk, DROP COLUMN IF EXISTS c;
Warnings:
Note 1091 Can't DROP INDEX `fk`; check that it exists
Note 1091 Can't DROP COLUMN `c`; check that it exists
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
DROP TABLE t1;
#
# End of 10.0 tests
#
#

View File

@ -1803,6 +1803,37 @@ ALTER TABLE t1 CONVERT TO CHARACTER SET utf8;
SHOW CREATE TABLE t1;
DROP TABLE t1;
--echo #
--echo # MDEV-15308
--echo # Assertion `ha_alter_info->alter_info->drop_list.elements > 0' failed
--echo # in ha_innodb::prepare_inplace_alter_table
--echo #
CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP COLUMN b;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
ALTER TABLE t1 DROP INDEX IF EXISTS fk, DROP COLUMN b;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT, c INT, KEY(c)) ENGINE=InnoDB;
ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP COLUMN c;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT, c INT, KEY c1(c)) ENGINE=InnoDB;
ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP INDEX c1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
ALTER TABLE t1 DROP INDEX IF EXISTS fk, DROP COLUMN IF EXISTS c;
SHOW CREATE TABLE t1;
DROP TABLE t1;
--echo #
--echo # End of 10.0 tests
--echo #

View File

@ -809,10 +809,9 @@ LOAD INDEX INTO CACHE t3;
Table Op Msg_type Msg_text
mysqltest_db1.t3 preload_keys status OK
#
# RENAME (doesn't work for temporary tables, thus should fail).
# RENAME should work for temporary tables
#
RENAME TABLE t3 TO t3_1;
ERROR 42000: INSERT, CREATE command denied to user 'mysqltest_u1'@'localhost' for table 't3_1'
#
# HANDLER OPEN/READ/CLOSE.
#

View File

@ -873,9 +873,8 @@ CACHE INDEX t3 IN keycache1;
LOAD INDEX INTO CACHE t3;
--echo #
--echo # RENAME (doesn't work for temporary tables, thus should fail).
--echo # RENAME should work for temporary tables
--echo #
--error ER_TABLEACCESS_DENIED_ERROR
RENAME TABLE t3 TO t3_1;
--echo #

View File

@ -78,3 +78,69 @@ ERROR HY000: 'test.v1' is not of type 'BASE TABLE'
drop view v1;
drop table t1;
End of 5.0 tests
CREATE OR REPLACE TABLE t1 (a INT);
CREATE OR REPLACE TABLE t2 (a INT);
CREATE OR REPLACE TEMPORARY TABLE t1_tmp (b INT);
CREATE OR REPLACE TEMPORARY TABLE t2_tmp (b INT);
rename table t1 to t2;
ERROR 42S01: Table 't2' already exists
rename table t1 to tmp, tmp to t2;
ERROR 42S01: Table 't2' already exists
rename table t1_tmp to t2_tmp;
ERROR 42S01: Table 't2_tmp' already exists
rename table t1_tmp to tmp, tmp to t2_tmp;
ERROR 42S01: Table 't2_tmp' already exists
show create table t1_tmp;
Table Create Table
t1_tmp CREATE TEMPORARY TABLE `t1_tmp` (
`b` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show create table t2_tmp;
Table Create Table
t2_tmp CREATE TEMPORARY TABLE `t2_tmp` (
`b` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
rename table t1 to t1_tmp;
rename table t2_tmp to t2;
rename table t2 to tmp, tmp to t2;
rename table t1_tmp to tmp, tmp to t1_tmp;
show tables;
Tables_in_test
t1_tmp
t2
SHOW CREATE TABLE t1_tmp;
Table Create Table
t1_tmp CREATE TEMPORARY TABLE `t1_tmp` (
`b` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1_tmp;
SHOW CREATE TABLE t1_tmp;
Table Create Table
t1_tmp CREATE TABLE `t1_tmp` (
`a` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1_tmp;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TEMPORARY TABLE `t2` (
`b` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t2;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t2;
CREATE TABLE t1 (a INT);
insert into t1 values (1);
CREATE TEMPORARY TABLE t1 (b INT);
insert into t1 values (2);
RENAME TABLE t1 TO tmp, t1 TO t2;
select * from tmp;
b
2
select * from t2;
a
1
drop table tmp,t2;

View File

@ -95,3 +95,49 @@ drop table t1;
--source include/wait_until_count_sessions.inc
#
# Test of rename with temporary tables
#
CREATE OR REPLACE TABLE t1 (a INT);
CREATE OR REPLACE TABLE t2 (a INT);
CREATE OR REPLACE TEMPORARY TABLE t1_tmp (b INT);
CREATE OR REPLACE TEMPORARY TABLE t2_tmp (b INT);
# Can't rename table over another one
--error ER_TABLE_EXISTS_ERROR
rename table t1 to t2;
--error ER_TABLE_EXISTS_ERROR
rename table t1 to tmp, tmp to t2;
--error ER_TABLE_EXISTS_ERROR
rename table t1_tmp to t2_tmp;
--error ER_TABLE_EXISTS_ERROR
rename table t1_tmp to tmp, tmp to t2_tmp;
show create table t1_tmp;
show create table t2_tmp;
# The following should work
rename table t1 to t1_tmp;
rename table t2_tmp to t2;
rename table t2 to tmp, tmp to t2;
rename table t1_tmp to tmp, tmp to t1_tmp;
show tables;
SHOW CREATE TABLE t1_tmp;
drop table t1_tmp;
SHOW CREATE TABLE t1_tmp;
drop table t1_tmp;
SHOW CREATE TABLE t2;
drop table t2;
SHOW CREATE TABLE t2;
drop table t2;
CREATE TABLE t1 (a INT);
insert into t1 values (1);
CREATE TEMPORARY TABLE t1 (b INT);
insert into t1 values (2);
RENAME TABLE t1 TO tmp, t1 TO t2;
select * from tmp;
select * from t2;
drop table tmp,t2;

View File

@ -0,0 +1,11 @@
CREATE TABLE t1 (i int);
connect con1,localhost,root,,test;
RENAME TABLE t1 TO t2;
connection default;
FLUSH TABLES;
connection con1;
disconnect con1;
connection default;
DROP TABLE IF EXISTS t1, t2;
Warnings:
Note 1051 Unknown table 'test.t1'

View File

@ -0,0 +1,18 @@
#
# MDEV-16123 ASAN heap-use-after-free handler::ha_index_or_rnd_end
# MDEV-13828 Segmentation fault on RENAME TABLE
#
CREATE TABLE t1 (i int);
--connect (con1,localhost,root,,test)
--send
RENAME TABLE t1 TO t2;
--connection default
FLUSH TABLES;
--connection con1
--reap
# Cleanup
--disconnect con1
--connection default
DROP TABLE IF EXISTS t1, t2;

View File

@ -2345,7 +2345,18 @@ CREATE TABLE t1 (i INT);
insert into t2 value (2);
DROP VIEW v1;
DROP TABLE t1,t2,t3;
End of 10.1 tests.
#
# MDEV-16093
# Assertion `global_status_var.global_memory_used == 0' failed or
# bytes lost after inserting into table with non-null blob and trigger
#
CREATE TABLE t1 (b BLOB NOT NULL);
CREATE TRIGGER tr BEFORE UPDATE ON t1 FOR EACH ROW BEGIN END;
INSERT INTO t1 VALUES ('foo');
DROP TABLE t1;
#
# End of 10.1 tests.
#
create table t1 (i int);
create trigger tr1 after insert on t1 for each row set @a=@a+1;
create trigger tr2 after insert on t1 for each row set @a=@a+1;

View File

@ -2665,8 +2665,20 @@ insert into t2 value (2);
DROP VIEW v1;
DROP TABLE t1,t2,t3;
--echo #
--echo # MDEV-16093
--echo # Assertion `global_status_var.global_memory_used == 0' failed or
--echo # bytes lost after inserting into table with non-null blob and trigger
--echo #
--echo End of 10.1 tests.
CREATE TABLE t1 (b BLOB NOT NULL);
CREATE TRIGGER tr BEFORE UPDATE ON t1 FOR EACH ROW BEGIN END;
INSERT INTO t1 VALUES ('foo');
DROP TABLE t1;
--echo #
--echo # End of 10.1 tests.
--echo #
#
# MDEV-10915 Count number of executed triggers

View File

@ -18,6 +18,7 @@
# - with annotated events, default checksums and minimal binlog row image
#
--source include/have_partition.inc
--source encryption_algorithms.inc
--source include/have_innodb.inc
--enable_connect_log

View File

@ -9,6 +9,7 @@
# relay logs and binary logs are encrypted on slave.
#
--source include/have_partition.inc
--source encryption_algorithms.inc
--source include/have_innodb.inc

View File

@ -1 +0,0 @@
--partition

View File

@ -0,0 +1,37 @@
SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
VARIABLE_VALUE = 'Synced'
1
SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
VARIABLE_VALUE = 2
1
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
VARIABLE_VALUE = 'Synced'
1
SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
VARIABLE_VALUE = 2
1
SELECT COUNT(*) = 1 FROM t1;
COUNT(*) = 1
1
DROP TABLE t1;
connection node_1;
CREATE TABLE `t1` (
`col1` int(11) NOT NULL,
`col2` varchar(64) NOT NULL DEFAULT '',
`col3` varchar(32) NOT NULL DEFAULT '0',
`col4` varchar(64) NOT NULL DEFAULT '',
`col5` tinyint(4) NOT NULL DEFAULT '0',
`col6` int(11) NOT NULL DEFAULT '0',
`col7` varchar(64) NOT NULL DEFAULT '',
`col8` tinyint(4) NOT NULL DEFAULT '0',
`col9` tinyint(4) NOT NULL DEFAULT '0',
`col10` text NOT NULL,
`col11` varchar(255) NOT NULL DEFAULT '',
`col12` tinyint(4) NOT NULL DEFAULT '1'
) ;
create table t2 (test int);
insert into t2 values (1);
drop table t1,t2;

View File

@ -0,0 +1,8 @@
!include ../galera_2nodes.cnf
[mysqld]
encrypt-tmp-files = 1
plugin-load-add= @ENV.FILE_KEY_MANAGEMENT_SO
file-key-management
loose-file-key-management-filename= @ENV.MYSQL_TEST_DIR/std_data/keys.txt
log-bin

View File

@ -0,0 +1,57 @@
# This file tests that mariadb cluster should not crash when encrypt_tmp_file
# is enabled
--source include/galera_cluster.inc
--source include/have_innodb.inc
SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
INSERT INTO t1 VALUES (1);
--connection node_2
SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
SELECT COUNT(*) = 1 FROM t1;
DROP TABLE t1;
--connection node_1
CREATE TABLE `t1` (
`col1` int(11) NOT NULL,
`col2` varchar(64) NOT NULL DEFAULT '',
`col3` varchar(32) NOT NULL DEFAULT '0',
`col4` varchar(64) NOT NULL DEFAULT '',
`col5` tinyint(4) NOT NULL DEFAULT '0',
`col6` int(11) NOT NULL DEFAULT '0',
`col7` varchar(64) NOT NULL DEFAULT '',
`col8` tinyint(4) NOT NULL DEFAULT '0',
`col9` tinyint(4) NOT NULL DEFAULT '0',
`col10` text NOT NULL,
`col11` varchar(255) NOT NULL DEFAULT '',
`col12` tinyint(4) NOT NULL DEFAULT '1'
) ;
#Although we just need $counter >= 907 for IO_CACHE to use
#encrypted temp file. Just on safe side I am using $counter
# = 1100
--disable_query_log
--let $counter=1100
--let $query= (1,'test','test','test',0,0,'-1',0,0,'','',-1)
while($counter)
{
--let $query= $query ,(1,'test','test','test',0,0,'-1',0,0,'','',-1)
--dec $counter
}
--let $query= INSERT INTO t1 values $query ;
--eval $query
--enable_query_log
#INSERT INTO `t1` VALUE
create table t2 (test int);
insert into t2 values (1);
drop table t1,t2;

View File

@ -4,6 +4,7 @@
--source include/galera_cluster.inc
--source include/have_innodb.inc
--source include/have_perfschema.inc
# Save original auto_increment_offset values.
--let $node_1=node_1

View File

@ -100,6 +100,17 @@ f2
unlock tables;
DROP TABLE t1,t2,tmp;
#
# MDEV-10378 Assertion `trn' failed in virtual int ha_maria::start_stmt
#
CREATE TABLE t1 (f1 VARCHAR(3), f2 INT, pk INT, PRIMARY KEY (pk)) ENGINE=Aria;
INSERT INTO t1 VALUES ('foo',10,1), ('foo',1,2);
LOCK TABLE t1 WRITE;
ALTER TABLE t1 ADD UNIQUE KEY (f1);
ERROR 23000: Duplicate entry 'foo' for key 'f1'
ALTER TABLE t1 ADD KEY (f2);
DROP TABLE t1;
# End of 10.2 tests
#
# MDEV-14669 Assertion `file->trn == trn' failed in ha_maria::start_stmt
#
CREATE TABLE t1 (i INT) ENGINE=Aria;

View File

@ -106,6 +106,20 @@ select * from t2;
unlock tables;
DROP TABLE t1,t2,tmp;
--echo #
--echo # MDEV-10378 Assertion `trn' failed in virtual int ha_maria::start_stmt
--echo #
CREATE TABLE t1 (f1 VARCHAR(3), f2 INT, pk INT, PRIMARY KEY (pk)) ENGINE=Aria;
INSERT INTO t1 VALUES ('foo',10,1), ('foo',1,2);
LOCK TABLE t1 WRITE;
--error ER_DUP_ENTRY
ALTER TABLE t1 ADD UNIQUE KEY (f1);
ALTER TABLE t1 ADD KEY (f2);
DROP TABLE t1;
--echo # End of 10.2 tests
--echo #
--echo # MDEV-14669 Assertion `file->trn == trn' failed in ha_maria::start_stmt
--echo #

View File

@ -0,0 +1 @@
--loose-partition

View File

@ -1,4 +1,5 @@
--source include/have_debug.inc
--source include/have_partition.inc
CREATE TABLE t(i INT) ENGINE INNODB;
INSERT INTO t VALUES(1);

View File

@ -1 +0,0 @@
--partition

View File

@ -1,3 +1,4 @@
--source include/have_partition.inc
let $targetdir=$MYSQLTEST_VARDIR/backup;
mkdir $targetdir;
mkdir $MYSQLTEST_VARDIR/partitdata;

View File

@ -1 +1 @@
--innodb --loose-changed_page_bitmaps --innodb-sys-tables --partition
--innodb --loose-changed_page_bitmaps --innodb-sys-tables

View File

@ -0,0 +1,10 @@
#
# MDEV-10679
# Server crashes in in mysql_create_frm_image upon query from
# performance schema in ps-protocol mode
#
CREATE TABLE t1 (i INT);
ALTER TABLE t1 ADD PARTITION (PARTITION p VALUES LESS THAN (1));
ERROR HY000: Partition management on a not partitioned table is not possible
SELECT * FROM performance_schema.events_stages_summary_by_user_by_event_name;
DROP TABLE t1;

View File

@ -0,0 +1,16 @@
--source include/have_perfschema.inc
--source include/have_partition.inc
--echo #
--echo # MDEV-10679
--echo # Server crashes in in mysql_create_frm_image upon query from
--echo # performance schema in ps-protocol mode
--echo #
CREATE TABLE t1 (i INT);
--error ER_PARTITION_MGMT_ON_NONPARTITIONED
ALTER TABLE t1 ADD PARTITION (PARTITION p VALUES LESS THAN (1));
--disable_result_log
SELECT * FROM performance_schema.events_stages_summary_by_user_by_event_name;
--enable_result_log
DROP TABLE t1;

View File

@ -0,0 +1,36 @@
include/master-slave.inc
[connection master]
#
# MDEV-16229 Replication aborts with ER_VIEW_SELECT_TMPTABLE after
# half-failed RENAME
#
CREATE TABLE t1 (a INT);
CREATE TEMPORARY TABLE t1 (b INT);
RENAME TABLE t1 TO tmp, tmp TO t1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TEMPORARY TABLE `t1` (
`b` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
CREATE VIEW v AS SELECT * FROM t1;
ERROR HY000: View's SELECT refers to a temporary table 't1'
RENAME TABLE t1 TO tmp, t1 TO t2;
SHOW CREATE TABLE tmp;
Table Create Table
tmp CREATE TEMPORARY TABLE `tmp` (
`b` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
CREATE VIEW v AS SELECT * FROM tmp;
ERROR HY000: View's SELECT refers to a temporary table 'tmp'
CREATE VIEW v AS SELECT * FROM t2;
connection slave;
connection master;
DROP VIEW v;
DROP TABLE tmp;
DROP TABLE t2;
include/rpl_end.inc

View File

@ -0,0 +1,33 @@
--source include/have_binlog_format_mixed.inc
--source include/master-slave.inc
--echo #
--echo # MDEV-16229 Replication aborts with ER_VIEW_SELECT_TMPTABLE after
--echo # half-failed RENAME
--echo #
CREATE TABLE t1 (a INT);
CREATE TEMPORARY TABLE t1 (b INT);
RENAME TABLE t1 TO tmp, tmp TO t1;
SHOW CREATE TABLE t1;
--error ER_VIEW_SELECT_TMPTABLE
CREATE VIEW v AS SELECT * FROM t1;
RENAME TABLE t1 TO tmp, t1 TO t2;
SHOW CREATE TABLE tmp;
SHOW CREATE TABLE t2;
--error ER_VIEW_SELECT_TMPTABLE
CREATE VIEW v AS SELECT * FROM tmp;
CREATE VIEW v AS SELECT * FROM t2;
--sync_slave_with_master
# Cleanup
--connection master
DROP VIEW v;
DROP TABLE tmp;
DROP TABLE t2;
--source include/rpl_end.inc

View File

@ -0,0 +1,70 @@
include/master-slave.inc
[connection master]
CREATE TABLE t1 (
pk SERIAL,
vcol_date DATE AS (col_date) PERSISTENT,
vcol_int INT AS (col_int) VIRTUAL,
vcol_year YEAR AS (col_year) PERSISTENT,
vcol_blob BLOB AS (col_blob) VIRTUAL,
col_date DATE,
col_int INT NULL,
col_blob BLOB NULL,
col_year YEAR,
PRIMARY KEY(pk)
) ENGINE=InnoDB;
INSERT INTO t1 (col_date,col_int,col_blob,col_year) VALUES ('2010-04-24',5,'foo',1981);
SET SQL_MODE='';
set binlog_row_image="FULL";
CREATE VIEW v1 AS SELECT * FROM t1;
REPLACE INTO v1 SELECT pk, vcol_date, vcol_int, vcol_year, vcol_blob, col_date, col_int, col_blob, 1982 FROM t1;
Warnings:
Warning 1906 The value specified for generated column 'vcol_date' in table 't1' ignored
Warning 1906 The value specified for generated column 'vcol_int' in table 't1' ignored
Warning 1906 The value specified for generated column 'vcol_year' in table 't1' ignored
Warning 1906 The value specified for generated column 'vcol_blob' in table 't1' ignored
select col_date,col_int,col_blob,col_year from v1;
col_date col_int col_blob col_year
2010-04-24 5 foo 1982
connection slave;
select col_date,col_int,col_blob,col_year from v1;
col_date col_int col_blob col_year
2010-04-24 5 foo 1982
connection master;
DROP VIEW v1;
set binlog_row_image="MINIMAL";
CREATE VIEW v1 AS SELECT * FROM t1;
REPLACE INTO v1 SELECT pk, vcol_date, vcol_int, vcol_year, vcol_blob, col_date, col_int, col_blob, 1983 FROM t1;
Warnings:
Warning 1906 The value specified for generated column 'vcol_date' in table 't1' ignored
Warning 1906 The value specified for generated column 'vcol_int' in table 't1' ignored
Warning 1906 The value specified for generated column 'vcol_year' in table 't1' ignored
Warning 1906 The value specified for generated column 'vcol_blob' in table 't1' ignored
select col_date,col_int,col_blob,col_year from v1;
col_date col_int col_blob col_year
2010-04-24 5 foo 1983
connection slave;
select col_date,col_int,col_blob,col_year from v1;
col_date col_int col_blob col_year
2010-04-24 5 foo 1983
connection master;
DROP VIEW v1;
set @@binlog_row_image="NOBLOB";
CREATE VIEW v1 AS SELECT * FROM t1;
REPLACE INTO v1 SELECT pk, vcol_date, vcol_int, vcol_year, vcol_blob, col_date, col_int, col_blob, 1984 FROM t1;
Warnings:
Warning 1906 The value specified for generated column 'vcol_date' in table 't1' ignored
Warning 1906 The value specified for generated column 'vcol_int' in table 't1' ignored
Warning 1906 The value specified for generated column 'vcol_year' in table 't1' ignored
Warning 1906 The value specified for generated column 'vcol_blob' in table 't1' ignored
select col_date,col_int,col_blob,col_year from v1;
col_date col_int col_blob col_year
2010-04-24 5 foo 1984
connection slave;
select col_date,col_int,col_blob,col_year from v1;
col_date col_int col_blob col_year
2010-04-24 5 foo 1984
connection master;
DROP VIEW v1;
set @@binlog_row_image=default;
DROP TABLE t1;
include/rpl_end.inc

View File

@ -0,0 +1,361 @@
set binlog_row_image="FULL";
set @@default_storage_engine="myisam";
create table t1 (a int, b int as (a+1), c int as (b+1) stored);
insert t1 set a=1;
select * from t1;
a b c
1 2 3
update t1 set a=2;
select * from t1;
a b c
2 3 4
drop table t1;
create table t1 (a int, c int as(a), p varchar(20) as(y), y char(20), index (p,c));
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL,
`c` int(11) GENERATED ALWAYS AS (`a`) VIRTUAL,
`p` varchar(20) GENERATED ALWAYS AS (`y`) VIRTUAL,
`y` char(20) DEFAULT NULL,
KEY `p` (`p`,`c`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
insert into t1 (a,y) values(1, "yyy");
update t1 set a = 100 where a = 1;
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
create table t1 (
a varchar(10000),
b varchar(3000),
c varchar(14000) generated always as (concat(a,b)) virtual,
d varchar(5000) generated always as (b) virtual,
e int(11) generated always as (10) virtual,
h int(11) not null primary key,
index(c(100), d(20)));
insert t1 (a,b,h) values (repeat('g', 10000), repeat('x', 2800), 1);
update t1 set a = repeat(cast(1 as char), 2000);
drop table t1;
create table t1 (
a varchar(10000),
b varchar(3000),
c varchar(14000) generated always as (concat(a,b)) virtual,
i varchar(5000) generated always as (b) virtual,
d varchar(5000) generated always as (i) virtual,
e int(11) generated always as (10) virtual,
h int(11) not null primary key,
index(c(100), d(20)));
insert t1 (a,b,h) values (repeat('g', 10000), repeat('x', 2800), 1);
update t1 set a = repeat(cast(1 as char), 2000);
drop table t1;
create table t1(a blob not null, b int, c varbinary (10) generated always as (a) virtual, unique (c(9)));
insert t1 (a,b) values ('a', 1);
replace t1 set a = 'a',b =1;
insert t1 (a,b) values ('a', 1) on duplicate key update a='b', b=2;
select * from t1;
a b c
b 2 b
drop table t1;
create table t (a int primary key, b int, c int as (b), index (c));
insert t (a,b) values (9,0);
create table t2 select * from t;
update t, t2 set t.b=10 where t.a=t2.a;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c
9 10 10
drop table t, t2;
create table t1 (a int, b int, c int, d int, e int);
insert t1 values (1,2,3,4,5), (1,2,3,4,5);
SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR
create table t (a int primary key,
b int, c blob as (b), index (c(57)),
d blob, e blob as (d), index (e(57)))
replace select * from t1;
Warnings:
Warning 1906 The value specified for generated column 'c' in table 't' ignored
Warning 1906 The value specified for generated column 'e' in table 't' ignored
Warning 1906 The value specified for generated column 'c' in table 't' ignored
Warning 1906 The value specified for generated column 'e' in table 't' ignored
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
1 2 2 4 4
update t set a=10, b=1, d=1;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 1 1 1 1
replace t (a,b,d) values (10,2,2);
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 2 2 2 2
insert t(a,b,d) values (10) on duplicate key update b=3;
ERROR 21S01: Column count doesn't match value count at row 1
insert t(a,b,d) values (10,2,2) on duplicate key update b=3, d=3;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 3 3 3 3
replace t (a,b,d) select 10,4,4;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 4 4 4 4
insert t(a,b,d) select 10,4,4 on duplicate key update b=5, d=5;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 5 5 5 5
replace delayed t (a,b,d) values (10,6,6);
flush tables;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 6 6 6 6
insert delayed t(a,b,d) values (10,6,6) on duplicate key update b=7, d=7;
flush tables;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 7 7 7 7
load data infile 'MYSQLTEST_VARDIR/tmp/vblobs.txt' replace into table t;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 8 8 8 8
update t set a=11, b=9, d=9 where a>5;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
11 9 9 9 9
create table t2 select * from t;
update t, t2 set t.b=10, t.d=10 where t.a=t2.a;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
11 10 10 10 10
update t, t tt set t.b=11, tt.d=11 where t.a=tt.a;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
11 11 11 11 11
drop table t, t1, t2;
create table t (f1 int, f2 int, f3 int as (f1*2) virtual, key(f3,f2));
insert into t (f1,f2) values (1,1),(2,2);
create view v as
select a2.f1, a2.f2, a1.f3
from t a1, t a2
where a2.f3 <> 0
with local check option;
update v set f3 = 52;
drop view v;
drop table t;
set binlog_row_image="MINIMAL";
create table t1 (a int, b int as (a+1), c int as (b+1) stored);
insert t1 set a=1;
select * from t1;
a b c
1 2 3
update t1 set a=2;
select * from t1;
a b c
2 3 4
drop table t1;
create table t1 (a int, c int as(a), p varchar(20) as(y), y char(20), index (p,c));
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL,
`c` int(11) GENERATED ALWAYS AS (`a`) VIRTUAL,
`p` varchar(20) GENERATED ALWAYS AS (`y`) VIRTUAL,
`y` char(20) DEFAULT NULL,
KEY `p` (`p`,`c`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
insert into t1 (a,y) values(1, "yyy");
update t1 set a = 100 where a = 1;
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
create table t1 (
a varchar(10000),
b varchar(3000),
c varchar(14000) generated always as (concat(a,b)) virtual,
d varchar(5000) generated always as (b) virtual,
e int(11) generated always as (10) virtual,
h int(11) not null primary key,
index(c(100), d(20)));
insert t1 (a,b,h) values (repeat('g', 10000), repeat('x', 2800), 1);
update t1 set a = repeat(cast(1 as char), 2000);
drop table t1;
create table t1 (
a varchar(10000),
b varchar(3000),
c varchar(14000) generated always as (concat(a,b)) virtual,
i varchar(5000) generated always as (b) virtual,
d varchar(5000) generated always as (i) virtual,
e int(11) generated always as (10) virtual,
h int(11) not null primary key,
index(c(100), d(20)));
insert t1 (a,b,h) values (repeat('g', 10000), repeat('x', 2800), 1);
update t1 set a = repeat(cast(1 as char), 2000);
drop table t1;
create table t1(a blob not null, b int, c varbinary (10) generated always as (a) virtual, unique (c(9)));
insert t1 (a,b) values ('a', 1);
replace t1 set a = 'a',b =1;
insert t1 (a,b) values ('a', 1) on duplicate key update a='b', b=2;
select * from t1;
a b c
b 2 b
drop table t1;
create table t (a int primary key, b int, c int as (b), index (c));
insert t (a,b) values (9,0);
create table t2 select * from t;
update t, t2 set t.b=10 where t.a=t2.a;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c
9 10 10
drop table t, t2;
create table t1 (a int, b int, c int, d int, e int);
insert t1 values (1,2,3,4,5), (1,2,3,4,5);
SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR
create table t (a int primary key,
b int, c blob as (b), index (c(57)),
d blob, e blob as (d), index (e(57)))
replace select * from t1;
Warnings:
Warning 1906 The value specified for generated column 'c' in table 't' ignored
Warning 1906 The value specified for generated column 'e' in table 't' ignored
Warning 1906 The value specified for generated column 'c' in table 't' ignored
Warning 1906 The value specified for generated column 'e' in table 't' ignored
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
1 2 2 4 4
update t set a=10, b=1, d=1;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 1 1 1 1
replace t (a,b,d) values (10,2,2);
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 2 2 2 2
insert t(a,b,d) values (10) on duplicate key update b=3;
ERROR 21S01: Column count doesn't match value count at row 1
insert t(a,b,d) values (10,2,2) on duplicate key update b=3, d=3;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 3 3 3 3
replace t (a,b,d) select 10,4,4;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 4 4 4 4
insert t(a,b,d) select 10,4,4 on duplicate key update b=5, d=5;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 5 5 5 5
replace delayed t (a,b,d) values (10,6,6);
flush tables;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 6 6 6 6
insert delayed t(a,b,d) values (10,6,6) on duplicate key update b=7, d=7;
flush tables;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 7 7 7 7
load data infile 'MYSQLTEST_VARDIR/tmp/vblobs.txt' replace into table t;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
10 8 8 8 8
update t set a=11, b=9, d=9 where a>5;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
11 9 9 9 9
create table t2 select * from t;
update t, t2 set t.b=10, t.d=10 where t.a=t2.a;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
11 10 10 10 10
update t, t tt set t.b=11, tt.d=11 where t.a=tt.a;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
select * from t;
a b c d e
11 11 11 11 11
drop table t, t1, t2;
create table t (f1 int, f2 int, f3 int as (f1*2) virtual, key(f3,f2));
insert into t (f1,f2) values (1,1),(2,2);
create view v as
select a2.f1, a2.f2, a1.f3
from t a1, t a2
where a2.f3 <> 0
with local check option;
update v set f3 = 52;
drop view v;
drop table t;

View File

@ -0,0 +1,55 @@
--source include/have_innodb.inc
--source include/have_binlog_format_row.inc
--source include/master-slave.inc
#
# MDEV-15243
# Server crashes in in Field_blob::pack upon REPLACE into view with virtual
# columns with binlog enabled
#
CREATE TABLE t1 (
pk SERIAL,
vcol_date DATE AS (col_date) PERSISTENT,
vcol_int INT AS (col_int) VIRTUAL,
vcol_year YEAR AS (col_year) PERSISTENT,
vcol_blob BLOB AS (col_blob) VIRTUAL,
col_date DATE,
col_int INT NULL,
col_blob BLOB NULL,
col_year YEAR,
PRIMARY KEY(pk)
) ENGINE=InnoDB;
INSERT INTO t1 (col_date,col_int,col_blob,col_year) VALUES ('2010-04-24',5,'foo',1981);
SET SQL_MODE='';
set binlog_row_image="FULL";
CREATE VIEW v1 AS SELECT * FROM t1;
REPLACE INTO v1 SELECT pk, vcol_date, vcol_int, vcol_year, vcol_blob, col_date, col_int, col_blob, 1982 FROM t1;
select col_date,col_int,col_blob,col_year from v1;
sync_slave_with_master;
select col_date,col_int,col_blob,col_year from v1;
connection master;
DROP VIEW v1;
set binlog_row_image="MINIMAL";
CREATE VIEW v1 AS SELECT * FROM t1;
REPLACE INTO v1 SELECT pk, vcol_date, vcol_int, vcol_year, vcol_blob, col_date, col_int, col_blob, 1983 FROM t1;
select col_date,col_int,col_blob,col_year from v1;
sync_slave_with_master;
select col_date,col_int,col_blob,col_year from v1;
connection master;
DROP VIEW v1;
set @@binlog_row_image="NOBLOB";
CREATE VIEW v1 AS SELECT * FROM t1;
REPLACE INTO v1 SELECT pk, vcol_date, vcol_int, vcol_year, vcol_blob, col_date, col_int, col_blob, 1984 FROM t1;
select col_date,col_int,col_blob,col_year from v1;
sync_slave_with_master;
select col_date,col_int,col_blob,col_year from v1;
connection master;
DROP VIEW v1;
set @@binlog_row_image=default;
DROP TABLE t1;
--source include/rpl_end.inc

View File

@ -0,0 +1,14 @@
#
# Check that vcol update works with binlog enabled
#
--source include/have_binlog_format_row.inc
set binlog_row_image="FULL";
set @@default_storage_engine="myisam";
--source update.test
set binlog_row_image="MINIMAL";
--source update.test

View File

@ -3662,7 +3662,7 @@ public:
DBUG_ASSERT(number < UINT_MAX32);
store_length(ptr, packlength, (uint32)number);
}
inline uint32 get_length(uint row_offset= 0) const
inline uint32 get_length(my_ptrdiff_t row_offset= 0) const
{ return get_length(ptr+row_offset, this->packlength); }
uint32 get_length(const uchar *ptr, uint packlength) const;
uint32 get_length(const uchar *ptr_arg) const

View File

@ -49,8 +49,8 @@ static int my_b_encr_read(IO_CACHE *info, uchar *Buffer, size_t Count)
if (pos_in_file == info->end_of_file)
{
info->read_pos= info->read_end= info->buffer;
info->pos_in_file= pos_in_file;
/* reading past EOF should not empty the cache */
info->read_pos= info->read_end;
info->error= 0;
DBUG_RETURN(MY_TEST(Count));
}

View File

@ -2192,7 +2192,8 @@ static void mysqld_exit(int exit_code)
if (opt_endinfo && global_status_var.global_memory_used)
fprintf(stderr, "Warning: Memory not freed: %ld\n",
(long) global_status_var.global_memory_used);
if (!opt_debugging && !my_disable_leak_check && exit_code == 0)
if (!opt_debugging && !my_disable_leak_check && exit_code == 0 &&
debug_assert_on_not_freed_memory)
{
#ifdef SAFEMALLOC
sf_report_leaked_memory(0);

View File

@ -430,7 +430,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
HA_CHECK_OPT* check_opt,
const char *operator_name,
thr_lock_type lock_type,
bool open_for_modify,
bool org_open_for_modify,
bool repair_table_use_frm,
uint extra_open_options,
int (*prepare_func)(THD *, TABLE_LIST *,
@ -497,6 +497,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
bool fatal_error=0;
bool open_error;
bool collect_eis= FALSE;
bool open_for_modify= org_open_for_modify;
DBUG_PRINT("admin", ("table: '%s'.'%s'", db, table->table_name.str));
strxmov(table_name, db, ".", table->table_name.str, NullS);
@ -1164,7 +1165,7 @@ send_result_message:
}
}
/* Error path, a admin command failed. */
if (thd->transaction_rollback_request)
if (thd->transaction_rollback_request || fatal_error)
{
/*
Unlikely, but transaction rollback was requested by one of storage
@ -1220,7 +1221,9 @@ err:
}
close_thread_tables(thd); // Shouldn't be needed
thd->mdl_context.release_transactional_locks();
#ifdef WITH_PARTITION_STORAGE_ENGINE
err2:
#endif
thd->resume_subsequent_commits(suspended_wfc);
DBUG_RETURN(TRUE);
}

View File

@ -402,8 +402,8 @@ bool Sql_cmd_alter_table::execute(THD *thd)
- For temporary MERGE tables we do not track if their child tables are
base or temporary. As result we can't guarantee that privilege check
which was done in presence of temporary child will stay relevant later
as this temporary table might be removed.
which was done in presence of temporary child will stay relevant
later as this temporary table might be removed.
If SELECT_ACL | UPDATE_ACL | DELETE_ACL privileges were not checked for
the underlying *base* tables, it would create a security breach as in
@ -443,6 +443,9 @@ bool Sql_cmd_alter_table::execute(THD *thd)
create_info.data_file_name= create_info.index_file_name= NULL;
thd->prepare_logs_for_admin_command();
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info= 0;
#endif
#ifdef WITH_WSREP
if ((!thd->is_current_stmt_binlog_format_row() ||

View File

@ -1481,15 +1481,15 @@ open_table_get_mdl_lock(THD *thd, Open_table_context *ot_ctx,
return FALSE;
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
/* Set all [named] partitions as used. */
static int set_partitions_as_used(TABLE_LIST *tl, TABLE *t)
{
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (t->part_info)
return t->file->change_partitions_to_open(tl->partition_names);
#endif
return 0;
}
#endif
/**
@ -1535,7 +1535,9 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
MDL_ticket *mdl_ticket;
TABLE_SHARE *share;
uint gts_flags;
#ifdef WITH_PARTITION_STORAGE_ENGINE
int part_names_error=0;
#endif
DBUG_ENTER("open_table");
/*
@ -1633,7 +1635,9 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
table= best_table;
table->query_id= thd->query_id;
DBUG_PRINT("info",("Using locked table"));
#ifdef WITH_PARTITION_STORAGE_ENGINE
part_names_error= set_partitions_as_used(table_list, table);
#endif
goto reset;
}
/*
@ -1918,7 +1922,9 @@ retry_share:
{
DBUG_ASSERT(table->file != NULL);
MYSQL_REBIND_TABLE(table->file);
#ifdef WITH_PARTITION_STORAGE_ENGINE
part_names_error= set_partitions_as_used(table_list, table);
#endif
}
else
{

View File

@ -6686,7 +6686,8 @@ int THD::binlog_write_row(TABLE* table, bool is_trans,
Pack records into format for transfer. We are allocating more
memory than needed, but that doesn't matter.
*/
Row_data_memory memory(table, max_row_length(table, record));
Row_data_memory memory(table, max_row_length(table, table->rpl_write_set,
record));
if (!memory.has_memory())
return HA_ERR_OUT_OF_MEM;
@ -6723,8 +6724,10 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()));
size_t const before_maxlen = max_row_length(table, before_record);
size_t const after_maxlen = max_row_length(table, after_record);
size_t const before_maxlen= max_row_length(table, table->read_set,
before_record);
size_t const after_maxlen= max_row_length(table, table->rpl_write_set,
after_record);
Row_data_memory row_data(table, before_maxlen, after_maxlen);
if (!row_data.has_memory())
@ -6800,7 +6803,8 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
Pack records into format for transfer. We are allocating more
memory than needed, but that doesn't matter.
*/
Row_data_memory memory(table, max_row_length(table, record));
Row_data_memory memory(table, max_row_length(table, table->read_set,
record));
if (unlikely(!memory.has_memory()))
return HA_ERR_OUT_OF_MEM;
@ -6839,15 +6843,17 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
}
/**
Remove from read_set spurious columns. The write_set has been
handled before in table->mark_columns_needed_for_update.
*/
void THD::binlog_prepare_row_images(TABLE *table)
{
DBUG_ENTER("THD::binlog_prepare_row_images");
/**
Remove from read_set spurious columns. The write_set has been
handled before in table->mark_columns_needed_for_update.
*/
DBUG_PRINT_BITSET("debug", "table->read_set (before preparing): %s", table->read_set);
DBUG_PRINT_BITSET("debug", "table->read_set (before preparing): %s",
table->read_set);
THD *thd= table->in_use;
/**
@ -6865,7 +6871,7 @@ void THD::binlog_prepare_row_images(TABLE *table)
*/
DBUG_ASSERT(table->read_set != &table->tmp_set);
switch(thd->variables.binlog_row_image)
switch (thd->variables.binlog_row_image)
{
case BINLOG_ROW_IMAGE_MINIMAL:
/* MINIMAL: Mark only PK */
@ -6895,7 +6901,8 @@ void THD::binlog_prepare_row_images(TABLE *table)
table->write_set);
}
DBUG_PRINT_BITSET("debug", "table->read_set (after preparing): %s", table->read_set);
DBUG_PRINT_BITSET("debug", "table->read_set (after preparing): %s",
table->read_set);
DBUG_VOID_RETURN;
}

View File

@ -4568,6 +4568,12 @@ public:
/* Members related to temporary tables. */
public:
/* Opened table states. */
enum Temporary_table_state {
TMP_TABLE_IN_USE,
TMP_TABLE_NOT_IN_USE,
TMP_TABLE_ANY
};
bool has_thd_temporary_tables();
TABLE *create_and_open_tmp_table(handlerton *hton,
@ -4578,8 +4584,10 @@ public:
bool open_in_engine,
bool open_internal_tables);
TABLE *find_temporary_table(const char *db, const char *table_name);
TABLE *find_temporary_table(const TABLE_LIST *tl);
TABLE *find_temporary_table(const char *db, const char *table_name,
Temporary_table_state state= TMP_TABLE_IN_USE);
TABLE *find_temporary_table(const TABLE_LIST *tl,
Temporary_table_state state= TMP_TABLE_IN_USE);
TMP_TABLE_SHARE *find_tmp_table_share_w_base_key(const char *key,
uint key_length);
@ -4606,13 +4614,6 @@ private:
/* Whether a lock has been acquired? */
bool m_tmp_tables_locked;
/* Opened table states. */
enum Temporary_table_state {
TMP_TABLE_IN_USE,
TMP_TABLE_NOT_IN_USE,
TMP_TABLE_ANY
};
bool has_temporary_tables();
uint create_tmp_table_def_key(char *key, const char *db,
const char *table_name);

View File

@ -195,13 +195,14 @@ static void mysql_ha_close_childs(THD *thd, TABLE_LIST *current_table_list,
static void mysql_ha_close_table(SQL_HANDLER *handler)
{
DBUG_ENTER("mysql_ha_close_table");
THD *thd= handler->thd;
TABLE *table= handler->table;
TABLE_LIST *current_table_list= NULL, *next_global;
/* check if table was already closed */
if (!table)
return;
DBUG_VOID_RETURN;
if ((next_global= table->file->get_next_global_for_child()))
current_table_list= next_global->parent_l;
@ -232,6 +233,7 @@ static void mysql_ha_close_table(SQL_HANDLER *handler)
}
my_free(handler->lock);
handler->init();
DBUG_VOID_RETURN;
}
/*

View File

@ -775,6 +775,8 @@ void init_update_queries(void)
There are other statements that deal with temporary tables and open
them, but which are not listed here. The thing is that the order of
pre-opening temporary tables for those statements is somewhat custom.
Note that SQLCOM_RENAME_TABLE should not be in this list!
*/
sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DROP_TABLE]|= CF_PREOPEN_TMP_TABLES;
@ -789,7 +791,6 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_INSERT_SELECT]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DELETE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DELETE_MULTI]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_RENAME_TABLE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_REPLACE_SELECT]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_SELECT]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_SET_OPTION]|= CF_PREOPEN_TMP_TABLES;
@ -3237,10 +3238,6 @@ mysql_execute_command(THD *thd)
#endif
DBUG_ENTER("mysql_execute_command");
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info= 0;
#endif
DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt);
/*
Each statement or replication event which might produce deadlock
@ -4100,6 +4097,7 @@ mysql_execute_command(THD *thd)
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info= 0;
{
partition_info *part_info= thd->lex->part_info;
if (part_info && !(part_info= part_info->get_clone(thd)))
@ -6594,6 +6592,60 @@ static bool execute_show_status(THD *thd, TABLE_LIST *all_tables)
}
/*
Find out if a table is a temporary table
A table is a temporary table if it's a temporary table or
there has been before a temporary table that has been renamed
to the current name.
Some examples:
A->B B is a temporary table if and only if A is a temp.
A->B, B->C Second B is temp if A is temp
A->B, A->C Second A can't be temp as if A was temp then B is temp
and Second A can only be a normal table. C is also not temp
*/
static TABLE *find_temporary_table_for_rename(THD *thd,
TABLE_LIST *first_table,
TABLE_LIST *cur_table)
{
TABLE_LIST *table;
TABLE *res= 0;
bool found= 0;
DBUG_ENTER("find_temporary_table_for_rename");
/* Find last instance when cur_table is in TO part */
for (table= first_table;
table != cur_table;
table= table->next_local->next_local)
{
TABLE_LIST *next= table->next_local;
if (!strcmp(table->get_db_name(), cur_table->get_db_name()) &&
!strcmp(table->get_table_name(), cur_table->get_table_name()))
{
/* Table was moved away, can't be same as 'table' */
found= 1;
res= 0; // Table can't be a temporary table
}
if (!strcmp(next->get_db_name(), cur_table->get_db_name()) &&
!strcmp(next->get_table_name(), cur_table->get_table_name()))
{
/*
Table has matching name with new name of this table. cur_table should
have same temporary type as this table.
*/
found= 1;
res= table->table;
}
}
if (!found)
res= thd->find_temporary_table(table, THD::TMP_TABLE_ANY);
DBUG_RETURN(res);
}
static bool check_rename_table(THD *thd, TABLE_LIST *first_table,
TABLE_LIST *all_tables)
{
@ -6610,13 +6662,19 @@ static bool check_rename_table(THD *thd, TABLE_LIST *first_table,
&table->next_local->grant.m_internal,
0, 0))
return 1;
/* check if these are refering to temporary tables */
table->table= find_temporary_table_for_rename(thd, first_table, table);
table->next_local->table= table->table;
TABLE_LIST old_list, new_list;
/*
we do not need initialize old_list and new_list because we will
come table[0] and table->next[0] there
copy table[0] and table->next[0] there
*/
old_list= table[0];
new_list= table->next_local[0];
if (check_grant(thd, ALTER_ACL | DROP_ACL, &old_list, FALSE, 1, FALSE) ||
(!test_all_bits(table->next_local->grant.privilege,
INSERT_ACL | CREATE_ACL) &&

View File

@ -223,7 +223,7 @@ do_rename_temporary(THD *thd, TABLE_LIST *ren_table, TABLE_LIST *new_table,
new_alias= (lower_case_table_names == 2) ? &new_table->alias :
&new_table->table_name;
if (is_temporary_table(new_table))
if (thd->find_temporary_table(new_table, THD::TMP_TABLE_ANY))
{
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias->str);
DBUG_RETURN(1); // This can't be skipped

View File

@ -1517,7 +1517,8 @@ public:
~Stat_table_write_iter()
{
cleanup();
/* Ensure that cleanup has been run */
DBUG_ASSERT(rowid_buf == 0);
}
};

View File

@ -240,8 +240,17 @@ bool String::copy(const char *str,size_t arg_length, CHARSET_INFO *cs)
{
if (alloc(arg_length))
return TRUE;
DBUG_ASSERT(arg_length <= UINT_MAX32);
if ((str_length=(uint32)arg_length))
DBUG_ASSERT(arg_length < UINT_MAX32);
if (Ptr == str && arg_length == uint32(str_length))
{
/*
This can happen in some cases. This code is here mainly to avoid
warnings from valgrind, but can also be an indication of error.
*/
DBUG_PRINT("warning", ("Copying string on itself: %p %zu",
str, arg_length));
}
else if ((str_length=uint32(arg_length)))
memcpy(Ptr,str,arg_length);
Ptr[arg_length]=0;
str_charset=cs;

View File

@ -6095,10 +6095,28 @@ drop_create_field:
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
Alter_drop *drop;
bool remove_drop;
ulonglong left_flags= 0;
while ((drop= drop_it++))
{
ulonglong cur_flag= 0;
switch (drop->type) {
case Alter_drop::COLUMN:
cur_flag= ALTER_PARSER_DROP_COLUMN;
break;
case Alter_drop::FOREIGN_KEY:
cur_flag= ALTER_DROP_FOREIGN_KEY;
break;
case Alter_drop::KEY:
cur_flag= ALTER_DROP_INDEX;
break;
default:
break;
}
if (!drop->drop_if_exists)
{
left_flags|= cur_flag;
continue;
}
remove_drop= TRUE;
if (drop->type == Alter_drop::COLUMN)
{
@ -6190,12 +6208,15 @@ drop_create_field:
ER_THD(thd, ER_CANT_DROP_FIELD_OR_KEY),
drop->type_name(), drop->name);
drop_it.remove();
if (alter_info->drop_list.is_empty())
alter_info->flags&= ~(ALTER_PARSER_DROP_COLUMN |
ALTER_DROP_INDEX |
ALTER_DROP_FOREIGN_KEY);
}
else
left_flags|= cur_flag;
}
/* Reset state to what's left in drop list */
alter_info->flags&= ~(ALTER_PARSER_DROP_COLUMN |
ALTER_DROP_INDEX |
ALTER_DROP_FOREIGN_KEY);
alter_info->flags|= left_flags;
}
/* ALTER TABLE ADD KEY IF NOT EXISTS */
@ -6309,8 +6330,9 @@ remove_key:
}
}
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
DBUG_ASSERT(thd->work_part_info == 0);
partition_info *tab_part_info= table->part_info;
thd->work_part_info= thd->lex->part_info;
if (tab_part_info)
@ -9017,6 +9039,10 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
{
DBUG_ENTER("mysql_alter_table");
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info= 0; // Used by partitioning
#endif
/*
Check if we attempt to alter mysql.slow_log or
mysql.general_log table and return an error if

View File

@ -624,6 +624,7 @@ end:
#endif /* WITH_WSREP */
}
/**
Build stmt_query to write it in the bin-log, the statement to write in
the trigger file and the trigger definer.
@ -1191,6 +1192,12 @@ Table_triggers_list::~Table_triggers_list()
}
}
}
/* Free blobs used in insert */
if (record0_field)
for (Field **fld_ptr= record0_field; *fld_ptr; fld_ptr++)
(*fld_ptr)->free();
if (record1_field)
for (Field **fld_ptr= record1_field; *fld_ptr; fld_ptr++)
delete *fld_ptr;

View File

@ -2770,6 +2770,9 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write,
goto ret;
thd->lex->create_info.db_type= hton;
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info= 0; // For partitioning
#endif
if (tabledef_version.str)
thd->lex->create_info.tabledef_version= tabledef_version;
@ -6682,6 +6685,12 @@ void TABLE::mark_columns_per_binlog_row_image()
DBUG_ASSERT(FALSE);
}
}
/*
We have to ensure that all virtual columns that are part of read set
are calculated.
*/
if (vcol_set)
bitmap_union(vcol_set, read_set);
file->column_bitmaps_signal();
}
@ -6723,7 +6732,8 @@ bool TABLE::mark_virtual_col(Field *field)
/*
@brief Mark virtual columns for update/insert commands
@param insert_fl <-> virtual columns are marked for insert command
@param insert_fl true if virtual columns are marked for insert command
For the moment this is not used, may be used in future.
@details
The function marks virtual columns used in a update/insert commands
@ -6748,7 +6758,8 @@ bool TABLE::mark_virtual_col(Field *field)
be added to read_set either.
*/
bool TABLE::mark_virtual_columns_for_write(bool insert_fl)
bool TABLE::mark_virtual_columns_for_write(bool insert_fl
__attribute__((unused)))
{
Field **vfield_ptr, *tmp_vfield;
bool bitmap_updated= false;
@ -6758,35 +6769,13 @@ bool TABLE::mark_virtual_columns_for_write(bool insert_fl)
{
tmp_vfield= *vfield_ptr;
if (bitmap_is_set(write_set, tmp_vfield->field_index))
bitmap_updated= mark_virtual_col(tmp_vfield);
bitmap_updated|= mark_virtual_col(tmp_vfield);
else if (tmp_vfield->vcol_info->stored_in_db ||
(tmp_vfield->flags & (PART_KEY_FLAG | FIELD_IN_PART_FUNC_FLAG)))
{
if (insert_fl)
{
bitmap_set_bit(write_set, tmp_vfield->field_index);
mark_virtual_col(tmp_vfield);
bitmap_updated= true;
}
else
{
MY_BITMAP *save_read_set= read_set, *save_vcol_set= vcol_set;
Item *vcol_item= tmp_vfield->vcol_info->expr;
DBUG_ASSERT(vcol_item);
bitmap_clear_all(&tmp_set);
read_set= vcol_set= &tmp_set;
vcol_item->walk(&Item::register_field_in_read_map, 1, 0);
read_set= save_read_set;
vcol_set= save_vcol_set;
if (bitmap_is_overlapping(&tmp_set, write_set))
{
bitmap_set_bit(write_set, tmp_vfield->field_index);
bitmap_set_bit(vcol_set, tmp_vfield->field_index);
bitmap_union(read_set, &tmp_set);
bitmap_union(vcol_set, &tmp_set);
bitmap_updated= true;
}
}
bitmap_set_bit(write_set, tmp_vfield->field_index);
mark_virtual_col(tmp_vfield);
bitmap_updated= true;
}
}
if (bitmap_updated)
@ -7432,8 +7421,8 @@ bool TABLE_LIST::process_index_hints(TABLE *tbl)
}
/*
TODO: get rid of tbl->force_index (on if any FORCE INDEX is specified) and
create tbl->force_index_join instead.
TODO: get rid of tbl->force_index (on if any FORCE INDEX is specified)
and create tbl->force_index_join instead.
Then use the correct force_index_XX instead of the global one.
*/
if (!index_join[INDEX_HINT_FORCE].is_clear_all() ||
@ -7463,21 +7452,27 @@ bool TABLE_LIST::process_index_hints(TABLE *tbl)
}
size_t max_row_length(TABLE *table, const uchar *data)
size_t max_row_length(TABLE *table, MY_BITMAP const *cols, const uchar *data)
{
TABLE_SHARE *table_s= table->s;
size_t length= table_s->reclength + 2 * table_s->fields;
uint *const beg= table_s->blob_field;
uint *const end= beg + table_s->blob_fields;
my_ptrdiff_t const rec_offset= (my_ptrdiff_t) (data - table->record[0]);
DBUG_ENTER("max_row_length");
for (uint *ptr= beg ; ptr != end ; ++ptr)
{
Field_blob* const blob= (Field_blob*) table->field[*ptr];
length+= blob->get_length((const uchar*)
(data + blob->offset(table->record[0]))) +
HA_KEY_BLOB_LENGTH;
Field * const field= table->field[*ptr];
if (bitmap_is_set(cols, field->field_index) &&
!field->is_null(rec_offset))
{
Field_blob * const blob= (Field_blob*) field;
length+= blob->get_length(rec_offset) + 8; /* max blob store length */
}
}
return length;
DBUG_PRINT("exit", ("length: %lld", (longlong) length));
DBUG_RETURN(length);
}
@ -7592,7 +7587,7 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
Query_arena backup_arena;
Turn_errors_to_warnings_handler Suppress_errors;
int error;
bool handler_pushed= 0;
bool handler_pushed= 0, update_all_columns= 1;
DBUG_ASSERT(vfield);
if (h->keyread_enabled())
@ -7609,6 +7604,16 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
in_use->push_internal_handler(&Suppress_errors);
handler_pushed= 1;
}
else if (update_mode == VCOL_UPDATE_FOR_REPLACE &&
in_use->is_current_stmt_binlog_format_row() &&
in_use->variables.binlog_row_image != BINLOG_ROW_IMAGE_MINIMAL)
{
/*
If we are doing a replace with not minimal binary logging, we have to
calculate all virtual columns.
*/
update_all_columns= 1;
}
/* Iterate over virtual fields in the table */
for (vfield_ptr= vfield; *vfield_ptr; vfield_ptr++)
@ -7621,8 +7626,8 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
bool update= 0, swap_values= 0;
switch (update_mode) {
case VCOL_UPDATE_FOR_READ:
update= !vcol_info->stored_in_db
&& bitmap_is_set(vcol_set, vf->field_index);
update= (!vcol_info->stored_in_db &&
bitmap_is_set(vcol_set, vf->field_index));
swap_values= 1;
break;
case VCOL_UPDATE_FOR_DELETE:
@ -7630,8 +7635,9 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
update= bitmap_is_set(vcol_set, vf->field_index);
break;
case VCOL_UPDATE_FOR_REPLACE:
update= !vcol_info->stored_in_db && (vf->flags & PART_KEY_FLAG)
&& bitmap_is_set(vcol_set, vf->field_index);
update= ((!vcol_info->stored_in_db && (vf->flags & PART_KEY_FLAG) &&
bitmap_is_set(vcol_set, vf->field_index)) ||
update_all_columns);
if (update && (vf->flags & BLOB_FLAG))
{
/*
@ -7648,8 +7654,8 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
case VCOL_UPDATE_INDEXED:
case VCOL_UPDATE_INDEXED_FOR_UPDATE:
/* Read indexed fields that was not updated in VCOL_UPDATE_FOR_READ */
update= !vcol_info->stored_in_db && (vf->flags & PART_KEY_FLAG) &&
bitmap_is_set(vcol_set, vf->field_index);
update= (!vcol_info->stored_in_db && (vf->flags & PART_KEY_FLAG) &&
!bitmap_is_set(vcol_set, vf->field_index));
swap_values= 1;
break;
}

View File

@ -2879,7 +2879,7 @@ enum get_table_share_flags {
GTS_FORCE_DISCOVERY = 16
};
size_t max_row_length(TABLE *table, const uchar *data);
size_t max_row_length(TABLE *table, MY_BITMAP const *cols, const uchar *data);
void init_mdl_requests(TABLE_LIST *table_list);

View File

@ -112,12 +112,14 @@ TABLE *THD::create_and_open_tmp_table(handlerton *hton,
@param db [IN] Database name
@param table_name [IN] Table name
@param state [IN] State of temp table to open
@return Success Pointer to first used table instance.
Failure NULL
*/
TABLE *THD::find_temporary_table(const char *db,
const char *table_name)
const char *table_name,
Temporary_table_state state)
{
DBUG_ENTER("THD::find_temporary_table");
@ -134,7 +136,7 @@ TABLE *THD::find_temporary_table(const char *db,
key_length= create_tmp_table_def_key(key, db, table_name);
locked= lock_temporary_tables();
table = find_temporary_table(key, key_length, TMP_TABLE_IN_USE);
table= find_temporary_table(key, key_length, state);
if (locked)
{
DBUG_ASSERT(m_tmp_tables_locked);
@ -153,16 +155,12 @@ TABLE *THD::find_temporary_table(const char *db,
@return Success Pointer to first used table instance.
Failure NULL
*/
TABLE *THD::find_temporary_table(const TABLE_LIST *tl)
TABLE *THD::find_temporary_table(const TABLE_LIST *tl,
Temporary_table_state state)
{
DBUG_ENTER("THD::find_temporary_table");
if (!has_temporary_tables())
{
DBUG_RETURN(NULL);
}
TABLE *table= find_temporary_table(tl->get_db_name(), tl->get_table_name());
TABLE *table= find_temporary_table(tl->get_db_name(), tl->get_table_name(),
state);
DBUG_RETURN(table);
}

View File

@ -898,18 +898,19 @@ int ha_archive::real_write_row(uchar *buf, azio_stream *writer)
the bytes required for the length in the header.
*/
uint32 ha_archive::max_row_length(const uchar *buf)
uint32 ha_archive::max_row_length(const uchar *record)
{
uint32 length= (uint32)(table->s->reclength + table->s->fields*2);
length+= ARCHIVE_ROW_HEADER_SIZE;
my_ptrdiff_t const rec_offset= record - table->record[0];
uint *ptr, *end;
for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
ptr != end ;
ptr++)
{
if (!table->field[*ptr]->is_null())
length += 2 + ((Field_blob*)table->field[*ptr])->get_length();
if (!table->field[*ptr]->is_null(rec_offset))
length += 2 + ((Field_blob*)table->field[*ptr])->get_length(rec_offset);
}
return length;
@ -919,10 +920,9 @@ uint32 ha_archive::max_row_length(const uchar *buf)
unsigned int ha_archive::pack_row(uchar *record, azio_stream *writer)
{
uchar *ptr;
my_ptrdiff_t const rec_offset= record - table->record[0];
DBUG_ENTER("ha_archive::pack_row");
if (fix_rec_buff(max_row_length(record)))
DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
@ -936,7 +936,7 @@ unsigned int ha_archive::pack_row(uchar *record, azio_stream *writer)
for (Field **field=table->field ; *field ; field++)
{
if (!((*field)->is_null()))
if (!((*field)->is_null(rec_offset)))
ptr= (*field)->pack(ptr, record + (*field)->offset(record));
}

View File

@ -1145,7 +1145,7 @@ retry:
#endif
ut_ad(btr_search_enabled);
ut_ad(block->page.id.space() == index->table->space->id);
ut_ad(block->page.id.space() == index->table->space_id);
ut_a(index_id == index->id);
ut_a(!dict_index_is_ibuf(index));
#ifdef UNIV_DEBUG
@ -1271,9 +1271,8 @@ cleanup:
ut_free(folds);
}
/** Drop any adaptive hash index entries that may point to an index
page that may be in the buffer pool, when a page is evicted from the
buffer pool or freed in a file segment.
/** Drop possible adaptive hash index entries when a page is evicted
from the buffer pool or freed in a file, or the index is being dropped.
@param[in] page_id page id */
void btr_search_drop_page_hash_when_freed(const page_id_t& page_id)
{
@ -2056,7 +2055,7 @@ btr_search_hash_table_validate(ulint hash_table_id)
ut_a(!dict_index_is_ibuf(block->index));
ut_ad(block->page.id.space()
== block->index->table->space->id);
== block->index->table->space_id);
page_index_id = btr_page_get_index_id(block->frame);

View File

@ -225,24 +225,17 @@ particular space id.
@param[in] count number of entries in array */
static
void
buf_LRU_drop_page_hash_batch(
ulint space_id,
const ulint* arr,
ulint count)
buf_LRU_drop_page_hash_batch(ulint space_id, const ulint* arr, ulint count)
{
ut_ad(count <= BUF_LRU_DROP_SEARCH_SIZE);
for (ulint i = 0; i < count; ++i, ++arr) {
for (const ulint* const end = arr + count; arr != end; ) {
/* While our only caller
buf_LRU_drop_page_hash_for_tablespace()
is being executed for DROP TABLE or similar,
the table cannot be evicted from the buffer pool.
Note: this should not be executed for DROP TABLESPACE,
because DROP TABLESPACE would be refused if tables existed
in the tablespace, and a previous DROP TABLE would have
already removed the AHI entries. */
the table cannot be evicted from the buffer pool. */
btr_search_drop_page_hash_when_freed(
page_id_t(space_id, *arr));
page_id_t(space_id, *arr++));
}
}
@ -359,6 +352,28 @@ next_page:
buf_LRU_drop_page_hash_batch(id, page_arr, num_entries);
ut_free(page_arr);
}
/** Drop the adaptive hash index for a tablespace.
@param[in,out] table table */
void buf_LRU_drop_page_hash_for_tablespace(dict_table_t* table)
{
for (dict_index_t* index = dict_table_get_first_index(table);
index != NULL;
index = dict_table_get_next_index(index)) {
if (btr_search_info_get_ref_count(btr_search_get_info(index),
index)) {
goto drop_ahi;
}
}
return;
drop_ahi:
ulint id = table->space_id;
for (ulint i = 0; i < srv_buf_pool_instances; i++) {
buf_LRU_drop_page_hash_for_tablespace(buf_pool_from_array(i),
id);
}
}
#endif /* BTR_CUR_HASH_ADAPT */
/******************************************************************//**
@ -682,26 +697,13 @@ buf_flush_dirty_pages(
@param[in] id tablespace identifier
@param[in] observer flush observer,
or NULL if nothing is to be written */
void
buf_LRU_flush_or_remove_pages(
ulint id,
FlushObserver* observer
#ifdef BTR_CUR_HASH_ADAPT
, bool drop_ahi /*!< whether to drop the adaptive hash index */
#endif /* BTR_CUR_HASH_ADAPT */
)
void buf_LRU_flush_or_remove_pages(ulint id, FlushObserver* observer)
{
/* Pages in the system tablespace must never be discarded. */
ut_ad(id || observer);
for (ulint i = 0; i < srv_buf_pool_instances; i++) {
buf_pool_t* buf_pool = buf_pool_from_array(i);
#ifdef BTR_CUR_HASH_ADAPT
if (drop_ahi) {
buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
}
#endif /* BTR_CUR_HASH_ADAPT */
buf_flush_dirty_pages(buf_pool, id, observer);
buf_flush_dirty_pages(buf_pool_from_array(i), id, observer);
}
if (observer && !observer->is_interrupted()) {

View File

@ -1623,11 +1623,7 @@ dict_table_rename_in_cache(
return(DB_OUT_OF_MEMORY);
}
fil_delete_tablespace(table->space->id
#ifdef BTR_CUR_HASH_ADAPT
, true
#endif /* BTR_CUR_HASH_ADAPT */
);
fil_delete_tablespace(table->space_id);
/* Delete any temp file hanging around. */
if (os_file_status(filepath, &exists, &ftype)
@ -2593,28 +2589,13 @@ dict_index_remove_from_cache_low(
zero. See also: dict_table_can_be_evicted() */
do {
ulint ref_count = btr_search_info_get_ref_count(info, index);
if (ref_count == 0) {
if (!btr_search_info_get_ref_count(info, index)) {
break;
}
/* Sleep for 10ms before trying again. */
os_thread_sleep(10000);
++retries;
buf_LRU_drop_page_hash_for_tablespace(table);
if (retries % 500 == 0) {
/* No luck after 5 seconds of wait. */
ib::error() << "Waited for " << retries / 100
<< " secs for hash index"
" ref_count (" << ref_count << ") to drop to 0."
" index: " << index->name
<< " table: " << table->name;
}
/* To avoid a hang here we commit suicide if the
ref_count doesn't drop to zero in 600 seconds. */
ut_a(retries < 60000);
ut_a(++retries < 10000);
} while (srv_shutdown_state == SRV_SHUTDOWN_NONE || !lru_evict);
#endif /* BTR_CUR_HASH_ADAPT */

View File

@ -2698,11 +2698,7 @@ fil_delete_tablespace(
To deal with potential read requests, we will check the
::stop_new_ops flag in fil_io(). */
buf_LRU_flush_or_remove_pages(id, NULL
#ifdef BTR_CUR_HASH_ADAPT
, drop_ahi
#endif /* BTR_CUR_HASH_ADAPT */
);
buf_LRU_flush_or_remove_pages(id, NULL);
/* If it is a delete then also delete any generated files, otherwise
when we drop the database the remove directory will fail. */

View File

@ -119,11 +119,9 @@ btr_search_move_or_delete_hash_entries(
i.e.: it is in state BUF_BLOCK_REMOVE_HASH */
void btr_search_drop_page_hash_index(buf_block_t* block);
/** Drop any adaptive hash index entries that may point to an index
page that may be in the buffer pool, when a page is evicted from the
buffer pool or freed in a file segment.
@param[in] page_id page id
@param[in] page_size page size */
/** Drop possible adaptive hash index entries when a page is evicted
from the buffer pool or freed in a file, or the index is being dropped.
@param[in] page_id page id */
void btr_search_drop_page_hash_when_freed(const page_id_t& page_id);
/** Updates the page hash index when a single record is inserted on a page.

View File

@ -51,18 +51,20 @@ These are low-level functions
/** Minimum LRU list length for which the LRU_old pointer is defined */
#define BUF_LRU_OLD_MIN_LEN 512 /* 8 megabytes of 16k pages */
#ifdef BTR_CUR_HASH_ADAPT
struct dict_table_t;
/** Drop the adaptive hash index for a tablespace.
@param[in,out] table table */
void buf_LRU_drop_page_hash_for_tablespace(dict_table_t* table);
#else
# define buf_LRU_drop_page_hash_for_tablespace(table)
#endif /* BTR_CUR_HASH_ADAPT */
/** Empty the flush list for all pages belonging to a tablespace.
@param[in] id tablespace identifier
@param[in,out] observer flush observer,
or NULL if nothing is to be written */
void
buf_LRU_flush_or_remove_pages(
ulint id,
FlushObserver* observer
#ifdef BTR_CUR_HASH_ADAPT
, bool drop_ahi = false /*!< whether to drop the adaptive hash index */
#endif /* BTR_CUR_HASH_ADAPT */
);
void buf_LRU_flush_or_remove_pages(ulint id, FlushObserver* observer);
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
/********************************************************************//**

View File

@ -62,7 +62,9 @@ struct crypt_info_t {
static crypt_info_t info;
/** Crypt info when upgrading from 10.1 */
static crypt_info_t infos[5];
static crypt_info_t infos[5 * 2];
/** First unused slot in infos[] */
static size_t infos_used;
/*********************************************************************//**
Get a log block's start lsn.
@ -80,28 +82,6 @@ log_block_get_start_lsn(
return start_lsn;
}
/*********************************************************************//**
Get crypt info from checkpoint.
@return a crypt info or NULL if not present. */
static
const crypt_info_t*
get_crypt_info(ulint checkpoint_no)
{
/* a log block only stores 4-bytes of checkpoint no */
checkpoint_no &= 0xFFFFFFFF;
for (unsigned i = 0; i < 5; i++) {
const crypt_info_t* it = &infos[i];
if (it->key_version && it->checkpoint_no == checkpoint_no) {
return it;
}
}
/* If checkpoint contains more than one key and we did not
find the correct one use the first one. */
return infos;
}
/** Encrypt or decrypt log blocks.
@param[in,out] buf log blocks to encrypt or decrypt
@param[in] lsn log sequence number of the start of the buffer
@ -166,9 +146,7 @@ log_crypt(byte* buf, lsn_t lsn, ulint size, bool decrypt)
@param[in,out] info encryption key
@param[in] upgrade whether to use the key in MariaDB 10.1 format
@return whether the operation was successful */
static
bool
init_crypt_key(crypt_info_t* info, bool upgrade = false)
static bool init_crypt_key(crypt_info_t* info, bool upgrade = false)
{
byte mysqld_key[MY_AES_MAX_KEY_LENGTH];
uint keylen = sizeof mysqld_key;
@ -253,8 +231,20 @@ log_crypt_101_read_checkpoint(const byte* buf)
const size_t n = *buf++ == 2 ? std::min(unsigned(*buf++), 5U) : 0;
for (size_t i = 0; i < n; i++) {
struct crypt_info_t& info = infos[i];
info.checkpoint_no = mach_read_from_4(buf);
struct crypt_info_t& info = infos[infos_used];
unsigned checkpoint_no = mach_read_from_4(buf);
for (size_t j = 0; j < infos_used; j++) {
if (infos[j].checkpoint_no == checkpoint_no) {
/* Do not overwrite an existing slot. */
goto next_slot;
}
}
if (infos_used >= UT_ARR_SIZE(infos)) {
ut_ad(!"too many checkpoint pages");
goto next_slot;
}
infos_used++;
info.checkpoint_no = checkpoint_no;
info.key_version = mach_read_from_4(buf + 4);
memcpy(info.crypt_msg.bytes, buf + 8, sizeof info.crypt_msg);
memcpy(info.crypt_nonce.bytes, buf + 24,
@ -263,6 +253,7 @@ log_crypt_101_read_checkpoint(const byte* buf)
if (!init_crypt_key(&info, true)) {
return false;
}
next_slot:
buf += 4 + 4 + 2 * MY_AES_BLOCK_SIZE;
}
@ -278,13 +269,19 @@ log_crypt_101_read_block(byte* buf)
{
ut_ad(log_block_calc_checksum_format_0(buf)
!= log_block_get_checksum(buf));
const crypt_info_t* info = get_crypt_info(
log_block_get_checkpoint_no(buf));
if (!info || info->key_version == 0) {
return false;
const uint32_t checkpoint_no
= uint32_t(log_block_get_checkpoint_no(buf));
const crypt_info_t* info = infos;
for (const crypt_info_t* const end = info + infos_used; info < end;
info++) {
if (info->key_version
&& info->checkpoint_no == checkpoint_no) {
goto found;
}
}
return false;
found:
byte dst[OS_FILE_LOG_BLOCK_SIZE];
uint dst_len;
byte aes_ctr_iv[MY_AES_BLOCK_SIZE];
@ -313,9 +310,7 @@ log_crypt_101_read_block(byte* buf)
LOG_DEFAULT_ENCRYPTION_KEY,
info->key_version);
if (rc != MY_AES_OK || dst_len != src_len
|| log_block_calc_checksum_format_0(dst)
!= log_block_get_checksum(dst)) {
if (rc != MY_AES_OK || dst_len != src_len) {
return false;
}

View File

@ -28,6 +28,7 @@ Created 2012-02-08 by Sunny Bains.
#include "row0import.h"
#include "btr0pcur.h"
#include "btr0sea.h"
#include "que0que.h"
#include "dict0boot.h"
#include "ibuf0ibuf.h"
@ -3870,6 +3871,17 @@ row_import_for_mysql(
return(row_import_cleanup(prebuilt, trx, err));
}
/* On DISCARD TABLESPACE, we did not drop any adaptive hash
index entries. If we replaced the discarded tablespace with a
smaller one here, there could still be some adaptive hash
index entries that point to cached garbage pages in the buffer
pool, because PageConverter::operator() only evicted those
pages that were replaced by the imported pages. We must
discard all remaining adaptive hash index entries, because the
adaptive hash index must be a subset of the table contents;
false positives are not tolerated. */
buf_LRU_drop_page_hash_for_tablespace(table);
row_mysql_lock_data_dictionary(trx);
/* If the table is stored in a remote tablespace, we need to

View File

@ -3151,11 +3151,7 @@ row_discard_tablespace(
}
/* Discard the physical file that is used for the tablespace. */
err = fil_delete_tablespace(table->space_id
#ifdef BTR_CUR_HASH_ADAPT
, true
#endif /* BTR_CUR_HASH_ADAPT */
);
err = fil_delete_tablespace(table->space_id);
switch (err) {
case DB_IO_ERROR:
ib::warn() << "ALTER TABLE " << table->name
@ -3706,6 +3702,21 @@ defer:
rw_lock_x_unlock(dict_index_get_lock(index));
}
if (table->space_id != TRX_SYS_SPACE) {
/* On DISCARD TABLESPACE, we would not drop the
adaptive hash index entries. If the tablespace is
missing here, delete-marking the record in SYS_INDEXES
would not free any pages in the buffer pool. Thus,
dict_index_remove_from_cache() would hang due to
adaptive hash index entries existing in the buffer
pool. To prevent this hang, and also to guarantee
that btr_search_drop_page_hash_when_freed() will avoid
calling btr_search_drop_page_hash_index() while we
hold the InnoDB dictionary lock, we will drop any
adaptive hash index entries upfront. */
buf_LRU_drop_page_hash_for_tablespace(table);
}
/* Deleting a row from SYS_INDEXES table will invoke
dict_drop_index_tree(). */
info = pars_info_create();

View File

@ -37,6 +37,7 @@ C_MODE_START
#include "ma_checkpoint.h"
#include "ma_recovery.h"
C_MODE_END
#include "ma_trnman.h"
//#include "sql_priv.h"
#include "protocol.h"
@ -1394,7 +1395,8 @@ int ha_maria::check(THD * thd, HA_CHECK_OPT * check_opt)
}
/* Reset trn, that may have been set by repair */
_ma_set_trn_for_table(file, old_trn);
if (old_trn && old_trn != file->trn)
_ma_set_trn_for_table(file, old_trn);
thd_proc_info(thd, old_proc_info);
thd_progress_end(thd);
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
@ -1528,7 +1530,8 @@ int ha_maria::zerofill(THD * thd, HA_CHECK_OPT *check_opt)
error=maria_zerofill(param, file, share->open_file_name.str);
/* Reset trn, that may have been set by repair */
_ma_set_trn_for_table(file, old_trn);
if (old_trn && old_trn != file->trn)
_ma_set_trn_for_table(file, old_trn);
if (!error)
{
@ -1771,7 +1774,8 @@ int ha_maria::repair(THD *thd, HA_CHECK *param, bool do_optimize)
maria_lock_database(file, F_UNLCK);
/* Reset trn, that may have been set by repair */
_ma_set_trn_for_table(file, old_trn);
if (old_trn && old_trn != file->trn)
_ma_set_trn_for_table(file, old_trn);
error= error ? HA_ADMIN_FAILED :
(optimize_done ?
(write_log_record_for_repair(param, file) ? HA_ADMIN_FAILED :
@ -2591,9 +2595,12 @@ int ha_maria::extra(enum ha_extra_function operation)
without calling commit/rollback in between. If file->trn is not set
we can't remove file->share from the transaction list in the extra() call.
We also ensure that we set file->trn to 0 if THD_TRN is 0 as in
this case we have already freed the trn. This can happen when one
implicit_commit() is called as part of alter table.
In current code we don't have to do this for HA_EXTRA_PREPARE_FOR_RENAME
as this is only used the intermediate table used by ALTER TABLE which
is not part of the transaction (it's not in the TRN list). Better to
keep this for now, to not break anything in a stable release.
When HA_EXTRA_PREPARE_FOR_RENAME is not handled below, we can change
the warnings in _ma_remove_table_from_trnman() to asserts.
table->in_use is not set in the case this is a done as part of closefrm()
as part of drop table.
@ -2606,7 +2613,7 @@ int ha_maria::extra(enum ha_extra_function operation)
{
THD *thd= table->in_use;
TRN *trn= THD_TRN;
_ma_set_trn_for_table(file, trn);
_ma_set_tmp_trn_for_table(file, trn);
}
DBUG_ASSERT(file->s->base.born_transactional || file->trn == 0 ||
file->trn == &dummy_transaction_object);
@ -2722,6 +2729,7 @@ int ha_maria::external_lock(THD *thd, int lock_type)
if (file->trn)
{
/* This can only happen with tables created with clone() */
DBUG_PRINT("info",("file->trn: %p", file->trn));
trnman_increment_locked_tables(file->trn);
}
@ -2742,7 +2750,7 @@ int ha_maria::external_lock(THD *thd, int lock_type)
}
else
{
TRN *trn= THD_TRN;
TRN *trn= (file->trn != &dummy_transaction_object ? file->trn : 0);
/* End of transaction */
/*
@ -2757,8 +2765,7 @@ int ha_maria::external_lock(THD *thd, int lock_type)
*/
if (_ma_reenable_logging_for_table(file, TRUE))
DBUG_RETURN(1);
/** @todo zero file->trn also in commit and rollback */
_ma_set_trn_for_table(file, NULL); // Safety
_ma_reset_trn_for_table(file);
/*
Ensure that file->state points to the current number of rows. This
is needed if someone calls maria_info() without first doing an
@ -2814,13 +2821,6 @@ int ha_maria::start_stmt(THD *thd, thr_lock_type lock_type)
DBUG_ASSERT(lock_type != TL_UNLOCK);
DBUG_ASSERT(file->trn == trn);
/*
If there was an implicit commit under this LOCK TABLES by a previous
statement (like a DDL), at least if that previous statement was about a
different ha_maria than 'this' then this->file->trn is a stale
pointer. We fix it:
*/
_ma_set_trn_for_table(file, trn);
/*
As external_lock() was already called, don't increment locked_tables.
Note that we call the function below possibly several times when
@ -2845,6 +2845,23 @@ int ha_maria::start_stmt(THD *thd, thr_lock_type lock_type)
}
/*
Reset THD_TRN and all file->trn related to the transaction
This is needed as some calls, like extra() or external_lock() may access
it before next transaction is started
*/
static void reset_thd_trn(THD *thd, MARIA_HA *first_table)
{
DBUG_ENTER("reset_thd_trn");
THD_TRN= NULL;
for (MARIA_HA *table= first_table; table ;
table= table->trn_next)
_ma_reset_trn_for_table(table);
DBUG_VOID_RETURN;
}
/**
Performs an implicit commit of the Maria transaction and creates a new
one.
@ -2868,10 +2885,10 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
TRN *trn;
int error;
uint locked_tables;
DYNAMIC_ARRAY used_tables;
extern my_bool plugins_are_initialized;
MARIA_HA *used_tables, *trn_next;
DBUG_ENTER("ha_maria::implicit_commit");
if (!maria_hton || !plugins_are_initialized || !(trn= THD_TRN))
DBUG_RETURN(0);
if (!new_trn && (thd->locked_tables_mode == LTM_LOCK_TABLES ||
@ -2889,48 +2906,16 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
locked_tables= trnman_has_locked_tables(trn);
if (new_trn && trn && trn->used_tables)
{
MARIA_USED_TABLES *tables;
/*
Save locked tables so that we can move them to another transaction
We are using a dynamic array as locked_tables in some cases can be
smaller than the used_tables list (for example when the server does
early unlock of tables.
*/
my_init_dynamic_array2(&used_tables, sizeof(MARIA_SHARE*), (void*) 0,
locked_tables, 8, MYF(MY_THREAD_SPECIFIC));
for (tables= (MARIA_USED_TABLES*) trn->used_tables;
tables;
tables= tables->next)
{
if (tables->share->base.born_transactional)
{
if (insert_dynamic(&used_tables, (uchar*) &tables->share))
{
error= HA_ERR_OUT_OF_MEM;
goto end_and_free;
}
}
}
}
else
bzero(&used_tables, sizeof(used_tables));
used_tables= (MARIA_HA*) trn->used_instances;
error= 0;
if (unlikely(ma_commit(trn)))
error= 1;
if (!new_trn)
{
/*
To be extra safe, we should also reset file->trn for all open
tables as some calls, like extra() may access it. We take care
of this in extra() by resetting file->trn if THD_TRN is 0.
*/
THD_TRN= NULL;
reset_thd_trn(thd, used_tables);
goto end;
}
/*
We need to create a new transaction and put it in THD_TRN. Indeed,
tables may be under LOCK TABLES, and so they will start the next
@ -2940,8 +2925,9 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
THD_TRN= trn;
if (unlikely(trn == NULL))
{
reset_thd_trn(thd, used_tables);
error= HA_ERR_OUT_OF_MEM;
goto end_and_free;
goto end;
}
/*
Move all locked tables to the new transaction
@ -2951,35 +2937,25 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
in check table, we use the table without calling start_stmt().
*/
uint i;
for (i= 0 ; i < used_tables.elements ; i++)
for (MARIA_HA *handler= used_tables; handler ;
handler= trn_next)
{
MARIA_SHARE *share;
LIST *handlers;
trn_next= handler->trn_next;
DBUG_ASSERT(handler->s->base.born_transactional);
share= *(dynamic_element(&used_tables, i, MARIA_SHARE**));
/* Find table instances that was used in this transaction */
for (handlers= share->open_list; handlers; handlers= handlers->next)
/* If handler uses versioning */
if (handler->s->lock_key_trees)
{
MARIA_HA *handler= (MARIA_HA*) handlers->data;
if (handler->external_ref &&
((TABLE*) handler->external_ref)->in_use == thd)
{
_ma_set_trn_for_table(handler, trn);
/* If handler uses versioning */
if (handler->s->lock_key_trees)
{
if (_ma_setup_live_state(handler))
error= HA_ERR_OUT_OF_MEM;
}
}
/* _ma_set_trn_for_table() will be called indirectly */
if (_ma_setup_live_state(handler))
error= HA_ERR_OUT_OF_MEM;
}
else
_ma_set_trn_for_table(handler, trn);
}
/* This is just a commit, tables stay locked if they were: */
trnman_reset_locked_tables(trn, locked_tables);
end_and_free:
delete_dynamic(&used_tables);
end:
DBUG_RETURN(error);
}
@ -3359,10 +3335,10 @@ static int maria_commit(handlerton *hton __attribute__ ((unused)),
trnman_set_flags(trn, trnman_get_flags(trn) & ~TRN_STATE_INFO_LOGGED);
/* statement or transaction ? */
if ((thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && !all)
if ((thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
!all)
DBUG_RETURN(0); // end of statement
DBUG_PRINT("info", ("THD_TRN set to 0x0"));
THD_TRN= 0;
reset_thd_trn(thd, (MARIA_HA*) trn->used_instances);
DBUG_RETURN(ma_commit(trn)); // end of transaction
}
@ -3379,8 +3355,7 @@ static int maria_rollback(handlerton *hton __attribute__ ((unused)),
trnman_rollback_statement(trn);
DBUG_RETURN(0); // end of statement
}
DBUG_PRINT("info", ("THD_TRN set to 0x0"));
THD_TRN= 0;
reset_thd_trn(thd, (MARIA_HA*) trn->used_instances);
DBUG_RETURN(trnman_rollback_trn(trn) ?
HA_ERR_OUT_OF_MEM : 0); // end of transaction
}

View File

@ -195,6 +195,7 @@ public:
private:
DsMrr_impl ds_mrr;
friend ICP_RESULT index_cond_func_maria(void *arg);
friend void reset_thd_trn(THD *thd);
};
#endif /* HA_MARIA_INCLUDED */

View File

@ -271,6 +271,7 @@
#include "maria_def.h"
#include "ma_blockrec.h"
#include "trnman.h"
#include "ma_trnman.h"
#include "ma_key_recover.h"
#include "ma_recovery_util.h"
#include <lf.h>
@ -7525,7 +7526,7 @@ void maria_ignore_trids(MARIA_HA *info)
if (info->s->base.born_transactional)
{
if (!info->trn)
_ma_set_trn_for_table(info, &dummy_transaction_object);
_ma_set_tmp_trn_for_table(info, &dummy_transaction_object);
/* Ignore transaction id when row is read */
info->trn->min_read_from= ~(TrID) 0;
}

View File

@ -37,6 +37,8 @@ int maria_close(register MARIA_HA *info)
/* Check that we have unlocked key delete-links properly */
DBUG_ASSERT(info->key_del_used == 0);
/* Check that file is not part of any uncommited transactions */
DBUG_ASSERT(info->trn == 0 || info->trn == &dummy_transaction_object);
if (share->reopen == 1)
{

View File

@ -15,6 +15,7 @@
#include "maria_def.h"
#include "trnman.h"
#include "ma_trnman.h"
/**
writes a COMMIT record to log and commits transaction in memory
@ -43,9 +44,9 @@ int ma_commit(TRN *trn)
COMMIT record) and this is not an issue as
* transaction's updates were not made visible to other transactions
* "commit ok" was not sent to client
Alternatively, Recovery might commit trn (if MY_MIN(rec_lsn) is before COMMIT
record), which is ok too. All in all it means that "trn committed" is not
100% equal to "COMMIT record written".
Alternatively, Recovery might commit trn (if MY_MIN(rec_lsn) is before
COMMIT record), which is ok too. All in all it means that "trn committed"
is not 100% equal to "COMMIT record written".
- if COMMIT record is written after trnman_commit_trn():
if crash happens between the two, trn will be rolled back which is an
issue (transaction's updates were made visible to other transactions).
@ -93,7 +94,12 @@ int ma_commit(TRN *trn)
int maria_commit(MARIA_HA *info)
{
return info->s->now_transactional ? ma_commit(info->trn) : 0;
TRN *trn;
if (!info->s->now_transactional)
return 0;
trn= info->trn;
info->trn= 0; /* checked in maria_close() */
return ma_commit(trn);
}
@ -120,10 +126,7 @@ int maria_begin(MARIA_HA *info)
TRN *trn= trnman_new_trn(0);
if (unlikely(!trn))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
DBUG_PRINT("info", ("TRN set to %p", trn));
_ma_set_trn_for_table(info, trn);
}
DBUG_RETURN(0);
}

View File

@ -346,7 +346,7 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
_ma_decrement_open_count(info, 0);
if (info->trn)
{
_ma_remove_table_from_trnman(share, info->trn);
_ma_remove_table_from_trnman(info);
/* Ensure we don't point to the deleted data in trn */
info->state= info->state_start= &share->state.state;
}
@ -409,7 +409,7 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
if (info->trn)
{
mysql_mutex_lock(&share->intern_lock);
_ma_remove_table_from_trnman(share, info->trn);
_ma_remove_table_from_trnman(info);
/* Ensure we don't point to the deleted data in trn */
info->state= info->state_start= &share->state.state;
mysql_mutex_unlock(&share->intern_lock);

View File

@ -19,6 +19,8 @@
#include "ma_sp_defs.h"
#include "ma_rt_index.h"
#include "ma_blockrec.h"
#include "trnman.h"
#include "ma_trnman.h"
#include <m_ctype.h>
#include "ma_crypt.h"
@ -184,7 +186,7 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share,
if (!share->base.born_transactional) /* For transactional ones ... */
{
/* ... force crash if no trn given */
_ma_set_trn_for_table(&info, &dummy_transaction_object);
_ma_set_tmp_trn_for_table(&info, &dummy_transaction_object);
info.state= &share->state.state; /* Change global values by default */
}
else

View File

@ -66,7 +66,7 @@ my_bool _ma_setup_live_state(MARIA_HA *info)
DBUG_RETURN(1);
trn= info->trn;
for (tables= (MARIA_USED_TABLES*) info->trn->used_tables;
for (tables= (MARIA_USED_TABLES*) trn->used_tables;
tables;
tables= tables->next)
{
@ -551,6 +551,7 @@ my_bool _ma_trnman_end_trans_hook(TRN *trn, my_bool commit,
my_free(tables);
}
trn->used_tables= 0;
trn->used_instances= 0;
DBUG_RETURN(error);
}
@ -565,18 +566,25 @@ my_bool _ma_trnman_end_trans_hook(TRN *trn, my_bool commit,
share->internal_lock must be locked when function is called
*/
void _ma_remove_table_from_trnman(MARIA_SHARE *share, TRN *trn)
void _ma_remove_table_from_trnman(MARIA_HA *info)
{
MARIA_SHARE *share= info->s;
TRN *trn= info->trn;
MARIA_USED_TABLES *tables, **prev;
MARIA_HA *handler, **prev_file;
DBUG_ENTER("_ma_remove_table_from_trnman");
DBUG_PRINT("enter", ("trn: %p used_tables: %p share: %p in_trans: %d",
trn, trn->used_tables, share, share->in_trans));
mysql_mutex_assert_owner(&share->intern_lock);
if (trn == &dummy_transaction_object)
DBUG_VOID_RETURN;
for (prev= (MARIA_USED_TABLES**) (char*) &trn->used_tables, tables= *prev;
tables;
tables= *prev)
/* First remove share from used_tables */
for (prev= (MARIA_USED_TABLES**) (char*) &trn->used_tables;
(tables= *prev);
prev= &tables->next)
{
if (tables->share == share)
{
@ -585,8 +593,36 @@ void _ma_remove_table_from_trnman(MARIA_SHARE *share, TRN *trn)
my_free(tables);
break;
}
prev= &tables->next;
}
if (tables != 0)
{
/*
This can only happens in case of rename of intermediate table as
part of alter table
*/
DBUG_PRINT("warning", ("share: %p where not in used_tables_list", share));
}
/* unlink table from used_instances */
for (prev_file= (MARIA_HA**) &trn->used_instances;
(handler= *prev_file);
prev_file= &handler->trn_next)
{
if (handler == info)
{
*prev_file= info->trn_next;
break;
}
}
if (handler != 0)
{
/*
This can only happens in case of rename of intermediate table as
part of alter table
*/
DBUG_PRINT("warning", ("table: %p where not in used_instances", info));
}
info->trn= 0; /* Not part of trans anymore */
DBUG_VOID_RETURN;
}

View File

@ -84,5 +84,5 @@ my_bool _ma_row_visible_non_transactional_table(MARIA_HA *info);
my_bool _ma_row_visible_transactional_table(MARIA_HA *info);
void _ma_remove_not_visible_states_with_lock(struct st_maria_share *share,
my_bool all);
void _ma_remove_table_from_trnman(struct st_maria_share *share, TRN *trn);
void _ma_remove_table_from_trnman(MARIA_HA *info);
void _ma_reset_history(struct st_maria_share *share);

65
storage/maria/ma_trnman.h Normal file
View File

@ -0,0 +1,65 @@
/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _ma_trnman_h
#define _ma_trnman_h
/**
Sets table's trn and prints debug information
Links table into used_instances if new_trn is not 0
@param tbl MARIA_HA of table
@param newtrn what to put into tbl->trn
*/
static inline void _ma_set_trn_for_table(MARIA_HA *tbl, TRN *newtrn)
{
DBUG_PRINT("info",("table: %p trn: %p -> %p",
tbl, tbl->trn, newtrn));
/* check that we are not calling this twice in a row */
DBUG_ASSERT(newtrn->used_instances != (void*) tbl);
tbl->trn= newtrn;
/* Link into used list */
tbl->trn_next= (MARIA_HA*) newtrn->used_instances;
newtrn->used_instances= tbl;
}
/*
Same as _ma_set_trn_for_table(), but don't link table into used_instance list
Used when we want to temporary set trn for a table in extra()
*/
static inline void _ma_set_tmp_trn_for_table(MARIA_HA *tbl, TRN *newtrn)
{
DBUG_PRINT("info",("table: %p trn: %p -> %p",
tbl, tbl->trn, newtrn));
tbl->trn= newtrn;
}
/*
Reset TRN in table
*/
static inline void _ma_reset_trn_for_table(MARIA_HA *tbl)
{
DBUG_PRINT("info",("table: %p trn: %p -> NULL", tbl, tbl->trn));
tbl->trn= 0;
}
#endif /* _ma_trnman_h */

View File

@ -602,6 +602,7 @@ struct st_maria_handler
{
MARIA_SHARE *s; /* Shared between open:s */
struct st_ma_transaction *trn; /* Pointer to active transaction */
struct st_maria_handler *trn_next;
MARIA_STATUS_INFO *state, state_save;
MARIA_STATUS_INFO *state_start; /* State at start of transaction */
MARIA_USED_TABLES *used_tables;
@ -862,19 +863,6 @@ struct st_maria_handler
#define get_pack_length(length) ((length) >= 255 ? 3 : 1)
#define _ma_have_versioning(info) ((info)->row_flag & ROW_FLAG_TRANSID)
/**
Sets table's trn and prints debug information
@param tbl MARIA_HA of table
@param newtrn what to put into tbl->trn
@note cast of newtrn is because %p of NULL gives warning (NULL is int)
*/
#define _ma_set_trn_for_table(tbl, newtrn) do { \
DBUG_PRINT("info",("table: %p trn: %p -> %p", \
(tbl), (tbl)->trn, (void *)(newtrn))); \
(tbl)->trn= (newtrn); \
} while (0)
#define MARIA_MIN_BLOCK_LENGTH 20 /* Because of delete-link */
/* Don't use to small record-blocks */
#define MARIA_EXTEND_BLOCK_LENGTH 20

View File

@ -357,6 +357,7 @@ TRN *trnman_new_trn(WT_THD *wt)
trn->commit_trid= MAX_TRID;
trn->rec_lsn= trn->undo_lsn= trn->first_undo_lsn= 0;
trn->used_tables= 0;
trn->used_instances= 0;
trn->locked_tables= 0;
trn->flags= 0;

View File

@ -46,7 +46,8 @@ struct st_ma_transaction
LF_PINS *pins;
WT_THD *wt;
mysql_mutex_t state_lock;
void *used_tables; /**< Tables used by transaction */
void *used_tables; /**< Table shares used by transaction */
void *used_instances; /* table files used by transaction */
TRN *next, *prev;
TrID trid, min_read_from, commit_trid;
LSN rec_lsn, undo_lsn;

View File

@ -22,5 +22,5 @@ let SEARCH_PATTERN= RocksDB: Compatibility check against existing database optio
--enable_reconnect
--exec echo "restart" > $restart_file
--source include/wait_until_connected_again.inc
--exec find $MYSQLD_DATADIR/#rocksdb/OPTIONS* | sort -n | tail -1 | xargs -0 -I {} -t sh -c "sed -i '/hello=world/d' {}"
--exec find $MYSQLD_DATADIR/#rocksdb/OPTIONS* | sort -n | tail -1 | xargs -0 -I {} -t sh -c "sed -i'' -e '/hello=world/d' {}"
select variable_name, variable_value from information_schema.global_variables where variable_name="rocksdb_ignore_unknown_options";

View File

@ -188,10 +188,76 @@ void mdev9044()
close_cached_file(&info);
}
/* 2 Reads (with my_b_fill) in cache makes second read to fail */
void mdev10259()
{
int res;
uchar buf[200];
memset(buf, FILL, sizeof(buf));
diag("MDEV-10259- mysqld crash with certain statement length and order with"
" Galera and encrypt-tmp-files=1");
init_io_cache_encryption();
res= open_cached_file(&info, 0, 0, CACHE_SIZE, 0);
ok(res == 0, "open_cached_file" INFO_TAIL);
res= my_b_write(&info, buf, sizeof(buf));
ok(res == 0 && info.pos_in_file == 0, "200 write" INFO_TAIL);
res= my_b_flush_io_cache(&info, 1);
ok(res == 0, "flush" INFO_TAIL);
my_off_t saved_pos= my_b_tell(&info);
res= reinit_io_cache(&info, READ_CACHE, 0, 0, 0);
ok(res == 0, "reinit READ_CACHE" INFO_TAIL);
res= my_b_fill(&info);
ok(res == 200, "fill" INFO_TAIL);
res= my_b_fill(&info);
ok(res == 0, "fill" INFO_TAIL);
res= my_b_fill(&info);
ok(res == 0, "fill" INFO_TAIL);
res= reinit_io_cache(&info, WRITE_CACHE, saved_pos, 0, 0);
ok(res == 0, "reinit WRITE_CACHE" INFO_TAIL);
res= reinit_io_cache(&info, READ_CACHE, 0, 0, 0);
ok(res == 0, "reinit READ_CACHE" INFO_TAIL);
ok(200 == my_b_bytes_in_cache(&info),"my_b_bytes_in_cache == 200");
res= my_b_fill(&info);
ok(res == 0, "fill" INFO_TAIL);
res= my_b_fill(&info);
ok(res == 0, "fill" INFO_TAIL);
res= my_b_fill(&info);
ok(res == 0, "fill" INFO_TAIL);
res= reinit_io_cache(&info, WRITE_CACHE, saved_pos, 0, 0);
ok(res == 0, "reinit WRITE_CACHE" INFO_TAIL);
res= reinit_io_cache(&info, READ_CACHE, 0, 0, 0);
ok(res == 0, "reinit READ_CACHE" INFO_TAIL);
ok(200 == my_b_bytes_in_cache(&info),"my_b_bytes_in_cache == 200");
res= my_b_read(&info, buf, sizeof(buf)) || data_bad(buf, sizeof(buf));
ok(res == 0 && info.pos_in_file == 0, "large read" INFO_TAIL);
close_cached_file(&info);
}
int main(int argc __attribute__((unused)),char *argv[])
{
MY_INIT(argv[0]);
plan(29);
plan(46);
/* temp files with and without encryption */
encrypt_tmp_files= 1;
@ -203,6 +269,10 @@ int main(int argc __attribute__((unused)),char *argv[])
/* regression tests */
mdev9044();
encrypt_tmp_files= 1;
mdev10259();
encrypt_tmp_files= 0;
my_end(0);
return exit_status();
}