summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2018-05-24 11:08:02 +0300
committerMonty <monty@mariadb.org>2018-05-24 11:08:02 +0300
commite744c687ca2c2523b63d5ac0066276a6cb3e932f (patch)
tree7d3fbd9457d9a6f074d4c8dbb925fcb65730e135
parent5797cbaf4ab93cdae191486c6c82be79b83c56d2 (diff)
parenta816aa066e5c879a92819d694a93d245e6ec6e47 (diff)
downloadmariadb-git-e744c687ca2c2523b63d5ac0066276a6cb3e932f.tar.gz
Merge remote-tracking branch 'origin/10.0' into 10.1
-rw-r--r--mysql-test/r/alter_table.result60
-rw-r--r--mysql-test/r/grant2.result3
-rw-r--r--mysql-test/r/rename.result66
-rw-r--r--mysql-test/r/statistics_close.result6
-rw-r--r--mysql-test/suite/maria/lock.result10
-rw-r--r--mysql-test/suite/maria/lock.test12
-rw-r--r--mysql-test/suite/rpl/r/rename.result34
-rw-r--r--mysql-test/suite/rpl/t/rename.test33
-rw-r--r--mysql-test/t/alter_table.test31
-rw-r--r--mysql-test/t/grant2.test3
-rw-r--r--mysql-test/t/rename.test46
-rw-r--r--mysql-test/t/statistics_close.test18
-rw-r--r--sql/sql_admin.cc11
-rw-r--r--sql/sql_handler.cc4
-rw-r--r--sql/sql_parse.cc65
-rw-r--r--sql/sql_rename.cc2
-rw-r--r--sql/sql_statistics.cc3
-rw-r--r--sql/sql_table.cc29
-rw-r--r--storage/maria/ha_maria.cc137
-rw-r--r--storage/maria/ha_maria.h1
-rw-r--r--storage/maria/ma_blockrec.c3
-rw-r--r--storage/maria/ma_close.c2
-rw-r--r--storage/maria/ma_commit.c17
-rw-r--r--storage/maria/ma_extra.c4
-rw-r--r--storage/maria/ma_open.c4
-rw-r--r--storage/maria/ma_state.c48
-rw-r--r--storage/maria/ma_state.h2
-rw-r--r--storage/maria/ma_trnman.h65
-rw-r--r--storage/maria/maria_def.h14
-rw-r--r--storage/maria/trnman.c1
-rw-r--r--storage/maria/trnman.h3
31 files changed, 606 insertions, 131 deletions
diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result
index 17e2dc9b009..4ccbc8a483f 100644
--- a/mysql-test/r/alter_table.result
+++ b/mysql-test/r/alter_table.result
@@ -2174,6 +2174,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 'fk'; check that column/key 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 'fk'; check that column/key 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 'fk'; check that column/key 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 'fk'; check that column/key 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 'fk'; check that column/key exists
+Note 1091 Can't DROP 'c'; check that column/key 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
#
#
diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result
index cf58a2dc6f5..bdd88e12617 100644
--- a/mysql-test/r/grant2.result
+++ b/mysql-test/r/grant2.result
@@ -707,10 +707,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.
#
diff --git a/mysql-test/r/rename.result b/mysql-test/r/rename.result
index 74370ba74dd..c90aaf24e9b 100644
--- a/mysql-test/r/rename.result
+++ b/mysql-test/r/rename.result
@@ -67,3 +67,69 @@ ERROR HY000: 'test.v1' is not 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;
diff --git a/mysql-test/r/statistics_close.result b/mysql-test/r/statistics_close.result
new file mode 100644
index 00000000000..348681c3311
--- /dev/null
+++ b/mysql-test/r/statistics_close.result
@@ -0,0 +1,6 @@
+CREATE TABLE t1 (i int);
+RENAME TABLE t1 TO t2;
+FLUSH TABLES;
+DROP TABLE IF EXISTS t1, t2;
+Warnings:
+Note 1051 Unknown table 'test.t1'
diff --git a/mysql-test/suite/maria/lock.result b/mysql-test/suite/maria/lock.result
index 90250568ef5..1c9d6b18100 100644
--- a/mysql-test/suite/maria/lock.result
+++ b/mysql-test/suite/maria/lock.result
@@ -99,3 +99,13 @@ f2
3
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;
diff --git a/mysql-test/suite/maria/lock.test b/mysql-test/suite/maria/lock.test
index 57447a18c55..4f3d4e8065e 100644
--- a/mysql-test/suite/maria/lock.test
+++ b/mysql-test/suite/maria/lock.test
@@ -105,3 +105,15 @@ INSERT INTO t2 (f2) SELECT f3 FROM tmp AS tmp_alias;
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;
diff --git a/mysql-test/suite/rpl/r/rename.result b/mysql-test/suite/rpl/r/rename.result
new file mode 100644
index 00000000000..5cedea51c86
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rename.result
@@ -0,0 +1,34 @@
+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;
+DROP VIEW v;
+DROP TABLE tmp;
+DROP TABLE t2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rename.test b/mysql-test/suite/rpl/t/rename.test
new file mode 100644
index 00000000000..ac499157918
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rename.test
@@ -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
diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test
index 5cb33516ed2..bcb5264af48 100644
--- a/mysql-test/t/alter_table.test
+++ b/mysql-test/t/alter_table.test
@@ -1810,6 +1810,37 @@ 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 #
diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test
index a40fd2afb18..f0721b3e5e9 100644
--- a/mysql-test/t/grant2.test
+++ b/mysql-test/t/grant2.test
@@ -875,9 +875,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 #
diff --git a/mysql-test/t/rename.test b/mysql-test/t/rename.test
index a55bc845acc..67732d5b5b9 100644
--- a/mysql-test/t/rename.test
+++ b/mysql-test/t/rename.test
@@ -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;
+
diff --git a/mysql-test/t/statistics_close.test b/mysql-test/t/statistics_close.test
new file mode 100644
index 00000000000..de22a5a44fe
--- /dev/null
+++ b/mysql-test/t/statistics_close.test
@@ -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;
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index ef7a2e82338..be23cd3341b 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -302,7 +302,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 *,
@@ -365,10 +365,11 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
for (table= tables; table; table= table->next_local)
{
char table_name[SAFE_NAME_LEN*2+2];
- char* db = table->db;
+ char *db= table->db;
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'", table->db, table->table_name));
strxmov(table_name, db, ".", table->table_name, NullS);
@@ -406,8 +407,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
/*
CHECK TABLE command is allowed for views as well. Check on alter flags
- to differentiate from ALTER TABLE...CHECK PARTITION on which view is not
- allowed.
+ to differentiate from ALTER TABLE...CHECK PARTITION on which view is
+ not allowed.
*/
if (lex->alter_info.flags & Alter_info::ALTER_ADMIN_PARTITION ||
view_operator_func == NULL)
@@ -1102,7 +1103,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
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 662fa33dc9f..8aee34a484d 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -155,10 +155,11 @@ static void mysql_ha_close_table(SQL_HANDLER *handler)
{
THD *thd= handler->thd;
TABLE *table= handler->table;
+ DBUG_ENTER("mysql_ha_close_table");
/* check if table was already closed */
if (!table)
- return;
+ DBUG_VOID_RETURN;
if (!table->s->tmp_table)
{
@@ -184,6 +185,7 @@ static void mysql_ha_close_table(SQL_HANDLER *handler)
}
my_free(handler->lock);
handler->init();
+ DBUG_VOID_RETURN;
}
/*
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index b4a26fa734d..55673ba2713 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -520,6 +520,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;
@@ -533,7 +535,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;
@@ -5995,6 +5996,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= find_temporary_table(thd, table);
+ DBUG_RETURN(res);
+}
+
+
static bool check_rename_table(THD *thd, TABLE_LIST *first_table,
TABLE_LIST *all_tables)
{
@@ -6011,13 +6066,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) &&
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 35222bce949..4c164a3a621 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -222,7 +222,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 (find_temporary_table(thd, new_table))
{
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
DBUG_RETURN(1); // This can't be skipped
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index 2a97c37e477..b7ccbb5c212 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -1518,7 +1518,8 @@ public:
~Stat_table_write_iter()
{
- cleanup();
+ /* Ensure that cleanup has been run */
+ DBUG_ASSERT(rowid_buf == 0);
}
};
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 72488fc870f..31da585443a 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -5835,10 +5835,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_info::ALTER_DROP_COLUMN;
+ break;
+ case Alter_drop::FOREIGN_KEY:
+ cur_flag= Alter_info::DROP_FOREIGN_KEY;
+ break;
+ case Alter_drop::KEY:
+ cur_flag= Alter_info::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)
{
@@ -5915,12 +5933,15 @@ drop_create_field:
ER_THD(thd, ER_CANT_DROP_FIELD_OR_KEY),
drop->name);
drop_it.remove();
- if (alter_info->drop_list.is_empty())
- alter_info->flags&= ~(Alter_info::ALTER_DROP_COLUMN |
- Alter_info::ALTER_DROP_INDEX |
- Alter_info::DROP_FOREIGN_KEY);
}
+ else
+ left_flags|= cur_flag;
}
+ /* Reset state to what's left in drop list */
+ alter_info->flags&= ~(Alter_info::ALTER_DROP_COLUMN |
+ Alter_info::ALTER_DROP_INDEX |
+ Alter_info::DROP_FOREIGN_KEY);
+ alter_info->flags|= left_flags;
}
/* ALTER TABLE ADD KEY IF NOT EXISTS */
diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc
index 814cb72a5cb..eee6b502c47 100644
--- a/storage/maria/ha_maria.cc
+++ b/storage/maria/ha_maria.cc
@@ -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"
@@ -1382,7 +1383,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;
@@ -1516,7 +1518,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)
{
@@ -1756,7 +1759,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 :
@@ -2567,9 +2571,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.
@@ -2582,7 +2589,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);
@@ -2698,6 +2705,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);
}
@@ -2718,7 +2726,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 */
/*
@@ -2733,8 +2741,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
@@ -2791,13 +2798,6 @@ int ha_maria::start_stmt(THD *thd, thr_lock_type lock_type)
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
statement starts (once per table). This is ok as long as that function
@@ -2821,6 +2821,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.
@@ -2844,10 +2861,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 ||
@@ -2865,48 +2882,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
@@ -2916,8 +2901,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
@@ -2927,35 +2913,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);
}
@@ -3328,10 +3304,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
}
@@ -3348,8 +3324,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
}
diff --git a/storage/maria/ha_maria.h b/storage/maria/ha_maria.h
index 65fe5f545d1..f3548a38137 100644
--- a/storage/maria/ha_maria.h
+++ b/storage/maria/ha_maria.h
@@ -193,6 +193,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 */
diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c
index c4ec3cf2f9a..c0a93415379 100644
--- a/storage/maria/ma_blockrec.c
+++ b/storage/maria/ma_blockrec.c
@@ -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;
}
diff --git a/storage/maria/ma_close.c b/storage/maria/ma_close.c
index d89a69f02ab..b63340e23a6 100644
--- a/storage/maria/ma_close.c
+++ b/storage/maria/ma_close.c
@@ -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)
{
diff --git a/storage/maria/ma_commit.c b/storage/maria/ma_commit.c
index 358f564d3f1..0ae3868dbf6 100644
--- a/storage/maria/ma_commit.c
+++ b/storage/maria/ma_commit.c
@@ -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 0x%lx", (ulong) trn));
_ma_set_trn_for_table(info, trn);
}
DBUG_RETURN(0);
}
-
diff --git a/storage/maria/ma_extra.c b/storage/maria/ma_extra.c
index 6c74bb52f51..f3800bc36be 100644
--- a/storage/maria/ma_extra.c
+++ b/storage/maria/ma_extra.c
@@ -345,7 +345,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;
}
@@ -408,7 +408,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);
diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c
index c4a7df4443c..27a85142f6b 100644
--- a/storage/maria/ma_open.c
+++ b/storage/maria/ma_open.c
@@ -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
diff --git a/storage/maria/ma_state.c b/storage/maria/ma_state.c
index 7404fe06641..aeefd9aa190 100644
--- a/storage/maria/ma_state.c
+++ b/storage/maria/ma_state.c
@@ -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;
}
diff --git a/storage/maria/ma_state.h b/storage/maria/ma_state.h
index a86aada94fd..8728a2113e5 100644
--- a/storage/maria/ma_state.h
+++ b/storage/maria/ma_state.h
@@ -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);
diff --git a/storage/maria/ma_trnman.h b/storage/maria/ma_trnman.h
new file mode 100644
index 00000000000..9bfd1f0d047
--- /dev/null
+++ b/storage/maria/ma_trnman.h
@@ -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 */
diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h
index 6cd6cda4b2f..8262e1b5e2d 100644
--- a/storage/maria/maria_def.h
+++ b/storage/maria/maria_def.h
@@ -601,6 +601,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;
@@ -860,19 +861,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
diff --git a/storage/maria/trnman.c b/storage/maria/trnman.c
index bc48d39baaa..5b3c9f0287a 100644
--- a/storage/maria/trnman.c
+++ b/storage/maria/trnman.c
@@ -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;
diff --git a/storage/maria/trnman.h b/storage/maria/trnman.h
index 66139a31230..11c73797766 100644
--- a/storage/maria/trnman.h
+++ b/storage/maria/trnman.h
@@ -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;