summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libmysqld/CMakeLists.txt1
-rw-r--r--mysql-test/r/create.result3
-rw-r--r--mysql-test/r/lock.result5
-rw-r--r--mysql-test/r/reopen_temp_table.result133
-rw-r--r--mysql-test/r/sp.result10
-rw-r--r--mysql-test/suite/handler/aria.result22
-rw-r--r--mysql-test/suite/handler/handler.inc7
-rw-r--r--mysql-test/suite/handler/heap.result22
-rw-r--r--mysql-test/suite/handler/innodb.result22
-rw-r--r--mysql-test/suite/handler/myisam.result22
-rw-r--r--mysql-test/suite/rpl/r/rpl_reopen_temp_table.result30
-rw-r--r--mysql-test/suite/rpl/t/rpl_reopen_temp_table.test43
-rw-r--r--mysql-test/t/create.test1
-rw-r--r--mysql-test/t/lock.test5
-rw-r--r--mysql-test/t/reopen_temp_table.test128
-rw-r--r--mysql-test/t/sp.test9
-rw-r--r--sql/CMakeLists.txt4
-rw-r--r--sql/log_event.cc2
-rw-r--r--sql/rpl_rli.cc51
-rw-r--r--sql/rpl_rli.h2
-rw-r--r--sql/slave.cc7
-rw-r--r--sql/sp_head.cc2
-rw-r--r--sql/sql_admin.cc8
-rw-r--r--sql/sql_alter.cc6
-rw-r--r--sql/sql_base.cc955
-rw-r--r--sql/sql_base.h26
-rw-r--r--sql/sql_cache.cc44
-rw-r--r--sql/sql_class.cc28
-rw-r--r--sql/sql_class.h174
-rw-r--r--sql/sql_db.cc5
-rw-r--r--sql/sql_handler.cc14
-rw-r--r--sql/sql_insert.cc9
-rw-r--r--sql/sql_parse.cc24
-rw-r--r--sql/sql_partition_admin.cc14
-rw-r--r--sql/sql_prepare.cc8
-rw-r--r--sql/sql_show.cc3
-rw-r--r--sql/sql_table.cc128
-rw-r--r--sql/sql_test.cc2
-rw-r--r--sql/sql_trigger.cc4
-rw-r--r--sql/sql_view.cc4
-rw-r--r--sql/sys_vars.cc5
-rw-r--r--sql/table.cc2
-rw-r--r--sql/table.h25
-rw-r--r--sql/table_cache.cc4
-rw-r--r--sql/table_cache.h3
-rw-r--r--sql/temporary_tables.cc1499
-rw-r--r--sql/wsrep_applier.cc12
-rw-r--r--sql/wsrep_mysqld.cc23
-rw-r--r--sql/wsrep_thd.cc9
-rw-r--r--storage/spider/spd_direct_sql.cc2
50 files changed, 2313 insertions, 1258 deletions
diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt
index ad16584ec0e..643876a7ae4 100644
--- a/libmysqld/CMakeLists.txt
+++ b/libmysqld/CMakeLists.txt
@@ -111,6 +111,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/wsrep_dummy.cc ../sql/encryption.cc
../sql/item_windowfunc.cc ../sql/sql_window.cc
../sql/sql_cte.cc
+ ../sql/temporary_tables.cc
${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE}
)
diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result
index 154a8544ca9..b9c95a04968 100644
--- a/mysql-test/r/create.result
+++ b/mysql-test/r/create.result
@@ -1736,7 +1736,8 @@ drop view t1;
create table t1 (a int) select 1 as a;
create temporary table if not exists t1 (a int) select * from t1;
create temporary table if not exists t1 (a int) select * from t1;
-ERROR HY000: Can't reopen table: 't1'
+Warnings:
+Note 1050 Table 't1' already exists
select * from t1;
a
1
diff --git a/mysql-test/r/lock.result b/mysql-test/r/lock.result
index 381667745d8..0313666d2a5 100644
--- a/mysql-test/r/lock.result
+++ b/mysql-test/r/lock.result
@@ -380,12 +380,7 @@ alter table t1 add column j int;
unlock tables;
drop table t1;
create temporary table t1 (i int);
-#
-# This is just for test coverage purposes,
-# when this is allowed, remove the --error.
-#
lock tables t1 write, t1 as a read, t1 as b read;
-ERROR HY000: Can't reopen table: 't1'
alter table t1 add column j int;
unlock tables;
drop table t1;
diff --git a/mysql-test/r/reopen_temp_table.result b/mysql-test/r/reopen_temp_table.result
new file mode 100644
index 00000000000..f98ab96747f
--- /dev/null
+++ b/mysql-test/r/reopen_temp_table.result
@@ -0,0 +1,133 @@
+#
+# MDEV-5535: Cannot reopen temporary table
+#
+DROP DATABASE IF EXISTS temp_db;
+CREATE DATABASE temp_db;
+USE temp_db;
+#
+# Reopen temporary table
+#
+CREATE TEMPORARY TABLE t1(i int)ENGINE=INNODB;
+INSERT INTO t1 VALUES(1), (2);
+SELECT * FROM t1 a, t1 b;
+i i
+1 1
+2 1
+1 2
+2 2
+DROP TABLE t1;
+#
+# CREATE & Stored routines
+#
+CREATE TEMPORARY TABLE t3 AS SELECT 1 AS a;
+CREATE PROCEDURE p1()
+BEGIN
+DROP TEMPORARY TABLE t3;
+end|
+CREATE FUNCTION f3() RETURNS INT
+BEGIN
+CALL p1();
+RETURN 1;
+END|
+PREPARE STMT FROM "SELECT f3() AS my_Column, a FROM t3";
+EXECUTE STMT;
+ERROR HY000: Can't reopen table: 't3'
+DROP TABLE t3;
+DROP FUNCTION f3;
+DROP PROCEDURE p1;
+CREATE TEMPORARY TABLE t4 (i INT);
+INSERT INTO t4 VALUES(1), (2);
+CREATE FUNCTION f4() RETURNS INT
+BEGIN
+DROP TEMPORARY TABLE t4;
+RETURN 1;
+END|
+SELECT f4() FROM t4;
+ERROR HY000: Can't reopen table: 't4'
+SELECT * FROM t4;
+i
+1
+2
+DROP TABLE t4;
+DROP FUNCTION f4;
+CREATE TEMPORARY TABLE t5 AS SELECT 1 AS a;
+CREATE PROCEDURE p2()
+BEGIN
+DROP TEMPORARY TABLE t5;
+END|
+CREATE FUNCTION f5() RETURNS INT
+BEGIN
+CALL p2();
+RETURN 1;
+END|
+SELECT f5() AS my_column, a FROM t5;
+ERROR HY000: Can't reopen table: 't5'
+DROP TABLE t5;
+DROP FUNCTION f5;
+DROP PROCEDURE p2;
+#
+# CTAS
+#
+CREATE TABLE t1(i INT);
+INSERT INTO t1 VALUES(1), (2);
+CREATE TEMPORARY TABLE t1
+SELECT temp_1.i a, temp_2.i b FROM t1 AS temp_1, t1 AS temp_2;
+SELECT * FROM t1;
+a b
+1 1
+2 1
+1 2
+2 2
+DROP TABLE t1;
+SELECT * FROM t1;
+i
+1
+2
+DROP TABLE t1;
+#
+# HANDLER
+#
+CREATE TABLE t1 (a INT, KEY a(a));
+INSERT INTO t1 (a) VALUES (1), (2), (3), (4), (5);
+CREATE TABLE t2 (a INT, KEY a (a)) SELECT * FROM t1;
+CREATE TEMPORARY TABLE t3 (a INT, KEY a (a)) SELECT * FROM t2;
+HANDLER t3 OPEN;
+SELECT * FROM t1;
+a
+1
+2
+3
+4
+5
+LOCK TABLE t1 READ;
+HANDLER t3 OPEN;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+UNLOCK TABLES;
+HANDLER t3 OPEN;
+ERROR 42000: Not unique table/alias: 't3'
+HANDLER t3 READ NEXT;
+a
+1
+HANDLER t3 OPEN AS t3_1;
+HANDLER t3_1 READ NEXT;
+a
+1
+HANDLER t3_1 READ NEXT;
+a
+2
+HANDLER t3 CLOSE;
+HANDLER t3_1 CLOSE;
+DROP TEMPORARY TABLE t3;
+DROP TABLE t1, t2;
+#
+# INSERT-SELECT
+#
+CREATE TEMPORARY TABLE t4 (a INT) ENGINE=MYISAM;
+INSERT INTO t4 VALUES(1), (2);
+INSERT INTO t4 SELECT * FROM t4;
+SELECT COUNT(*) FROM t4;
+COUNT(*)
+4
+DROP TABLE t4;
+# Cleanup
+DROP DATABASE temp_db;
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index de6b87d67cd..ce23fe1693e 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -1140,9 +1140,12 @@ insert into t3 values (1), (2), (3);
return (select count(*) from t3 as a, t3 as b);
end|
select f11()|
-ERROR HY000: Can't reopen table: 'a'
+f11()
+9
select f11() from t1|
-ERROR HY000: Can't reopen table: 'a'
+f11()
+9
+9
create function f12_1() returns int
begin
drop temporary table if exists t3;
@@ -1156,6 +1159,7 @@ drop temporary table t3|
select f12_1()|
f12_1()
3
+drop temporary table t3|
select f12_1() from t1 limit 1|
f12_1()
3
@@ -6933,7 +6937,7 @@ CREATE TEMPORARY TABLE t3 LIKE t1;
CREATE PROCEDURE p1 () BEGIN SELECT f1 FROM t3 AS A WHERE A.f1 IN ( SELECT f1 FROM t3 ) ;
END|
CALL p1;
-ERROR HY000: Can't reopen table: 'A'
+f1
CREATE VIEW t3 AS SELECT f1 FROM t2 A WHERE A.f1 IN ( SELECT f1 FROM t2 );
DROP TABLE t3;
CALL p1;
diff --git a/mysql-test/suite/handler/aria.result b/mysql-test/suite/handler/aria.result
index 43720eaa4bb..b8ed1fd98c8 100644
--- a/mysql-test/suite/handler/aria.result
+++ b/mysql-test/suite/handler/aria.result
@@ -632,7 +632,18 @@ handler a1 read a next;
a b
3 d
select a,b from t1;
-ERROR HY000: Can't reopen table: 'a1'
+a b
+0 a
+1 b
+2 c
+3 d
+4 e
+5 f
+6 g
+7 h
+8 i
+9 j
+9 k
handler a1 read a prev;
a b
2 c
@@ -745,7 +756,7 @@ ERROR HY000: Can't execute the given command because you have active locked tabl
handler t2 close;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
handler t3 open;
-ERROR HY000: Can't reopen table: 't3'
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
# After UNLOCK TABLES handlers should be around and
# we should be able to continue reading through them.
unlock tables;
@@ -1396,7 +1407,12 @@ handler t2 read a next;
a b
3 NULL
select * from t2;
-ERROR HY000: Can't reopen table: 't2'
+a b
+1 NULL
+2 NULL
+3 NULL
+4 NULL
+5 NULL
handler t2 read a next;
a b
4 NULL
diff --git a/mysql-test/suite/handler/handler.inc b/mysql-test/suite/handler/handler.inc
index b1e881f1bd8..a4ab5f1ed32 100644
--- a/mysql-test/suite/handler/handler.inc
+++ b/mysql-test/suite/handler/handler.inc
@@ -460,9 +460,6 @@ drop table t1;
#
# Bug#30882 Dropping a temporary table inside a stored function may cause a server crash
#
-# Test HANDLER statements in conjunction with temporary tables. While the temporary table
-# is open by a HANDLER, no other statement can access it.
-#
create temporary table t1 (a int, b char(1), key a using btree (a), key b using btree (a,b));
insert into t1 values (0,"a"),(1,"b"),(2,"c"),(3,"d"),(4,"e"),
@@ -472,7 +469,6 @@ handler t1 open as a1;
handler a1 read a=(1);
handler a1 read a next;
handler a1 read a next;
---error ER_CANT_REOPEN_TABLE
select a,b from t1;
handler a1 read a prev;
handler a1 read a prev;
@@ -564,7 +560,7 @@ handler t1 open;
handler t1 read next;
--error ER_LOCK_OR_ACTIVE_TRANSACTION
handler t2 close;
---error ER_CANT_REOPEN_TABLE
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
handler t3 open;
--echo # After UNLOCK TABLES handlers should be around and
--echo # we should be able to continue reading through them.
@@ -1182,7 +1178,6 @@ handler t1 read a next;
select * from t1;
--echo # Sic: the position is not lost
handler t2 read a next;
---error ER_CANT_REOPEN_TABLE
select * from t2;
handler t2 read a next;
drop table t1;
diff --git a/mysql-test/suite/handler/heap.result b/mysql-test/suite/handler/heap.result
index e558911e2e1..70dcefe4ff3 100644
--- a/mysql-test/suite/handler/heap.result
+++ b/mysql-test/suite/handler/heap.result
@@ -632,7 +632,18 @@ handler a1 read a next;
a b
3 d
select a,b from t1;
-ERROR HY000: Can't reopen table: 'a1'
+a b
+0 a
+1 b
+2 c
+3 d
+4 e
+5 f
+6 g
+7 h
+8 i
+9 j
+9 k
handler a1 read a prev;
a b
2 c
@@ -745,7 +756,7 @@ ERROR HY000: Can't execute the given command because you have active locked tabl
handler t2 close;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
handler t3 open;
-ERROR HY000: Can't reopen table: 't3'
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
# After UNLOCK TABLES handlers should be around and
# we should be able to continue reading through them.
unlock tables;
@@ -1396,7 +1407,12 @@ handler t2 read a next;
a b
3 NULL
select * from t2;
-ERROR HY000: Can't reopen table: 't2'
+a b
+1 NULL
+2 NULL
+3 NULL
+4 NULL
+5 NULL
handler t2 read a next;
a b
4 NULL
diff --git a/mysql-test/suite/handler/innodb.result b/mysql-test/suite/handler/innodb.result
index fc1089ee445..f3c0f798902 100644
--- a/mysql-test/suite/handler/innodb.result
+++ b/mysql-test/suite/handler/innodb.result
@@ -633,7 +633,18 @@ handler a1 read a next;
a b
3 d
select a,b from t1;
-ERROR HY000: Can't reopen table: 'a1'
+a b
+0 a
+1 b
+2 c
+3 d
+4 e
+5 f
+6 g
+7 h
+8 i
+9 j
+9 k
handler a1 read a prev;
a b
2 c
@@ -747,7 +758,7 @@ ERROR HY000: Can't execute the given command because you have active locked tabl
handler t2 close;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
handler t3 open;
-ERROR HY000: Can't reopen table: 't3'
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
# After UNLOCK TABLES handlers should be around and
# we should be able to continue reading through them.
unlock tables;
@@ -1400,7 +1411,12 @@ handler t2 read a next;
a b
3 NULL
select * from t2;
-ERROR HY000: Can't reopen table: 't2'
+a b
+1 NULL
+2 NULL
+3 NULL
+4 NULL
+5 NULL
handler t2 read a next;
a b
4 NULL
diff --git a/mysql-test/suite/handler/myisam.result b/mysql-test/suite/handler/myisam.result
index 84cd8bbd5d2..fca75f3b7a6 100644
--- a/mysql-test/suite/handler/myisam.result
+++ b/mysql-test/suite/handler/myisam.result
@@ -632,7 +632,18 @@ handler a1 read a next;
a b
3 d
select a,b from t1;
-ERROR HY000: Can't reopen table: 'a1'
+a b
+0 a
+1 b
+2 c
+3 d
+4 e
+5 f
+6 g
+7 h
+8 i
+9 j
+9 k
handler a1 read a prev;
a b
2 c
@@ -745,7 +756,7 @@ ERROR HY000: Can't execute the given command because you have active locked tabl
handler t2 close;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
handler t3 open;
-ERROR HY000: Can't reopen table: 't3'
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
# After UNLOCK TABLES handlers should be around and
# we should be able to continue reading through them.
unlock tables;
@@ -1396,7 +1407,12 @@ handler t2 read a next;
a b
3 NULL
select * from t2;
-ERROR HY000: Can't reopen table: 't2'
+a b
+1 NULL
+2 NULL
+3 NULL
+4 NULL
+5 NULL
handler t2 read a next;
a b
4 NULL
diff --git a/mysql-test/suite/rpl/r/rpl_reopen_temp_table.result b/mysql-test/suite/rpl/r/rpl_reopen_temp_table.result
new file mode 100644
index 00000000000..2c4ffba622b
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_reopen_temp_table.result
@@ -0,0 +1,30 @@
+include/master-slave.inc
+[connection master]
+connection slave;
+reset master;
+#
+# MDEV-5535: Cannot reopen temporary table
+#
+connection master;
+DROP TABLE IF EXISTS t1, t2, t3;
+CREATE TEMPORARY TABLE t1(c1 INT) ENGINE=INNODB;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+CREATE TEMPORARY TABLE t2 SELECT A.c1 a, B.c1 b FROM t1 AS A, t1 AS B;
+CREATE TABLE t3 SELECT * FROM t2;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+SELECT COUNT(*) = 25 FROM t2;
+COUNT(*) = 25
+1
+SELECT COUNT(*) = 25 FROM t3;
+COUNT(*) = 25
+1
+connection slave;
+SELECT COUNT(*) = 25 FROM t3;
+COUNT(*) = 25
+1
+connection master;
+DROP TABLE t1, t2, t3;
+connection slave;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_reopen_temp_table.test b/mysql-test/suite/rpl/t/rpl_reopen_temp_table.test
new file mode 100644
index 00000000000..2396dc348fe
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_reopen_temp_table.test
@@ -0,0 +1,43 @@
+--source include/have_innodb.inc
+--source include/master-slave.inc
+
+# Clean up old slave's binlogs (see rpl_temporary.test for explanation).
+save_master_pos;
+connection slave;
+sync_with_master;
+reset master;
+
+--echo #
+--echo # MDEV-5535: Cannot reopen temporary table
+--echo #
+
+connection master;
+--disable_query_log
+CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
+--enable_query_log
+
+disable_warnings;
+DROP TABLE IF EXISTS t1, t2, t3;
+enable_warnings;
+
+CREATE TEMPORARY TABLE t1(c1 INT) ENGINE=INNODB;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+
+CREATE TEMPORARY TABLE t2 SELECT A.c1 a, B.c1 b FROM t1 AS A, t1 AS B;
+
+CREATE TABLE t3 SELECT * FROM t2;
+
+SELECT COUNT(*) = 5 FROM t1;
+SELECT COUNT(*) = 25 FROM t2;
+SELECT COUNT(*) = 25 FROM t3;
+
+sync_slave_with_master;
+
+SELECT COUNT(*) = 25 FROM t3;
+
+connection master;
+DROP TABLE t1, t2, t3;
+
+sync_slave_with_master;
+
+--source include/rpl_end.inc
diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test
index 10ee41ca2aa..0fd3e31a5b4 100644
--- a/mysql-test/t/create.test
+++ b/mysql-test/t/create.test
@@ -1618,7 +1618,6 @@ drop view t1;
create table t1 (a int) select 1 as a;
create temporary table if not exists t1 (a int) select * from t1;
---error ER_CANT_REOPEN_TABLE
create temporary table if not exists t1 (a int) select * from t1;
select * from t1;
drop temporary table t1;
diff --git a/mysql-test/t/lock.test b/mysql-test/t/lock.test
index 23eb04d7826..2e164de9b93 100644
--- a/mysql-test/t/lock.test
+++ b/mysql-test/t/lock.test
@@ -442,11 +442,6 @@ alter table t1 add column j int;
unlock tables;
drop table t1;
create temporary table t1 (i int);
---echo #
---echo # This is just for test coverage purposes,
---echo # when this is allowed, remove the --error.
---echo #
---error ER_CANT_REOPEN_TABLE
lock tables t1 write, t1 as a read, t1 as b read;
alter table t1 add column j int;
unlock tables;
diff --git a/mysql-test/t/reopen_temp_table.test b/mysql-test/t/reopen_temp_table.test
new file mode 100644
index 00000000000..0cf3f774985
--- /dev/null
+++ b/mysql-test/t/reopen_temp_table.test
@@ -0,0 +1,128 @@
+--source include/have_innodb.inc
+
+--echo #
+--echo # MDEV-5535: Cannot reopen temporary table
+--echo #
+
+--disable_warnings
+DROP DATABASE IF EXISTS temp_db;
+--enable_warnings
+
+CREATE DATABASE temp_db;
+USE temp_db;
+
+--echo #
+--echo # Reopen temporary table
+--echo #
+
+CREATE TEMPORARY TABLE t1(i int)ENGINE=INNODB;
+INSERT INTO t1 VALUES(1), (2);
+SELECT * FROM t1 a, t1 b;
+DROP TABLE t1;
+
+--echo #
+--echo # CREATE & Stored routines
+--echo #
+
+CREATE TEMPORARY TABLE t3 AS SELECT 1 AS a;
+DELIMITER |;
+CREATE PROCEDURE p1()
+BEGIN
+ DROP TEMPORARY TABLE t3;
+end|
+CREATE FUNCTION f3() RETURNS INT
+BEGIN
+ CALL p1();
+ RETURN 1;
+END|
+DELIMITER ;|
+PREPARE STMT FROM "SELECT f3() AS my_Column, a FROM t3";
+--error ER_CANT_REOPEN_TABLE
+EXECUTE STMT;
+DROP TABLE t3;
+DROP FUNCTION f3;
+DROP PROCEDURE p1;
+
+CREATE TEMPORARY TABLE t4 (i INT);
+INSERT INTO t4 VALUES(1), (2);
+DELIMITER |;
+CREATE FUNCTION f4() RETURNS INT
+BEGIN
+ DROP TEMPORARY TABLE t4;
+ RETURN 1;
+END|
+DELIMITER ;|
+--error ER_CANT_REOPEN_TABLE
+SELECT f4() FROM t4;
+SELECT * FROM t4;
+DROP TABLE t4;
+DROP FUNCTION f4;
+
+CREATE TEMPORARY TABLE t5 AS SELECT 1 AS a;
+DELIMITER |;
+CREATE PROCEDURE p2()
+BEGIN
+ DROP TEMPORARY TABLE t5;
+END|
+CREATE FUNCTION f5() RETURNS INT
+BEGIN
+ CALL p2();
+ RETURN 1;
+END|
+DELIMITER ;|
+--error ER_CANT_REOPEN_TABLE
+SELECT f5() AS my_column, a FROM t5;
+DROP TABLE t5;
+DROP FUNCTION f5;
+DROP PROCEDURE p2;
+
+--echo #
+--echo # CTAS
+--echo #
+
+CREATE TABLE t1(i INT);
+INSERT INTO t1 VALUES(1), (2);
+CREATE TEMPORARY TABLE t1
+ SELECT temp_1.i a, temp_2.i b FROM t1 AS temp_1, t1 AS temp_2;
+SELECT * FROM t1;
+DROP TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # HANDLER
+--echo #
+
+CREATE TABLE t1 (a INT, KEY a(a));
+INSERT INTO t1 (a) VALUES (1), (2), (3), (4), (5);
+CREATE TABLE t2 (a INT, KEY a (a)) SELECT * FROM t1;
+CREATE TEMPORARY TABLE t3 (a INT, KEY a (a)) SELECT * FROM t2;
+HANDLER t3 OPEN;
+SELECT * FROM t1;
+LOCK TABLE t1 READ;
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
+HANDLER t3 OPEN;
+UNLOCK TABLES;
+--error ER_NONUNIQ_TABLE
+HANDLER t3 OPEN;
+HANDLER t3 READ NEXT;
+HANDLER t3 OPEN AS t3_1;
+HANDLER t3_1 READ NEXT;
+HANDLER t3_1 READ NEXT;
+HANDLER t3 CLOSE;
+HANDLER t3_1 CLOSE;
+DROP TEMPORARY TABLE t3;
+DROP TABLE t1, t2;
+
+--echo #
+--echo # INSERT-SELECT
+--echo #
+
+CREATE TEMPORARY TABLE t4 (a INT) ENGINE=MYISAM;
+INSERT INTO t4 VALUES(1), (2);
+INSERT INTO t4 SELECT * FROM t4;
+SELECT COUNT(*) FROM t4;
+DROP TABLE t4;
+
+--echo # Cleanup
+DROP DATABASE temp_db;
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 9e6b919ea19..c80e1eaaa3e 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -1368,11 +1368,6 @@ select f10()|
create table t4 as select 1 as id|
select f10()|
-# Practical cases which we don't handle well (yet)
-#
-# Function which does not work because of well-known and documented
-# limitation of MySQL. We can't use the several instances of the
-# same temporary table in statement.
create function f11() returns int
begin
drop temporary table if exists t3;
@@ -1380,9 +1375,7 @@ begin
insert into t3 values (1), (2), (3);
return (select count(*) from t3 as a, t3 as b);
end|
---error ER_CANT_REOPEN_TABLE
select f11()|
---error ER_CANT_REOPEN_TABLE
select f11() from t1|
# Test that using a single table instance at a time works
create function f12_1() returns int
@@ -1397,6 +1390,7 @@ create function f12_2() returns int
drop temporary table t3|
select f12_1()|
+drop temporary table t3|
select f12_1() from t1 limit 1|
# Cleanup
@@ -8278,7 +8272,6 @@ delimiter |;
CREATE PROCEDURE p1 () BEGIN SELECT f1 FROM t3 AS A WHERE A.f1 IN ( SELECT f1 FROM t3 ) ;
END|
delimiter ;|
---error ER_CANT_REOPEN_TABLE
CALL p1;
CREATE VIEW t3 AS SELECT f1 FROM t2 A WHERE A.f1 IN ( SELECT f1 FROM t2 );
DROP TABLE t3;
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 062e59bee5b..089d793b2b0 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (c) 2006, 2014, Oracle and/or its affiliates.
-# Copyright (c) 2010, 2015, MariaDB
+# Copyright (c) 2010, 2016, MariaDB Corporation
#
# 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
@@ -141,7 +141,7 @@ SET (SQL_SOURCE
item_windowfunc.cc sql_window.cc
sql_cte.cc sql_cte.h
${WSREP_SOURCES}
- table_cache.cc encryption.cc
+ table_cache.cc encryption.cc temporary_tables.cc
${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc
${GEN_SOURCES}
${GEN_DIGEST_SOURCES}
diff --git a/sql/log_event.cc b/sql/log_event.cc
index c966d36b732..f7e718fccd0 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -6159,7 +6159,7 @@ int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
update it inside mysql_load().
*/
List<Item> tmp_list;
- if (open_temporary_tables(thd, &tables) ||
+ if (thd->open_temporary_tables(&tables) ||
mysql_load(thd, &ex, &tables, field_list, tmp_list, tmp_list,
handle_dup, ignore, net != 0))
thd->is_slave_error= 1;
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index f9d0910a2a7..f8f06d613f4 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -1,5 +1,6 @@
/* Copyright (c) 2006, 2013, Oracle and/or its affiliates.
Copyright (c) 2010, 2013, Monty Program Ab
+ Copyright (c) 2016, MariaDB Corporation
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
@@ -52,8 +53,8 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery)
no_storage(FALSE), replicate_same_server_id(::replicate_same_server_id),
info_fd(-1), cur_log_fd(-1), relay_log(&sync_relaylog_period),
sync_counter(0), is_relay_log_recovery(is_slave_recovery),
- save_temporary_tables(0), mi(0),
- inuse_relaylog_list(0), last_inuse_relaylog(0),
+ save_temporary_tables(0),
+ mi(0), inuse_relaylog_list(0), last_inuse_relaylog(0),
cur_log_old_open_count(0), group_relay_log_pos(0),
event_relay_log_pos(0),
#if HAVE_valgrind
@@ -1062,24 +1063,53 @@ void Relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
void Relay_log_info::close_temporary_tables()
{
- TABLE *table,*next;
DBUG_ENTER("Relay_log_info::close_temporary_tables");
- for (table=save_temporary_tables ; table ; table=next)
+ TMP_TABLE_SHARE *share;
+ TABLE *table;
+
+ if (!save_temporary_tables)
{
- next=table->next;
+ /* There are no temporary tables. */
+ DBUG_VOID_RETURN;
+ }
+
+ while ((share= save_temporary_tables->pop_front()))
+ {
+ /*
+ Iterate over the list of tables for this TABLE_SHARE and close them.
+ */
+ while ((table= share->all_tmp_tables.pop_front()))
+ {
+ DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'",
+ table->s->db.str, table->s->table_name.str));
+
+ /* Reset in_use as the table may have been created by another thd */
+ table->in_use= 0;
+ /*
+ Lets not free TABLE_SHARE here as there could be multiple TABLEs opened
+ for the same table (TABLE_SHARE).
+ */
+ closefrm(table);
+ my_free(table);
+ }
- /* Reset in_use as the table may have been created by another thd */
- table->in_use=0;
/*
Don't ask for disk deletion. For now, anyway they will be deleted when
slave restarts, but it is a better intention to not delete them.
*/
- DBUG_PRINT("info", ("table: 0x%lx", (long) table));
- close_temporary(table, 1, 0);
+
+ free_table_share(share);
+ my_free(share);
}
- save_temporary_tables= 0;
+
+ /* By now, there mustn't be any elements left in the list. */
+ DBUG_ASSERT(save_temporary_tables->is_empty());
+
+ my_free(save_temporary_tables);
+ save_temporary_tables= NULL;
slave_open_temp_tables= 0;
+
DBUG_VOID_RETURN;
}
@@ -1756,6 +1786,7 @@ void rpl_group_info::cleanup_context(THD *thd, bool error)
}
m_table_map.clear_tables();
slave_close_thread_tables(thd);
+
if (error)
{
thd->mdl_context.release_transactional_locks();
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index 3eaee90d0f6..c5b495cbc30 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -148,7 +148,7 @@ public:
Protected by data_lock.
*/
- TABLE *save_temporary_tables;
+ All_tmp_tables_list *save_temporary_tables;
/*
standard lock acquisition order to avoid deadlocks:
diff --git a/sql/slave.cc b/sql/slave.cc
index 3fd4b2a19c3..f02ef5e036b 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2008, 2015, MariaDB
+ Copyright (c) 2008, 2016, MariaDB Corporation
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
@@ -4895,8 +4895,11 @@ err_during_init:
/*
TODO: see if we can do this conditionally in next_event() instead
to avoid unneeded position re-init
+
+ We only reset THD::temporary_tables to 0 here and not free it, as this
+ could be used by slave through Relay_log_info::save_temporary_tables.
*/
- thd->temporary_tables = 0; // remove tempation from destructor to close them
+ thd->temporary_tables= 0;
rli->sql_driver_thd= 0;
thd->rgi_fake= thd->rgi_slave= NULL;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index d58b51afc5e..06a2022d914 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -3077,7 +3077,7 @@ int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
Check whenever we have access to tables for this statement
and open and lock them before executing instructions core function.
*/
- if (open_temporary_tables(thd, tables) ||
+ if (thd->open_temporary_tables(tables) ||
check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)
|| open_and_lock_tables(thd, tables, TRUE, 0))
result= -1;
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index 5c400e44bc7..4414f11ecd4 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -54,7 +54,7 @@ static bool admin_recreate_table(THD *thd, TABLE_LIST *table_list)
DEBUG_SYNC(thd, "ha_admin_try_alter");
tmp_disable_binlog(thd); // binlogging is done by caller if wanted
- result_code= (open_temporary_tables(thd, table_list) ||
+ result_code= (thd->open_temporary_tables(table_list) ||
mysql_recreate_table(thd, table_list, false));
reenable_binlog(thd);
/*
@@ -445,7 +445,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
da->push_warning_info(&tmp_wi);
- open_error= (open_temporary_tables(thd, table) ||
+ open_error= (thd->open_temporary_tables(table) ||
open_and_lock_tables(thd, table, TRUE, 0));
da->pop_warning_info();
@@ -460,7 +460,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
mode. It does make sense for the user to see such errors.
*/
- open_error= (open_temporary_tables(thd, table) ||
+ open_error= (thd->open_temporary_tables(table) ||
open_and_lock_tables(thd, table, TRUE, 0));
}
thd->prepare_derived_at_open= FALSE;
@@ -952,7 +952,7 @@ send_result_message:
table->mdl_request.ticket= NULL;
DEBUG_SYNC(thd, "ha_admin_open_ltable");
table->mdl_request.set_type(MDL_SHARED_WRITE);
- if (!open_temporary_tables(thd, table) &&
+ if (!thd->open_temporary_tables(table) &&
(table->table= open_ltable(thd, table, lock_type, 0)))
{
uint save_flags;
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index bff45e089a4..737d3cca729 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -1,4 +1,5 @@
/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2016, MariaDB Corporation
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
@@ -16,7 +17,6 @@
#include "sql_parse.h" // check_access
#include "sql_table.h" // mysql_alter_table,
// mysql_exchange_partition
-#include "sql_base.h" // open_temporary_tables
#include "sql_alter.h"
#include "wsrep_mysqld.h"
@@ -305,10 +305,8 @@ bool Sql_cmd_alter_table::execute(THD *thd)
thd->enable_slow_log= opt_log_slow_admin_statements;
#ifdef WITH_WSREP
- TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl);
-
if ((!thd->is_current_stmt_binlog_format_row() ||
- !find_temporary_table(thd, first_table)))
+ !thd->find_temporary_table(first_table)))
{
WSREP_TO_ISOLATION_BEGIN(((lex->name.str) ? select_lex->db : NULL),
((lex->name.str) ? lex->name.str : NULL),
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index e6f8b291778..e14fb1b4e5f 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -172,47 +172,13 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list);
/**
- Create a table cache/table definition cache key
-
- @param thd Thread context
- @param key Buffer for the key to be created (must be of
- size MAX_DBKEY_LENGTH).
- @param db_name Database name.
- @param table_name Table name.
-
- @note
- The table cache_key is created from:
- db_name + \0
- table_name + \0
-
- additionally we add the following to make each tmp table
- unique on the slave:
-
- 4 bytes for master thread id
- 4 bytes pseudo thread id
-
- @return Length of key.
-*/
-
-uint create_tmp_table_def_key(THD *thd, char *key,
- const char *db, const char *table_name)
-{
- uint key_length= tdc_create_key(key, db, table_name);
- int4store(key + key_length, thd->variables.server_id);
- int4store(key + key_length + 4, thd->variables.pseudo_thread_id);
- key_length+= TMP_TABLE_KEY_EXTRA;
- return key_length;
-}
-
-
-/**
Get table cache key for a table list element.
@param table_list[in] Table list element.
@param key[out] On return points to table cache key for the table.
@note Unlike create_table_def_key() call this function doesn't construct
- key in a buffer provider by caller. Instead it relies on the fact
+ key in a buffer provided by caller. Instead it relies on the fact
that table list element for which key is requested has properly
initialized MDL_request object and the fact that table definition
cache key is suffix of key used in MDL subsystem. So to get table
@@ -304,7 +270,7 @@ static my_bool list_open_tables_callback(TDC_element *element,
(*arg->start_list)->in_use= 0;
mysql_mutex_lock(&element->LOCK_table_share);
- TDC_element::All_share_tables_list::Iterator it(element->all_tables);
+ All_share_tables_list::Iterator it(element->all_tables);
TABLE *table;
while ((table= it++))
if (table->in_use)
@@ -602,96 +568,6 @@ bool close_cached_connection_tables(THD *thd, LEX_STRING *connection)
}
-/**
- Mark all temporary tables which were used by the current statement or
- substatement as free for reuse, but only if the query_id can be cleared.
-
- @param thd thread context
-
- @remark For temp tables associated with a open SQL HANDLER the query_id
- is not reset until the HANDLER is closed.
-*/
-
-static void mark_temp_tables_as_free_for_reuse(THD *thd)
-{
- rpl_group_info *rgi_slave;
- DBUG_ENTER("mark_temp_tables_as_free_for_reuse");
-
- if (thd->query_id == 0)
- {
- /* Thread has not executed any statement and has not used any tmp tables */
- DBUG_VOID_RETURN;
- }
-
- rgi_slave=thd->rgi_slave;
- if ((!rgi_slave && thd->temporary_tables) ||
- (rgi_slave && unlikely(rgi_slave->rli->save_temporary_tables)))
- {
- thd->lock_temporary_tables();
- for (TABLE *table= thd->temporary_tables ; table ; table= table->next)
- {
- if ((table->query_id == thd->query_id) && ! table->open_by_handler)
- mark_tmp_table_for_reuse(table);
- }
- thd->unlock_temporary_tables();
- if (rgi_slave)
- {
- /*
- Temporary tables are shared with other by sql execution threads.
- As a safety messure, clear the pointer to the common area.
- */
- thd->temporary_tables= 0;
- }
- }
- DBUG_VOID_RETURN;
-}
-
-
-/**
- Reset a single temporary table.
- Effectively this "closes" one temporary table,
- in a session.
-
- @param table Temporary table.
-*/
-
-void mark_tmp_table_for_reuse(TABLE *table)
-{
- DBUG_ENTER("mark_tmp_table_for_reuse");
- DBUG_ASSERT(table->s->tmp_table);
-
- table->query_id= 0;
- table->file->ha_reset();
-
- /* Detach temporary MERGE children from temporary parent. */
- DBUG_ASSERT(table->file);
- table->file->extra(HA_EXTRA_DETACH_CHILDREN);
-
- /*
- Reset temporary table lock type to it's default value (TL_WRITE).
-
- Statements such as INSERT INTO .. SELECT FROM tmp, CREATE TABLE
- .. SELECT FROM tmp and UPDATE may under some circumstances modify
- the lock type of the tables participating in the statement. This
- isn't a problem for non-temporary tables since their lock type is
- reset at every open, but the same does not occur for temporary
- tables for historical reasons.
-
- Furthermore, the lock type of temporary tables is not really that
- important because they can only be used by one query at a time and
- not even twice in a query -- a temporary table is represented by
- only one TABLE object. Nonetheless, it's safer from a maintenance
- point of view to reset the lock type of this singleton TABLE object
- as to not cause problems when the table is reused.
-
- Even under LOCK TABLES mode its okay to reset the lock type as
- LOCK TABLES is allowed (but ignored) for a temporary table.
- */
- table->reginfo.lock_type= TL_WRITE;
- DBUG_VOID_RETURN;
-}
-
-
/*
Mark all tables in the list which were used by current substatement
as free for reuse.
@@ -894,7 +770,7 @@ void close_thread_tables(THD *thd)
/*
Mark all temporary tables used by this statement as free for reuse.
*/
- mark_temp_tables_as_free_for_reuse(thd);
+ thd->mark_tmp_tables_as_free_for_reuse();
if (thd->locked_tables_mode)
{
@@ -1008,196 +884,6 @@ void close_thread_table(THD *thd, TABLE **table_ptr)
}
-/* close_temporary_tables' internal, 4 is due to uint4korr definition */
-static inline uint tmpkeyval(THD *thd, TABLE *table)
-{
- return uint4korr(table->s->table_cache_key.str + table->s->table_cache_key.length - 4);
-}
-
-
-/*
- Close all temporary tables created by 'CREATE TEMPORARY TABLE' for thread
- creates one DROP TEMPORARY TABLE binlog event for each pseudo-thread
-
- Temporary tables created in a sql slave is closed by
- Relay_log_info::close_temporary_tables()
-
-*/
-
-bool close_temporary_tables(THD *thd)
-{
- DBUG_ENTER("close_temporary_tables");
- TABLE *table;
- TABLE *next= NULL;
- TABLE *prev_table;
- /* Assume thd->variables.option_bits has OPTION_QUOTE_SHOW_CREATE */
- bool was_quote_show= TRUE;
- bool error= 0;
-
- if (!thd->temporary_tables)
- DBUG_RETURN(FALSE);
- DBUG_ASSERT(!thd->rgi_slave);
-
- /*
- Ensure we don't have open HANDLERs for tables we are about to close.
- This is necessary when close_temporary_tables() is called as part
- of execution of BINLOG statement (e.g. for format description event).
- */
- mysql_ha_rm_temporary_tables(thd);
- if (!mysql_bin_log.is_open())
- {
- TABLE *tmp_next;
- for (TABLE *t= thd->temporary_tables; t; t= tmp_next)
- {
- tmp_next= t->next;
- mysql_lock_remove(thd, thd->lock, t);
- close_temporary(t, 1, 1);
- }
- thd->temporary_tables= 0;
- DBUG_RETURN(FALSE);
- }
-
- /* Better add "if exists", in case a RESET MASTER has been done */
- const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ";
- char buf[FN_REFLEN];
- String s_query(buf, sizeof(buf), system_charset_info);
- bool found_user_tables= FALSE;
-
- s_query.copy(stub, sizeof(stub)-1, system_charset_info);
-
- /*
- Insertion sort of temp tables by pseudo_thread_id to build ordered list
- of sublists of equal pseudo_thread_id
- */
-
- for (prev_table= thd->temporary_tables, table= prev_table->next;
- table;
- prev_table= table, table= table->next)
- {
- TABLE *prev_sorted /* same as for prev_table */, *sorted;
- if (is_user_table(table))
- {
- if (!found_user_tables)
- found_user_tables= true;
- for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table;
- prev_sorted= sorted, sorted= sorted->next)
- {
- if (!is_user_table(sorted) ||
- tmpkeyval(thd, sorted) > tmpkeyval(thd, table))
- {
- /* move into the sorted part of the list from the unsorted */
- prev_table->next= table->next;
- table->next= sorted;
- if (prev_sorted)
- {
- prev_sorted->next= table;
- }
- else
- {
- thd->temporary_tables= table;
- }
- table= prev_table;
- break;
- }
- }
- }
- }
-
- /* We always quote db,table names though it is slight overkill */
- if (found_user_tables &&
- !(was_quote_show= MY_TEST(thd->variables.option_bits &
- OPTION_QUOTE_SHOW_CREATE)))
- {
- thd->variables.option_bits |= OPTION_QUOTE_SHOW_CREATE;
- }
-
- /* scan sorted tmps to generate sequence of DROP */
- for (table= thd->temporary_tables; table; table= next)
- {
- if (is_user_table(table))
- {
- bool save_thread_specific_used= thd->thread_specific_used;
- my_thread_id save_pseudo_thread_id= thd->variables.pseudo_thread_id;
- char db_buf[FN_REFLEN];
- String db(db_buf, sizeof(db_buf), system_charset_info);
-
- /* Set pseudo_thread_id to be that of the processed table */
- thd->variables.pseudo_thread_id= tmpkeyval(thd, table);
-
- db.copy(table->s->db.str, table->s->db.length, system_charset_info);
- /* Reset s_query() if changed by previous loop */
- s_query.length(sizeof(stub)-1);
-
- /* Loop forward through all tables that belong to a common database
- within the sublist of common pseudo_thread_id to create single
- DROP query
- */
- for (;
- table && is_user_table(table) &&
- (ulong) tmpkeyval(thd, table) ==
- (ulong) thd->variables.pseudo_thread_id &&
- table->s->db.length == db.length() &&
- memcmp(table->s->db.str, db.ptr(), db.length()) == 0;
- table= next)
- {
- /*
- We are going to add ` around the table names and possible more
- due to special characters
- */
- append_identifier(thd, &s_query, table->s->table_name.str,
- strlen(table->s->table_name.str));
- s_query.append(',');
- next= table->next;
- mysql_lock_remove(thd, thd->lock, table);
- close_temporary(table, 1, 1);
- }
- thd->clear_error();
- CHARSET_INFO *cs_save= thd->variables.character_set_client;
- thd->variables.character_set_client= system_charset_info;
- thd->thread_specific_used= TRUE;
- Query_log_event qinfo(thd, s_query.ptr(),
- s_query.length() - 1 /* to remove trailing ',' */,
- FALSE, TRUE, FALSE, 0);
- qinfo.db= db.ptr();
- qinfo.db_len= db.length();
- thd->variables.character_set_client= cs_save;
-
- thd->get_stmt_da()->set_overwrite_status(true);
- if ((error= (mysql_bin_log.write(&qinfo) || error)))
- {
- /*
- If we're here following THD::cleanup, thence the connection
- has been closed already. So lets print a message to the
- error log instead of pushing yet another error into the
- stmt_da.
-
- Also, we keep the error flag so that we propagate the error
- up in the stack. This way, if we're the SQL thread we notice
- that close_temporary_tables failed. (Actually, the SQL
- thread only calls close_temporary_tables while applying old
- Start_log_event_v3 events.)
- */
- sql_print_error("Failed to write the DROP statement for "
- "temporary tables to binary log");
- }
- thd->get_stmt_da()->set_overwrite_status(false);
-
- thd->variables.pseudo_thread_id= save_pseudo_thread_id;
- thd->thread_specific_used= save_thread_specific_used;
- }
- else
- {
- next= table->next;
- close_temporary(table, 1, 1);
- }
- }
- if (!was_quote_show)
- thd->variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE; /* restore option */
- thd->temporary_tables=0;
-
- DBUG_RETURN(error);
-}
-
/*
Find table in list.
@@ -1470,291 +1156,6 @@ void update_non_unique_table_error(TABLE_LIST *update,
/**
- Find temporary table specified by database and table names in the
- THD::temporary_tables list.
-
- @return TABLE instance if a temporary table has been found; NULL otherwise.
-*/
-
-TABLE *find_temporary_table(THD *thd, const char *db, const char *table_name)
-{
- char key[MAX_DBKEY_LENGTH];
- uint key_length= create_tmp_table_def_key(thd, key, db, table_name);
- return find_temporary_table(thd, key, key_length);
-}
-
-
-/**
- Find a temporary table specified by TABLE_LIST instance in the
- THD::temporary_tables list.
-
- @return TABLE instance if a temporary table has been found; NULL otherwise.
-*/
-
-TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl)
-{
- const char *tmp_key;
- char key[MAX_DBKEY_LENGTH];
- uint key_length;
-
- key_length= get_table_def_key(tl, &tmp_key);
- memcpy(key, tmp_key, key_length);
- int4store(key + key_length, thd->variables.server_id);
- int4store(key + key_length + 4, thd->variables.pseudo_thread_id);
-
- return find_temporary_table(thd, key, key_length + TMP_TABLE_KEY_EXTRA);
-}
-
-
-static bool
-use_temporary_table(THD *thd, TABLE *table, TABLE **out_table)
-{
- *out_table= table;
- if (!table)
- return false;
- /*
- Temporary tables are not safe for parallel replication. They were
- designed to be visible to one thread only, so have no table locking.
- Thus there is no protection against two conflicting transactions
- committing in parallel and things like that.
-
- So for now, anything that uses temporary tables will be serialised
- with anything before it, when using parallel replication.
-
- ToDo: We might be able to introduce a reference count or something
- on temp tables, and have slave worker threads wait for it to reach
- zero before being allowed to use the temp table. Might not be worth
- it though, as statement-based replication using temporary tables is
- in any case rather fragile.
- */
- if (thd->rgi_slave && thd->rgi_slave->is_parallel_exec &&
- thd->wait_for_prior_commit())
- return true;
- /*
- We need to set the THD as it may be different in case of
- parallel replication
- */
- if (table->in_use != thd)
- {
- table->in_use= thd;
-#ifdef REMOVE_AFTER_MERGE_WITH_10
- if (thd->rgi_slave)
- {
- /*
- We may be stealing an opened temporary tables from one slave
- thread to another, we need to let the performance schema know that,
- for aggregates per thread to work properly.
- */
- MYSQL_UNBIND_TABLE(table->file);
- MYSQL_REBIND_TABLE(table->file);
- }
-#endif
- }
- return false;
-}
-
-bool
-find_and_use_temporary_table(THD *thd, const char *db, const char *table_name,
- TABLE **out_table)
-{
- return use_temporary_table(thd, find_temporary_table(thd, db, table_name),
- out_table);
-}
-
-
-bool
-find_and_use_temporary_table(THD *thd, const TABLE_LIST *tl, TABLE **out_table)
-{
- return use_temporary_table(thd, find_temporary_table(thd, tl), out_table);
-}
-
-
-/**
- Find a temporary table specified by a key in the THD::temporary_tables list.
-
- @return TABLE instance if a temporary table has been found; NULL otherwise.
-*/
-
-TABLE *find_temporary_table(THD *thd,
- const char *table_key,
- uint table_key_length)
-{
- TABLE *result= 0;
- if (!thd->have_temporary_tables())
- return NULL;
-
- thd->lock_temporary_tables();
- for (TABLE *table= thd->temporary_tables; table; table= table->next)
- {
- if (table->s->table_cache_key.length == table_key_length &&
- !memcmp(table->s->table_cache_key.str, table_key, table_key_length))
- {
- result= table;
- break;
- }
- }
- thd->unlock_temporary_tables();
- return result;
-}
-
-
-/**
- Drop a temporary table.
-
- Try to locate the table in the list of thd->temporary_tables.
- If the table is found:
- - if the table is being used by some outer statement, fail.
- - if the table is locked with LOCK TABLES or by prelocking,
- unlock it and remove it from the list of locked tables
- (THD::lock). Currently only transactional temporary tables
- are locked.
- - Close the temporary table, remove its .FRM
- - remove the table from the list of temporary tables
-
- This function is used to drop user temporary tables, as well as
- internal tables created in CREATE TEMPORARY TABLE ... SELECT
- or ALTER TABLE. Even though part of the work done by this function
- is redundant when the table is internal, as long as we
- link both internal and user temporary tables into the same
- thd->temporary_tables list, it's impossible to tell here whether
- we're dealing with an internal or a user temporary table.
-
- @param thd Thread handler
- @param table Temporary table to be deleted
- @param is_trans Is set to the type of the table:
- transactional (e.g. innodb) as TRUE or non-transactional
- (e.g. myisam) as FALSE.
-
- @retval 0 the table was found and dropped successfully.
- @retval -1 the table is in use by a outer query
-*/
-
-int drop_temporary_table(THD *thd, TABLE *table, bool *is_trans)
-{
- DBUG_ENTER("drop_temporary_table");
- DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'",
- table->s->db.str, table->s->table_name.str));
-
- /* Table might be in use by some outer statement. */
- if (table->query_id && table->query_id != thd->query_id)
- {
- DBUG_PRINT("info", ("table->query_id: %lu thd->query_id: %lu",
- (ulong) table->query_id, (ulong) thd->query_id));
-
- my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias.c_ptr());
- DBUG_RETURN(-1);
- }
-
- *is_trans= table->file->has_transactions();
-
- /*
- If LOCK TABLES list is not empty and contains this table,
- unlock the table and remove the table from this list.
- */
- mysql_lock_remove(thd, thd->lock, table);
- close_temporary_table(thd, table, 1, 1);
- DBUG_RETURN(0);
-}
-
-
-/*
- unlink from thd->temporary tables and close temporary table
-*/
-
-void close_temporary_table(THD *thd, TABLE *table,
- bool free_share, bool delete_table)
-{
- DBUG_ENTER("close_temporary_table");
- DBUG_PRINT("tmptable", ("closing table: '%s'.'%s' 0x%lx alias: '%s'",
- table->s->db.str, table->s->table_name.str,
- (long) table, table->alias.c_ptr()));
-
- thd->lock_temporary_tables();
- if (table->prev)
- {
- table->prev->next= table->next;
- if (table->prev->next)
- table->next->prev= table->prev;
- }
- else
- {
- /* removing the item from the list */
- DBUG_ASSERT(table == thd->temporary_tables);
- /*
- slave must reset its temporary list pointer to zero to exclude
- passing non-zero value to end_slave via rli->save_temporary_tables
- when no temp tables opened, see an invariant below.
- */
- thd->temporary_tables= table->next;
- if (thd->temporary_tables)
- table->next->prev= 0;
- }
- if (thd->rgi_slave)
- {
- /* natural invariant of temporary_tables */
- DBUG_ASSERT(slave_open_temp_tables || !thd->temporary_tables);
- thread_safe_decrement32(&slave_open_temp_tables);
- table->in_use= 0; // No statistics
- }
- thd->unlock_temporary_tables();
- close_temporary(table, free_share, delete_table);
- DBUG_VOID_RETURN;
-}
-
-
-/*
- Close and delete a temporary table
-
- NOTE
- This dosn't unlink table from thd->temporary
- If this is needed, use close_temporary_table()
-*/
-
-void close_temporary(TABLE *table, bool free_share, bool delete_table)
-{
- handlerton *table_type= table->s->db_type();
- DBUG_ENTER("close_temporary");
- DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'",
- table->s->db.str, table->s->table_name.str));
-
- closefrm(table);
- if (delete_table)
- rm_temporary_table(table_type, table->s->path.str);
- if (free_share)
- {
- free_table_share(table->s);
- my_free(table);
- }
- DBUG_VOID_RETURN;
-}
-
-
-/*
- Used by ALTER TABLE when the table is a temporary one. It changes something
- only if the ALTER contained a RENAME clause (otherwise, table_name is the old
- name).
- Prepares a table cache key, which is the concatenation of db, table_name and
- thd->slave_proxy_id, separated by '\0'.
-*/
-
-bool rename_temporary_table(THD* thd, TABLE *table, const char *db,
- const char *table_name)
-{
- char *key;
- uint key_length;
- TABLE_SHARE *share= table->s;
- DBUG_ENTER("rename_temporary_table");
-
- if (!(key=(char*) alloc_root(&share->mem_root, MAX_DBKEY_LENGTH)))
- DBUG_RETURN(1); /* purecov: inspected */
-
- key_length= create_tmp_table_def_key(thd, key, db, table_name);
- share->set_table_cache_key(key, key_length);
- DBUG_RETURN(0);
-}
-
-
-/**
Force all other threads to stop using the table by upgrading
metadata lock on it and remove unused TABLE instances from cache.
@@ -1819,7 +1220,7 @@ void drop_open_table(THD *thd, TABLE *table, const char *db_name,
{
DBUG_ENTER("drop_open_table");
if (table->s->tmp_table)
- close_temporary_table(thd, table, 1, 1);
+ thd->drop_temporary_table(table, NULL, true);
else
{
DBUG_ASSERT(table == thd->open_tables);
@@ -3935,7 +3336,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
of temporary tables we have to try to open temporary table for it.
We can't simply skip this table list element and postpone opening of
- temporary tabletill the execution of substatement for several reasons:
+ temporary table till the execution of substatement for several reasons:
- Temporary table can be a MERGE table with base underlying tables,
so its underlying tables has to be properly open and locked at
prelocking stage.
@@ -3951,7 +3352,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
The problem is that since those attributes are not set in merge
children, another round of PREPARE will not help.
*/
- error= open_temporary_table(thd, tables);
+ error= thd->open_temporary_table(tables);
if (!error && !tables->table)
error= open_table(thd, tables, ot_ctx);
@@ -3970,7 +3371,8 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
Repair_mrg_table_error_handler repair_mrg_table_handler;
thd->push_internal_handler(&repair_mrg_table_handler);
- error= open_temporary_table(thd, tables);
+ error= thd->open_temporary_table(tables);
+
if (!error && !tables->table)
error= open_table(thd, tables, ot_ctx);
@@ -3986,7 +3388,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
still might need to look for a temporary table if this table
list element corresponds to underlying table of a merge table.
*/
- error= open_temporary_table(thd, tables);
+ error= thd->open_temporary_table(tables);
}
if (!error && !tables->table)
@@ -4158,6 +3560,7 @@ end:
new locks, so use open_tables_check_upgradable_mdl() instead.
@param thd Thread context.
+ @param options DDL options.
@param tables_start Start of list of tables on which upgradable locks
should be acquired.
@param tables_end End of list of tables.
@@ -4360,6 +3763,7 @@ open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
Open all tables in list
@param[in] thd Thread context.
+ @param[in] options DDL options.
@param[in,out] start List of tables to be open (it can be adjusted for
statement that uses tables only implicitly, e.g.
for "SELECT f1()").
@@ -4533,7 +3937,7 @@ restart:
goto error;
/* Re-open temporary tables after close_tables_for_reopen(). */
- if (open_temporary_tables(thd, *start))
+ if (thd->open_temporary_tables(*start))
goto error;
error= FALSE;
@@ -4595,7 +3999,7 @@ restart:
goto error;
/* Re-open temporary tables after close_tables_for_reopen(). */
- if (open_temporary_tables(thd, *start))
+ if (thd->open_temporary_tables(*start))
goto error;
error= FALSE;
@@ -5050,7 +4454,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
bool error;
DBUG_ENTER("open_ltable");
- /* Ignore temporary tables as they have already ben opened*/
+ /* Ignore temporary tables as they have already been opened. */
if (table_list->table)
DBUG_RETURN(table_list->table);
@@ -5137,8 +4541,9 @@ end:
Open all tables in list, locks them and optionally process derived tables.
@param thd Thread context.
+ @param options DDL options.
@param tables List of tables for open and locking.
- @param derived If to handle derived tables.
+ @param derived Whether to handle derived tables.
@param flags Bitmap of options to be used to open and lock
tables (see open_tables() and mysql_lock_tables()
for details).
@@ -5533,176 +4938,6 @@ void close_tables_for_reopen(THD *thd, TABLE_LIST **tables,
}
-/**
- Open a single table without table caching and don't add it to
- THD::open_tables. Depending on the 'add_to_temporary_tables_list' value,
- the opened TABLE instance will be addded to THD::temporary_tables list.
-
- @param thd Thread context.
- @param hton Storage engine of the table, if known,
- or NULL otherwise.
- @param frm frm image
- @param path Path (without .frm)
- @param db Database name.
- @param table_name Table name.
- @param add_to_temporary_tables_list Specifies if the opened TABLE
- instance should be linked into
- THD::temporary_tables list.
- @param open_in_engine Indicates that we need to open table
- in storage engine in addition to
- constructing TABLE object for it.
-
- @note This function is used:
- - by alter_table() to open a temporary table;
- - when creating a temporary table with CREATE TEMPORARY TABLE.
-
- @return TABLE instance for opened table.
- @retval NULL on error.
-*/
-
-TABLE *open_table_uncached(THD *thd, handlerton *hton,
- LEX_CUSTRING *frm,
- const char *path, const char *db,
- const char *table_name,
- bool add_to_temporary_tables_list,
- bool open_in_engine)
-{
- TABLE *tmp_table;
- TABLE_SHARE *share;
- char cache_key[MAX_DBKEY_LENGTH], *saved_cache_key, *tmp_path;
- uint key_length;
- DBUG_ENTER("open_table_uncached");
- DBUG_PRINT("enter",
- ("table: '%s'.'%s' path: '%s' server_id: %u "
- "pseudo_thread_id: %lu",
- db, table_name, path,
- (uint) thd->variables.server_id,
- (ulong) thd->variables.pseudo_thread_id));
-
- if (add_to_temporary_tables_list)
- {
- /* Temporary tables are not safe for parallel replication. */
- if (thd->rgi_slave && thd->rgi_slave->is_parallel_exec &&
- thd->wait_for_prior_commit())
- DBUG_RETURN(NULL);
- }
-
- /* Create the cache_key for temporary tables */
- key_length= create_tmp_table_def_key(thd, cache_key, db, table_name);
-
- if (!(tmp_table= (TABLE*) my_malloc(sizeof(*tmp_table) + sizeof(*share) +
- strlen(path)+1 + key_length,
- MYF(MY_WME))))
- DBUG_RETURN(0); /* purecov: inspected */
-
- share= (TABLE_SHARE*) (tmp_table+1);
- tmp_path= (char*) (share+1);
- saved_cache_key= strmov(tmp_path, path)+1;
- memcpy(saved_cache_key, cache_key, key_length);
-
- init_tmp_table_share(thd, share, saved_cache_key, key_length,
- strend(saved_cache_key)+1, tmp_path);
- share->db_plugin= ha_lock_engine(thd, hton);
-
- /*
- Use the frm image, if possible, open the file otherwise.
-
- The image might be unavailable in ALTER TABLE, when the discovering
- engine took over the ownership (see TABLE::read_frm_image).
- */
- int res= frm->str
- ? share->init_from_binary_frm_image(thd, false, frm->str, frm->length)
- : open_table_def(thd, share, GTS_TABLE | GTS_USE_DISCOVERY);
-
- if (res)
- {
- /* No need to lock share->mutex as this is not needed for tmp tables */
- free_table_share(share);
- my_free(tmp_table);
- DBUG_RETURN(0);
- }
-
- share->m_psi= PSI_CALL_get_table_share(true, share);
-
- if (open_table_from_share(thd, share, table_name,
- open_in_engine ?
- (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
- HA_GET_INDEX) : 0,
- READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
- ha_open_options,
- tmp_table,
- /*
- Set "is_create_table" if the table does not
- exist in SE
- */
- open_in_engine ? false : true))
- {
- /* No need to lock share->mutex as this is not needed for tmp tables */
- free_table_share(share);
- my_free(tmp_table);
- DBUG_RETURN(0);
- }
-
- tmp_table->reginfo.lock_type= TL_WRITE; // Simulate locked
- tmp_table->grant.privilege= TMP_TABLE_ACLS;
- share->tmp_table= (tmp_table->file->has_transactions() ?
- TRANSACTIONAL_TMP_TABLE : NON_TRANSACTIONAL_TMP_TABLE);
-
- if (add_to_temporary_tables_list)
- {
- thd->lock_temporary_tables();
- /* growing temp list at the head */
- tmp_table->next= thd->temporary_tables;
- if (tmp_table->next)
- tmp_table->next->prev= tmp_table;
- thd->temporary_tables= tmp_table;
- thd->temporary_tables->prev= 0;
- if (thd->rgi_slave)
- {
- thread_safe_increment32(&slave_open_temp_tables);
- }
- thd->unlock_temporary_tables();
- }
- tmp_table->pos_in_table_list= 0;
- DBUG_PRINT("tmptable", ("opened table: '%s'.'%s' 0x%lx", tmp_table->s->db.str,
- tmp_table->s->table_name.str, (long) tmp_table));
- DBUG_RETURN(tmp_table);
-}
-
-
-/**
- Delete a temporary table.
-
- @param base Handlerton for table to be deleted.
- @param path Path to the table to be deleted (i.e. path
- to its .frm without an extension).
-
- @retval false - success.
- @retval true - failure.
-*/
-
-bool rm_temporary_table(handlerton *base, const char *path)
-{
- bool error=0;
- handler *file;
- char frm_path[FN_REFLEN + 1];
- DBUG_ENTER("rm_temporary_table");
-
- strxnmov(frm_path, sizeof(frm_path) - 1, path, reg_ext, NullS);
- if (mysql_file_delete(key_file_frm, frm_path, MYF(0)))
- error=1; /* purecov: inspected */
- file= get_new_handler((TABLE_SHARE*) 0, current_thd->mem_root, base);
- if (file && file->ha_delete_table(path))
- {
- error=1;
- sql_print_warning("Could not remove temporary table: '%s', error: %d",
- path, my_errno);
- }
- delete file;
- DBUG_RETURN(error);
-}
-
-
/*****************************************************************************
* The following find_field_in_XXX procedures implement the core of the
* name resolution functionality. The entry point to resolve a column name in a
@@ -5771,164 +5006,6 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
}
-/**
- Find a temporary table specified by TABLE_LIST instance in the cache and
- prepare its TABLE instance for use.
-
- This function tries to resolve this table in the list of temporary tables
- of this thread. Temporary tables are thread-local and "shadow" base
- tables with the same name.
-
- @note In most cases one should use open_temporary_tables() instead
- of this call.
-
- @note One should finalize process of opening temporary table for table
- list element by calling open_and_process_table(). This function
- is responsible for table version checking and handling of merge
- tables.
-
- @note We used to check global_read_lock before opening temporary tables.
- However, that limitation was artificial and is removed now.
-
- @return Error status.
- @retval FALSE On success. If a temporary table exists for the given
- key, tl->table is set.
- @retval TRUE On error. my_error() has been called.
-*/
-
-bool open_temporary_table(THD *thd, TABLE_LIST *tl)
-{
- TABLE *table;
- DBUG_ENTER("open_temporary_table");
- DBUG_PRINT("enter", ("table: '%s'.'%s'", tl->db, tl->table_name));
-
- /*
- Code in open_table() assumes that TABLE_LIST::table can
- be non-zero only for pre-opened temporary tables.
- */
- DBUG_ASSERT(tl->table == NULL);
-
- /*
- This function should not be called for cases when derived or I_S
- tables can be met since table list elements for such tables can
- have invalid db or table name.
- Instead open_temporary_tables() should be used.
- */
- DBUG_ASSERT(!tl->derived && !tl->schema_table);
-
- if (tl->open_type == OT_BASE_ONLY || !thd->have_temporary_tables())
- {
- DBUG_PRINT("info", ("skip_temporary is set or no temporary tables"));
- DBUG_RETURN(FALSE);
- }
-
- if (find_and_use_temporary_table(thd, tl, &table))
- DBUG_RETURN(TRUE);
- if (!table)
- {
- if (tl->open_type == OT_TEMPORARY_ONLY &&
- tl->open_strategy == TABLE_LIST::OPEN_NORMAL)
- {
- my_error(ER_NO_SUCH_TABLE, MYF(0), tl->db, tl->table_name);
- DBUG_RETURN(TRUE);
- }
- DBUG_RETURN(FALSE);
- }
-
- /*
- Temporary tables are not safe for parallel replication. They were
- designed to be visible to one thread only, so have no table locking.
- Thus there is no protection against two conflicting transactions
- committing in parallel and things like that.
-
- So for now, anything that uses temporary tables will be serialised
- with anything before it, when using parallel replication.
-
- ToDo: We might be able to introduce a reference count or something
- on temp tables, and have slave worker threads wait for it to reach
- zero before being allowed to use the temp table. Might not be worth
- it though, as statement-based replication using temporary tables is
- in any case rather fragile.
- */
- if (thd->rgi_slave && thd->rgi_slave->is_parallel_exec &&
- thd->wait_for_prior_commit())
- DBUG_RETURN(true);
-
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- if (tl->partition_names)
- {
- /* Partitioned temporary tables is not supported. */
- DBUG_ASSERT(!table->part_info);
- my_error(ER_PARTITION_CLAUSE_ON_NONPARTITIONED, MYF(0));
- DBUG_RETURN(true);
- }
-#endif
-
- if (table->query_id)
- {
- /*
- We're trying to use the same temporary table twice in a query.
- Right now we don't support this because a temporary table is always
- represented by only one TABLE object in THD, and it can not be
- cloned. Emit an error for an unsupported behaviour.
- */
-
- DBUG_PRINT("error",
- ("query_id: %lu server_id: %u pseudo_thread_id: %lu",
- (ulong) table->query_id, (uint) thd->variables.server_id,
- (ulong) thd->variables.pseudo_thread_id));
- my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias.c_ptr());
- DBUG_RETURN(TRUE);
- }
-
- table->query_id= thd->query_id;
- thd->thread_specific_used= TRUE;
-
- tl->updatable= 1; // It is not derived table nor non-updatable VIEW.
- tl->table= table;
-
- table->init(thd, tl);
-
- DBUG_PRINT("info", ("Using temporary table"));
- DBUG_RETURN(FALSE);
-}
-
-
-/**
- Pre-open temporary tables corresponding to table list elements.
-
- @note One should finalize process of opening temporary tables
- by calling open_tables(). This function is responsible
- for table version checking and handling of merge tables.
-
- @return Error status.
- @retval FALSE On success. If a temporary tables exists for the
- given element, tl->table is set.
- @retval TRUE On error. my_error() has been called.
-*/
-
-bool open_temporary_tables(THD *thd, TABLE_LIST *tl_list)
-{
- TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
- DBUG_ENTER("open_temporary_tables");
-
- for (TABLE_LIST *tl= tl_list; tl && tl != first_not_own; tl= tl->next_global)
- {
- if (tl->derived || tl->schema_table)
- {
- /*
- Derived and I_S tables will be handled by a later call to open_tables().
- */
- continue;
- }
-
- if (open_temporary_table(thd, tl))
- DBUG_RETURN(TRUE);
- }
-
- DBUG_RETURN(FALSE);
-}
-
/*
Find a field by name in a view that uses merge algorithm.
diff --git a/sql/sql_base.h b/sql/sql_base.h
index 040e2897582..8750e6989e1 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -59,8 +59,6 @@ enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
IGNORE_ERRORS, REPORT_EXCEPT_NON_UNIQUE,
IGNORE_EXCEPT_NON_UNIQUE};
-uint create_tmp_table_def_key(THD *thd, char *key, const char *db,
- const char *table_name);
uint get_table_def_key(const TABLE_LIST *table_list, const char **key);
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
uint lock_flags);
@@ -124,11 +122,6 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx);
bool get_key_map_from_key_list(key_map *map, TABLE *table,
List<String> *index_list);
-TABLE *open_table_uncached(THD *thd, handlerton *hton,
- LEX_CUSTRING *frm, const char *path,
- const char *db, const char *table_name,
- bool add_to_temporary_tables_list,
- bool open_in_engine);
TABLE *find_locked_table(TABLE *list, const char *db, const char *table_name);
TABLE *find_write_locked_table(TABLE *list, const char *db,
const char *table_name);
@@ -138,21 +131,12 @@ thr_lock_type read_lock_type_for_table(THD *thd,
bool routine_modifies_data);
my_bool mysql_rm_tmp_tables(void);
-bool rm_temporary_table(handlerton *base, const char *path);
void close_tables_for_reopen(THD *thd, TABLE_LIST **tables,
const MDL_savepoint &start_of_statement_svp);
TABLE_LIST *find_table_in_list(TABLE_LIST *table,
TABLE_LIST *TABLE_LIST::*link,
const char *db_name,
const char *table_name);
-TABLE *find_temporary_table(THD *thd, const char *db, const char *table_name);
-bool find_and_use_temporary_table(THD *thd, const char *db,
- const char *table_name, TABLE **out_table);
-TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl);
-bool find_and_use_temporary_table(THD *thd, const TABLE_LIST *tl,
- TABLE **out_table);
-TABLE *find_temporary_table(THD *thd, const char *table_key,
- uint table_key_length);
void close_thread_tables(THD *thd);
void switch_to_nullable_trigger_fields(List<Item> &items, TABLE *);
bool fill_record_n_invoke_before_triggers(THD *thd, TABLE *table,
@@ -272,17 +256,8 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags,
bool lock_tables(THD *thd, TABLE_LIST *tables, uint counter, uint flags);
int decide_logging_format(THD *thd, TABLE_LIST *tables);
void close_thread_table(THD *thd, TABLE **table_ptr);
-bool close_temporary_tables(THD *thd);
TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
bool check_alias);
-int drop_temporary_table(THD *thd, TABLE *table, bool *is_trans);
-void close_temporary_table(THD *thd, TABLE *table, bool free_share,
- bool delete_table);
-void close_temporary(TABLE *table, bool free_share, bool delete_table);
-bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db,
- const char *table_name);
-bool open_temporary_tables(THD *thd, TABLE_LIST *tl_list);
-bool open_temporary_table(THD *thd, TABLE_LIST *tl);
bool is_equal(const LEX_STRING *a, const LEX_STRING *b);
class Open_tables_backup;
@@ -311,7 +286,6 @@ bool tdc_open_view(THD *thd, TABLE_LIST *table_list, uint flags);
TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db,
const char *table_name,
bool no_error);
-void mark_tmp_table_for_reuse(TABLE *table);
int update_virtual_fields(THD *thd, TABLE *table,
enum enum_vcol_update_mode vcol_update_mode= VCOL_UPDATE_FOR_READ);
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 42b80d9b143..6d1a8efaf22 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1999,36 +1999,32 @@ lookup:
for (; block_table != block_table_end; block_table++)
{
TABLE_LIST table_list;
- TABLE *tmptable;
+ TMP_TABLE_SHARE *tmptable;
Query_cache_table *table = block_table->parent;
/*
- Check that we have not temporary tables with same names of tables
- of this query. If we have such tables, we will not send data from
- query cache, because temporary tables hide real tables by which
+ Check that we do not have temporary tables with same names as that of
+ base tables from this query. If we have such tables, we will not send
+ data from query cache, because temporary tables hide real tables by which
query in query cache was made.
*/
- for (tmptable= thd->temporary_tables; tmptable ; tmptable= tmptable->next)
+ if ((tmptable=
+ thd->find_tmp_table_share_w_base_key((char *) table->data(),
+ table->key_length())))
{
- if (tmptable->s->table_cache_key.length - TMP_TABLE_KEY_EXTRA ==
- table->key_length() &&
- !memcmp(tmptable->s->table_cache_key.str, table->data(),
- table->key_length()))
- {
- DBUG_PRINT("qcache",
- ("Temporary table detected: '%s.%s'",
- tmptable->s->db.str, tmptable->alias.c_ptr()));
- unlock();
- /*
- We should not store result of this query because it contain
- temporary tables => assign following variable to make check
- faster.
- */
- thd->query_cache_is_applicable= 0; // Query can't be cached
- thd->lex->safe_to_cache_query= 0; // For prepared statements
- BLOCK_UNLOCK_RD(query_block);
- DBUG_RETURN(-1);
- }
+ DBUG_PRINT("qcache",
+ ("Temporary table detected: '%s.%s'",
+ tmptable->db.str, tmptable->table_name.str));
+ unlock();
+ /*
+ We should not store result of this query because it contain
+ temporary tables => assign following variable to make check
+ faster.
+ */
+ thd->query_cache_is_applicable= 0; // Query can't be cached
+ thd->lex->safe_to_cache_query= 0; // For prepared statements
+ BLOCK_UNLOCK_RD(query_block);
+ DBUG_RETURN(-1);
}
bzero((char*) &table_list,sizeof(table_list));
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 4b6e4bce3c0..e7324de4ed2 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -37,7 +37,7 @@
#include "tztime.h" // MYSQL_TIME <-> my_time_t
#include "sql_acl.h" // NO_ACCESS,
// acl_getroot_no_password
-#include "sql_base.h" // close_temporary_tables
+#include "sql_base.h"
#include "sql_handler.h" // mysql_ha_cleanup
#include "rpl_rli.h"
#include "rpl_filter.h"
@@ -883,7 +883,8 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
main_da(0, false, false),
m_stmt_da(&main_da),
tdc_hash_pins(0),
- xid_hash_pins(0)
+ xid_hash_pins(0),
+ m_tmp_tables_locked(false)
#ifdef WITH_WSREP
,
wsrep_applier(is_wsrep_applier),
@@ -1586,7 +1587,7 @@ void THD::cleanup(void)
locked_tables_list.unlock_locked_tables(this);
delete_dynamic(&user_var_events);
- close_temporary_tables(this);
+ close_temporary_tables();
transaction.xid_state.xa_state= XA_NOTR;
trans_rollback(this);
@@ -4319,7 +4320,8 @@ void THD::restore_backup_open_tables_state(Open_tables_backup *backup)
Before we will throw away current open tables state we want
to be sure that it was properly cleaned up.
*/
- DBUG_ASSERT(open_tables == 0 && temporary_tables == 0 &&
+ DBUG_ASSERT(open_tables == 0 &&
+ temporary_tables == 0 &&
derived_tables == 0 &&
lock == 0 &&
locked_tables_mode == LTM_NONE &&
@@ -6982,24 +6984,6 @@ THD::signal_wakeup_ready()
}
-void THD::rgi_lock_temporary_tables()
-{
- mysql_mutex_lock(&rgi_slave->rli->data_lock);
- temporary_tables= rgi_slave->rli->save_temporary_tables;
-}
-
-void THD::rgi_unlock_temporary_tables()
-{
- rgi_slave->rli->save_temporary_tables= temporary_tables;
- mysql_mutex_unlock(&rgi_slave->rli->data_lock);
-}
-
-bool THD::rgi_have_temporary_tables()
-{
- return rgi_slave->rli->save_temporary_tables != 0;
-}
-
-
void
wait_for_commit::reinit()
{
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 36ee298caed..783f8b9df11 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1264,6 +1264,61 @@ enum enum_locked_tables_mode
LTM_PRELOCKED_UNDER_LOCK_TABLES
};
+/**
+ The following structure is an extension to TABLE_SHARE and is
+ exclusively for temporary tables.
+
+ @note:
+ Although, TDC_element has data members (like next, prev &
+ all_tables) to store the list of TABLE_SHARE & TABLE objects
+ related to a particular TABLE_SHARE, they cannot be moved to
+ TABLE_SHARE in order to be reused for temporary tables. This
+ is because, as concurrent threads iterating through hash of
+ TDC_element's may need access to all_tables, but if all_tables
+ is made part of TABLE_SHARE, then TDC_element->share->all_tables
+ is not always guaranteed to be valid, as TDC_element can live
+ longer than TABLE_SHARE.
+*/
+struct TMP_TABLE_SHARE : public TABLE_SHARE
+{
+private:
+ /*
+ Link to all temporary table shares. Declared as private to
+ avoid direct manipulation with those objects. One should
+ use methods of I_P_List template instead.
+ */
+ TMP_TABLE_SHARE *tmp_next;
+ TMP_TABLE_SHARE **tmp_prev;
+
+ friend struct All_tmp_table_shares;
+
+public:
+ /*
+ Doubly-linked (back-linked) lists of used and unused TABLE objects
+ for this share.
+ */
+ All_share_tables_list all_tmp_tables;
+};
+
+/**
+ Helper class which specifies which members of TMP_TABLE_SHARE are
+ used for participation in the list of temporary tables.
+*/
+
+struct All_tmp_table_shares
+{
+ static inline TMP_TABLE_SHARE **next_ptr(TMP_TABLE_SHARE *l)
+ {
+ return &l->tmp_next;
+ }
+ static inline TMP_TABLE_SHARE ***prev_ptr(TMP_TABLE_SHARE *l)
+ {
+ return &l->tmp_prev;
+ }
+};
+
+/* Also used in rpl_rli.h. */
+typedef I_P_List <TMP_TABLE_SHARE, All_tmp_table_shares> All_tmp_tables_list;
/**
Class that holds information about tables which were opened and locked
@@ -1293,15 +1348,20 @@ public:
base tables that were opened with @see open_tables().
*/
TABLE *open_tables;
+
/**
- List of temporary tables used by this thread. Contains user-level
- temporary tables, created with CREATE TEMPORARY TABLE, and
- internal temporary tables, created, e.g., to resolve a SELECT,
+ A list of temporary tables used by this thread. This includes
+ user-level temporary tables, created with CREATE TEMPORARY TABLE,
+ and internal temporary tables, created, e.g., to resolve a SELECT,
or for an intermediate table used in ALTER.
- XXX Why are internal temporary tables added to this list?
*/
- TABLE *temporary_tables;
+ All_tmp_tables_list *temporary_tables;
+
+ /*
+ Derived tables.
+ */
TABLE *derived_tables;
+
/*
During a MySQL session, one can lock tables in two modes: automatic
or manual. In automatic mode all necessary tables are locked just before
@@ -1379,8 +1439,11 @@ public:
void reset_open_tables_state(THD *thd)
{
- open_tables= temporary_tables= derived_tables= 0;
- extra_lock= lock= 0;
+ open_tables= 0;
+ temporary_tables= 0;
+ derived_tables= 0;
+ extra_lock= 0;
+ lock= 0;
locked_tables_mode= LTM_NONE;
state_flags= 0U;
m_reprepare_observer= NULL;
@@ -3544,13 +3607,13 @@ public:
*/
DBUG_PRINT("debug",
("temporary_tables: %s, in_sub_stmt: %s, system_thread: %s",
- YESNO(temporary_tables), YESNO(in_sub_stmt),
+ YESNO(has_thd_temporary_tables()), YESNO(in_sub_stmt),
show_system_thread(system_thread)));
if (in_sub_stmt == 0)
{
if (wsrep_binlog_format() == BINLOG_FORMAT_ROW)
set_current_stmt_binlog_format_row();
- else if (temporary_tables == NULL)
+ else if (!has_thd_temporary_tables())
set_current_stmt_binlog_format_stmt();
}
DBUG_VOID_RETURN;
@@ -3950,10 +4013,6 @@ private:
LEX_STRING invoker_user;
LEX_STRING invoker_host;
- /* Protect against add/delete of temporary tables in parallel replication */
- void rgi_lock_temporary_tables();
- void rgi_unlock_temporary_tables();
- bool rgi_have_temporary_tables();
public:
/*
Flag, mutex and condition for a thread to wait for a signal from another
@@ -3971,26 +4030,85 @@ public:
*/
rpl_gtid last_commit_gtid;
- inline void lock_temporary_tables()
+ LF_PINS *tdc_hash_pins;
+ LF_PINS *xid_hash_pins;
+ bool fix_xid_hash_pins();
+
+/* Members related to temporary tables. */
+public:
+ bool has_thd_temporary_tables();
+
+ TABLE *create_and_open_tmp_table(handlerton *hton,
+ LEX_CUSTRING *frm,
+ const char *path,
+ const char *db,
+ const char *table_name,
+ bool open_in_engine);
+
+ TABLE *find_temporary_table(const char *db, const char *table_name);
+ TABLE *find_temporary_table(const TABLE_LIST *tl);
+
+ TMP_TABLE_SHARE *find_tmp_table_share_w_base_key(const char *key,
+ uint key_length);
+ TMP_TABLE_SHARE *find_tmp_table_share(const char *db,
+ const char *table_name);
+ TMP_TABLE_SHARE *find_tmp_table_share(const TABLE_LIST *tl);
+ TMP_TABLE_SHARE *find_tmp_table_share(const char *key, uint key_length);
+
+ bool open_temporary_table(TABLE_LIST *tl);
+ bool open_temporary_tables(TABLE_LIST *tl);
+
+ bool close_temporary_tables();
+ bool rename_temporary_table(TABLE *table, const char *db,
+ const char *table_name);
+ bool drop_temporary_table(TABLE *table, bool *is_trans, bool delete_table);
+ bool rm_temporary_table(handlerton *hton, const char *path);
+ void mark_tmp_tables_as_free_for_reuse();
+ void mark_tmp_table_as_free_for_reuse(TABLE *table);
+
+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);
+ TMP_TABLE_SHARE *create_temporary_table(handlerton *hton, LEX_CUSTRING *frm,
+ const char *path, const char *db,
+ const char *table_name);
+ TABLE *find_temporary_table(const char *key, uint key_length,
+ Temporary_table_state state);
+ TABLE *open_temporary_table(TMP_TABLE_SHARE *share, const char *alias,
+ bool open_in_engine);
+ bool find_and_use_tmp_table(const TABLE_LIST *tl, TABLE **out_table);
+ bool use_temporary_table(TABLE *table, TABLE **out_table);
+ void close_temporary_table(TABLE *table);
+ bool log_events_and_free_tmp_shares();
+ void free_tmp_table_share(TMP_TABLE_SHARE *share, bool delete_table);
+ void free_temporary_table(TABLE *table);
+ bool lock_temporary_tables();
+ void unlock_temporary_tables();
+
+ inline uint tmpkeyval(TMP_TABLE_SHARE *share)
{
- if (rgi_slave)
- rgi_lock_temporary_tables();
+ return uint4korr(share->table_cache_key.str +
+ share->table_cache_key.length - 4);
}
- inline void unlock_temporary_tables()
- {
- if (rgi_slave)
- rgi_unlock_temporary_tables();
- }
- inline bool have_temporary_tables()
+
+ inline TMP_TABLE_SHARE *tmp_table_share(TABLE *table)
{
- return (temporary_tables ||
- (rgi_slave && rgi_have_temporary_tables()));
+ DBUG_ASSERT(table->s->tmp_table);
+ return static_cast<TMP_TABLE_SHARE *>(table->s);
}
- LF_PINS *tdc_hash_pins;
- LF_PINS *xid_hash_pins;
- bool fix_xid_hash_pins();
-
+public:
inline ulong wsrep_binlog_format() const
{
return WSREP_FORMAT(variables.binlog_format);
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 2ba67cb1b00..be835e45ec7 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2014, Oracle and/or its affiliates.
- Copyright (c) 2009, 2015, MariaDB
+ Copyright (c) 2009, 2016, MariaDB Corporation
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
@@ -886,7 +886,8 @@ mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent)
{
LEX_STRING db_name= { table->db, table->db_length };
LEX_STRING table_name= { table->table_name, table->table_name_length };
- if (table->open_type == OT_BASE_ONLY || !find_temporary_table(thd, table))
+ if (table->open_type == OT_BASE_ONLY ||
+ !thd->find_temporary_table(table))
(void) delete_statistics_for_table(thd, &db_name, &table_name);
}
}
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index e8ade81062b..95417c73c74 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2001, 2015, Oracle and/or its affiliates.
- Copyright (c) 2011, 2015, MariaDB
+ Copyright (c) 2011, 2016, MariaDB Corporation
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
@@ -178,9 +178,8 @@ static void mysql_ha_close_table(SQL_HANDLER *handler)
{
/* Must be a temporary table */
table->file->ha_index_or_rnd_end();
- table->query_id= thd->query_id;
table->open_by_handler= 0;
- mark_tmp_table_for_reuse(table);
+ thd->mark_tmp_table_as_free_for_reuse(table);
}
my_free(handler->lock);
handler->init();
@@ -294,7 +293,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen)
open_ltable() or open_table() because we would like to be able
to open a temporary table.
*/
- error= (open_temporary_tables(thd, tables) ||
+ error= (thd->open_temporary_tables(tables) ||
open_tables(thd, &tables, &counter, 0));
if (error)
@@ -389,8 +388,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen)
/*
Assert that the above check prevents opening of views and merge tables.
For temporary tables, TABLE::next can be set even if only one table
- was opened for HANDLER as it is used to link them together
- (see thd->temporary_tables).
+ was opened for HANDLER as it is used to link them together.
*/
DBUG_ASSERT(sql_handler->table->next == NULL ||
sql_handler->table->s->tmp_table);
@@ -1195,10 +1193,10 @@ void mysql_ha_set_explicit_lock_duration(THD *thd)
Remove temporary tables from the HANDLER's hash table. The reason
for having a separate function, rather than calling
mysql_ha_rm_tables() is that it is not always feasible (e.g. in
- close_temporary_tables) to obtain a TABLE_LIST containing the
+ THD::close_temporary_tables) to obtain a TABLE_LIST containing the
temporary tables.
- @See close_temporary_tables
+ @See THD::close_temporary_tables()
@param thd Thread identifier.
*/
void mysql_ha_rm_temporary_tables(THD *thd)
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 9f63216af88..13ff5a74b0b 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -4078,7 +4078,12 @@ static TABLE *create_table_from_items(THD *thd,
}
else
{
- if (open_temporary_table(thd, create_table))
+ /*
+ The pointer to the newly created temporary table has been stored in
+ table->create_info.
+ */
+ create_table->table= create_info->table;
+ if (!create_table->table)
{
/*
This shouldn't happen as creation of temporary table should make
@@ -4087,7 +4092,6 @@ static TABLE *create_table_from_items(THD *thd,
*/
DBUG_ASSERT(0);
}
- DBUG_ASSERT(create_table->table == create_info->table);
}
}
else
@@ -4461,6 +4465,7 @@ void select_create::abort_result_set()
if (table)
{
bool tmp_table= table->s->tmp_table;
+
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
table->auto_increment_field_not_null= FALSE;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index a1883d2fc21..8b3d50e40e4 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2008, 2015, MariaDB
+ Copyright (c) 2008, 2016, MariaDB Corporation
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
@@ -23,7 +23,10 @@
// set_handler_table_locks,
// lock_global_read_lock,
// make_global_read_lock_block_commit
-#include "sql_base.h" // find_temporary_table
+#include "sql_base.h" // open_tables, open_and_lock_tables,
+ // lock_tables, unique_table,
+ // close_thread_tables, is_temporary_table
+ // table_cache.h
#include "sql_cache.h" // QUERY_CACHE_FLAGS_SIZE, query_cache_*
#include "sql_show.h" // mysqld_list_*, mysqld_show_*,
// calc_sum_of_all_status
@@ -418,7 +421,7 @@ static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables)
for (TABLE_LIST *table= tables; table; table= table->next_global)
{
DBUG_ASSERT(table->db && table->table_name);
- if (table->updating && !find_temporary_table(thd, table))
+ if (table->updating && !thd->find_tmp_table_share(table))
return 1;
}
return 0;
@@ -1967,7 +1970,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->set_query(fields, query_length);
general_log_print(thd, command, "%s %s", table_list.table_name, fields);
- if (open_temporary_tables(thd, &table_list))
+ if (thd->open_temporary_tables(&table_list))
break;
if (check_table_access(thd, SELECT_ACL, &table_list,
@@ -3264,7 +3267,7 @@ mysql_execute_command(THD *thd)
*/
if (sql_command_flags[lex->sql_command] & CF_PREOPEN_TMP_TABLES)
{
- if (open_temporary_tables(thd, all_tables))
+ if (thd->open_temporary_tables(all_tables))
goto error;
}
@@ -4066,7 +4069,7 @@ end_with_restore_list:
Temporary tables should be opened for SHOW CREATE TABLE, but not
for SHOW CREATE VIEW.
*/
- if (open_temporary_tables(thd, all_tables))
+ if (thd->open_temporary_tables(all_tables))
goto error;
/*
@@ -4274,7 +4277,8 @@ end_with_restore_list:
*/
if (first_table->lock_type != TL_WRITE_DELAYED)
{
- if ((res= open_temporary_tables(thd, all_tables)))
+ res= (thd->open_temporary_tables(all_tables)) ? TRUE : FALSE;
+ if (res)
break;
}
@@ -4586,7 +4590,7 @@ end_with_restore_list:
{
if (!lex->tmp_table() &&
(!thd->is_current_stmt_binlog_format_row() ||
- !find_temporary_table(thd, table)))
+ !thd->find_temporary_table(table)))
{
WSREP_TO_ISOLATION_BEGIN(NULL, NULL, all_tables);
break;
@@ -4739,7 +4743,7 @@ end_with_restore_list:
CF_PREOPEN_TMP_TABLES was set and the tables would be pre-opened
in a usual way, they would have been closed.
*/
- if (open_temporary_tables(thd, all_tables))
+ if (thd->open_temporary_tables(all_tables))
goto error;
if (lock_tables_precheck(thd, all_tables))
@@ -6780,7 +6784,7 @@ static bool check_show_access(THD *thd, TABLE_LIST *table)
/*
Open temporary tables to be able to detect them during privilege check.
*/
- if (open_temporary_tables(thd, dst_table))
+ if (thd->open_temporary_tables(dst_table))
return TRUE;
if (check_access(thd, SELECT_ACL, dst_table->db,
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
index 9e67a21e8f4..18f25ab7cf7 100644
--- a/sql/sql_partition_admin.cc
+++ b/sql/sql_partition_admin.cc
@@ -1,5 +1,6 @@
/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2014, SkySQL Ab.
+ Copyright (c) 2016, MariaDB Corporation
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
@@ -534,12 +535,9 @@ bool Sql_cmd_alter_table_exchange_partition::
#ifdef WITH_WSREP
if (WSREP_ON)
{
- /* Forward declaration */
- TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl);
-
if ((!thd->is_current_stmt_binlog_format_row() ||
/* TODO: Do we really need to check for temp tables in this case? */
- !find_temporary_table(thd, table_list)) &&
+ !thd->find_temporary_table(table_list)) &&
wsrep_to_isolation_begin(thd, table_list->db, table_list->table_name,
NULL))
{
@@ -783,11 +781,9 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd)
DBUG_RETURN(TRUE);
#ifdef WITH_WSREP
- /* Forward declaration */
- TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl);
-
- if (WSREP(thd) && (!thd->is_current_stmt_binlog_format_row() ||
- !find_temporary_table(thd, first_table)) &&
+ if (WSREP(thd) &&
+ (!thd->is_current_stmt_binlog_format_row() ||
+ !thd->find_temporary_table(first_table)) &&
wsrep_to_isolation_begin(
thd, first_table->db, first_table->table_name, NULL)
)
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 0c7e26c7b04..e8a7dce5771 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2002, 2015, Oracle and/or its affiliates.
- Copyright (c) 2008, 2015, MariaDB
+ Copyright (c) 2008, 2016, MariaDB
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
@@ -1259,7 +1259,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
*/
if (table_list->lock_type != TL_WRITE_DELAYED)
{
- if (open_temporary_tables(thd, table_list))
+ if (thd->open_temporary_tables(table_list))
goto error;
}
@@ -2028,7 +2028,7 @@ static bool mysql_test_create_view(Prepared_statement *stmt)
Since we can't pre-open temporary tables for SQLCOM_CREATE_VIEW,
(see mysql_create_view) we have to do it here instead.
*/
- if (open_temporary_tables(thd, tables))
+ if (thd->open_temporary_tables(tables))
goto err;
if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL,
@@ -2280,7 +2280,7 @@ static bool check_prepared_statement(Prepared_statement *stmt)
*/
if (sql_command_flags[sql_command] & CF_PREOPEN_TMP_TABLES)
{
- if (open_temporary_tables(thd, tables))
+ if (thd->open_temporary_tables(tables))
goto error;
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index ee968f173e1..923114ae0d4 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -4155,7 +4155,7 @@ fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys,
'only_view_structure()'.
*/
lex->sql_command= SQLCOM_SHOW_FIELDS;
- result= (open_temporary_tables(thd, table_list) ||
+ result= (thd->open_temporary_tables(table_list) ||
open_normal_and_derived_tables(thd, table_list,
(MYSQL_OPEN_IGNORE_FLUSH |
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
@@ -4218,6 +4218,7 @@ end:
all tables open within this Open_tables_state.
*/
thd->temporary_tables= NULL;
+
close_thread_tables(thd);
/*
Release metadata lock we might have acquired.
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 296953b3375..0be329e76c2 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -25,7 +25,7 @@
#include "sql_table.h"
#include "sql_parse.h" // test_if_data_home_dir
#include "sql_cache.h" // query_cache_*
-#include "sql_base.h" // open_table_uncached, lock_table_names
+#include "sql_base.h" // lock_table_names
#include "lock.h" // mysql_unlock_tables
#include "strfunc.h" // find_type2, find_set
#include "sql_truncate.h" // regenerate_locked_table
@@ -2030,7 +2030,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
LEX_STRING db_name= { table->db, table->db_length };
LEX_STRING table_name= { table->table_name, table->table_name_length };
if (table->open_type == OT_BASE_ONLY ||
- !find_temporary_table(thd, table))
+ !thd->find_temporary_table(table))
(void) delete_statistics_for_table(thd, &db_name, &table_name);
}
}
@@ -2283,23 +2283,17 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
*/
DBUG_ASSERT(!(thd->locked_tables_mode &&
table->open_type != OT_BASE_ONLY &&
- find_temporary_table(thd, table) &&
+ thd->find_temporary_table(table) &&
table->mdl_request.ticket != NULL));
- /*
- drop_temporary_table may return one of the following error codes:
- . 0 - a temporary table was successfully dropped.
- . 1 - a temporary table was not found.
- . -1 - a temporary table is used by an outer statement.
- */
if (table->open_type == OT_BASE_ONLY || !is_temporary_table(table))
error= 1;
else
{
table_creation_was_logged= table->table->s->table_creation_was_logged;
- if ((error= drop_temporary_table(thd, table->table, &is_trans)) == -1)
+ if (thd->drop_temporary_table(table->table, &is_trans, true))
{
- DBUG_ASSERT(thd->in_sub_stmt);
+ error= 1;
goto err;
}
table->table= 0;
@@ -4635,7 +4629,8 @@ err:
which was created.
@param[out] key_count Number of keys in table which was created.
- If one creates a temporary table, this is automatically opened
+ If one creates a temporary table, its is automatically opened and its
+ TABLE_SHARE is added to THD::all_temp_tables list.
Note that this function assumes that caller already have taken
exclusive metadata lock on table being created or used some other
@@ -4695,20 +4690,22 @@ int create_table_impl(THD *thd,
/* Check if table exists */
if (create_info->tmp_table())
{
- TABLE *tmp_table;
- if (find_and_use_temporary_table(thd, db, table_name, &tmp_table))
- goto err;
+ /*
+ If a table exists, it must have been pre-opened. Try looking for one
+ in-use in THD::all_temp_tables list of TABLE_SHAREs.
+ */
+ TABLE *tmp_table= thd->find_temporary_table(db, table_name);
+
if (tmp_table)
{
bool table_creation_was_logged= tmp_table->s->table_creation_was_logged;
if (options.or_replace())
{
- bool tmp;
/*
We are using CREATE OR REPLACE on an existing temporary table
Remove the old table so that we can re-create it.
*/
- if (drop_temporary_table(thd, tmp_table, &tmp))
+ if (thd->drop_temporary_table(tmp_table, NULL, true))
goto err;
}
else if (options.if_not_exists())
@@ -4847,17 +4844,12 @@ int create_table_impl(THD *thd,
create_info->table= 0;
if (!frm_only && create_info->tmp_table())
{
- /*
- Open a table (skipping table cache) and add it into
- THD::temporary_tables list.
- */
-
- TABLE *table= open_table_uncached(thd, create_info->db_type, frm, path,
- db, table_name, true, true);
+ TABLE *table= thd->create_and_open_tmp_table(create_info->db_type, frm,
+ path, db, table_name, true);
if (!table)
{
- (void) rm_temporary_table(create_info->db_type, path);
+ (void) thd->rm_temporary_table(create_info->db_type, path);
goto err;
}
@@ -7143,7 +7135,8 @@ static bool mysql_inplace_alter_table(THD *thd,
HA_EXTRA_NOT_USED,
NULL);
table_list->table= table= NULL;
- close_temporary_table(thd, altered_table, true, false);
+
+ thd->drop_temporary_table(altered_table, NULL, false);
/*
Replace the old .FRM with the new .FRM, but keep the old name for now.
@@ -7233,7 +7226,7 @@ static bool mysql_inplace_alter_table(THD *thd,
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
/* QQ; do something about metadata locks ? */
}
- close_temporary_table(thd, altered_table, true, false);
+ thd->drop_temporary_table(altered_table, NULL, false);
// Delete temporary .frm/.par
(void) quick_rm_table(thd, create_info->db_type, alter_ctx->new_db,
alter_ctx->tmp_name, FN_IS_TMP | NO_HA_TABLE);
@@ -8385,7 +8378,12 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
if (table->s->tmp_table != NO_TMP_TABLE)
{
- if (find_temporary_table(thd, alter_ctx.new_db, alter_ctx.new_name))
+ /*
+ Check whether a temporary table exists with same requested new name.
+ If such table exists, there must be a corresponding TABLE_SHARE in
+ THD::all_temp_tables list.
+ */
+ if (thd->find_tmp_table_share(alter_ctx.new_db, alter_ctx.new_name))
{
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alter_ctx.new_alias);
DBUG_RETURN(true);
@@ -8821,11 +8819,11 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
// We assume that the table is non-temporary.
DBUG_ASSERT(!table->s->tmp_table);
- if (!(altered_table= open_table_uncached(thd, new_db_type, &frm,
- alter_ctx.get_tmp_path(),
- alter_ctx.new_db,
- alter_ctx.tmp_name,
- true, false)))
+ if (!(altered_table=
+ thd->create_and_open_tmp_table(new_db_type, &frm,
+ alter_ctx.get_tmp_path(),
+ alter_ctx.new_db, alter_ctx.tmp_name,
+ false)))
goto err_new_table_cleanup;
/* Set markers for fields in TABLE object for altered table. */
@@ -8865,7 +8863,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
ha_alter_info.report_unsupported_error("LOCK=NONE/SHARED",
"LOCK=EXCLUSIVE");
- close_temporary_table(thd, altered_table, true, false);
+ thd->drop_temporary_table(altered_table, NULL, false);
goto err_new_table_cleanup;
}
break;
@@ -8876,7 +8874,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
Alter_info::ALTER_TABLE_LOCK_NONE)
{
ha_alter_info.report_unsupported_error("LOCK=NONE", "LOCK=SHARED");
- close_temporary_table(thd, altered_table, true, false);
+ thd->drop_temporary_table(altered_table, NULL, false);
goto err_new_table_cleanup;
}
break;
@@ -8890,7 +8888,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
ha_alter_info.report_unsupported_error("ALGORITHM=INPLACE",
"ALGORITHM=COPY");
- close_temporary_table(thd, altered_table, true, false);
+ thd->drop_temporary_table(altered_table, NULL, false);
goto err_new_table_cleanup;
}
// COPY with LOCK=NONE is not supported, no point in trying.
@@ -8898,7 +8896,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
Alter_info::ALTER_TABLE_LOCK_NONE)
{
ha_alter_info.report_unsupported_error("LOCK=NONE", "LOCK=SHARED");
- close_temporary_table(thd, altered_table, true, false);
+ thd->drop_temporary_table(altered_table, NULL, false);
goto err_new_table_cleanup;
}
// Otherwise use COPY
@@ -8906,7 +8904,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
break;
case HA_ALTER_ERROR:
default:
- close_temporary_table(thd, altered_table, true, false);
+ thd->drop_temporary_table(altered_table, NULL, false);
goto err_new_table_cleanup;
}
@@ -8925,7 +8923,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
else
{
- close_temporary_table(thd, altered_table, true, false);
+ thd->drop_temporary_table(altered_table, NULL, false);
}
}
@@ -8978,13 +8976,18 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (create_info->tmp_table())
{
- if (!open_table_uncached(thd, new_db_type, &frm,
- alter_ctx.get_tmp_path(),
- alter_ctx.new_db, alter_ctx.tmp_name,
- true, true))
+ TABLE *tmp_table=
+ thd->create_and_open_tmp_table(new_db_type, &frm,
+ alter_ctx.get_tmp_path(),
+ alter_ctx.new_db, alter_ctx.tmp_name,
+ true);
+ if (!tmp_table)
+ {
goto err_new_table_cleanup;
+ }
}
+
/* Open the table since we need to copy the data. */
if (table->s->tmp_table != NO_TMP_TABLE)
{
@@ -8992,18 +8995,24 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
tbl.init_one_table(alter_ctx.new_db, strlen(alter_ctx.new_db),
alter_ctx.tmp_name, strlen(alter_ctx.tmp_name),
alter_ctx.tmp_name, TL_READ_NO_INSERT);
- /* Table is in thd->temporary_tables */
- (void) open_temporary_table(thd, &tbl);
+ /*
+ Table can be found in the list of open tables in THD::all_temp_tables
+ list.
+ */
+ tbl.table= thd->find_temporary_table(&tbl);
new_table= tbl.table;
}
else
{
- /* table is a normal table: Create temporary table in same directory */
- /* Open our intermediate table. */
- new_table= open_table_uncached(thd, new_db_type, &frm,
- alter_ctx.get_tmp_path(),
- alter_ctx.new_db, alter_ctx.tmp_name,
- true, true);
+ /*
+ table is a normal table: Create temporary table in same directory.
+ Open our intermediate table.
+ */
+ new_table=
+ thd->create_and_open_tmp_table(new_db_type, &frm,
+ alter_ctx.get_tmp_path(),
+ alter_ctx.new_db, alter_ctx.tmp_name,
+ true);
}
if (!new_table)
goto err_new_table_cleanup;
@@ -9071,10 +9080,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
new_table->s->table_creation_was_logged=
table->s->table_creation_was_logged;
/* Remove link to old table and rename the new one */
- close_temporary_table(thd, table, true, true);
+ thd->drop_temporary_table(table, NULL, true);
/* Should pass the 'new_name' as we store table name in the cache */
- if (rename_temporary_table(thd, new_table,
- alter_ctx.new_db, alter_ctx.new_name))
+ if (thd->rename_temporary_table(new_table, alter_ctx.new_db,
+ alter_ctx.new_name))
goto err_new_table_cleanup;
/* We don't replicate alter table statement on temporary tables */
if (!thd->is_current_stmt_binlog_format_row() &&
@@ -9086,10 +9095,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
/*
Close the intermediate table that will be the new table, but do
- not delete it! Even altough MERGE tables do not have their children
- attached here it is safe to call close_temporary_table().
+ not delete it! Even though MERGE tables do not have their children
+ attached here it is safe to call THD::drop_temporary_table().
*/
- close_temporary_table(thd, new_table, true, false);
+ thd->drop_temporary_table(new_table, NULL, false);
new_table= NULL;
DEBUG_SYNC(thd, "alter_table_before_rename_result_table");
@@ -9231,8 +9240,7 @@ err_new_table_cleanup:
my_free(const_cast<uchar*>(frm.str));
if (new_table)
{
- /* close_temporary_table() frees the new_table pointer. */
- close_temporary_table(thd, new_table, true, true);
+ thd->drop_temporary_table(new_table, NULL, true);
}
else
(void) quick_rm_table(thd, new_db_type,
@@ -9732,7 +9740,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
/* Allow to open real tables only. */
table->required_type= FRMTYPE_TABLE;
- if (open_temporary_tables(thd, table) ||
+ if (thd->open_temporary_tables(table) ||
open_and_lock_tables(thd, table, FALSE, 0))
{
t= NULL;
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index 50d51dcc8cc..76586a9fbba 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -82,7 +82,7 @@ static my_bool print_cached_tables_callback(TDC_element *element,
TABLE *entry;
mysql_mutex_lock(&element->LOCK_table_share);
- TDC_element::All_share_tables_list::Iterator it(element->all_tables);
+ All_share_tables_list::Iterator it(element->all_tables);
while ((entry= it++))
{
THD *in_use= entry->in_use;
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 63093620805..5213c21e8a2 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -24,7 +24,7 @@
#include "sql_parse.h" // parse_sql
#include "parse_file.h"
#include "sp.h"
-#include "sql_base.h" // find_temporary_table
+#include "sql_base.h"
#include "sql_show.h" // append_definer, append_identifier
#include "sql_table.h" // build_table_filename,
// check_n_cut_mysql50_prefix
@@ -507,7 +507,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
DBUG_ASSERT(tables->next_global == 0);
/* We do not allow creation of triggers on temporary tables. */
- if (create && find_temporary_table(thd, tables))
+ if (create && thd->find_tmp_table_share(tables))
{
my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias);
goto end;
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index b66f678adfc..b33590637b9 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2004, 2013, Oracle and/or its affiliates.
- Copyright (c) 2011, 2015, MariaDB
+ Copyright (c) 2011, 2016, MariaDB Corporation
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
@@ -429,7 +429,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
lex->link_first_table_back(view, link_to_local);
view->open_type= OT_BASE_ONLY;
- if (open_temporary_tables(thd, lex->query_tables) ||
+ if (thd->open_temporary_tables(lex->query_tables) ||
open_and_lock_tables(thd, lex->query_tables, TRUE, 0))
{
view= lex->unlink_first_table(&link_to_local);
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 4bf202813f3..a722a1cd1c7 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2002, 2015, Oracle and/or its affiliates.
- Copyright (c) 2012, 2015, MariaDB
+ Copyright (c) 2012, 2016, MariaDB Corporation
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
@@ -477,7 +477,8 @@ static bool binlog_format_check(sys_var *self, THD *thd, set_var *var)
switching @@SESSION.binlog_format from MIXED to STATEMENT when there are
open temp tables and we are logging in row format.
*/
- if (thd->temporary_tables && var->type == OPT_SESSION &&
+ if (thd->has_thd_temporary_tables() &&
+ var->type == OPT_SESSION &&
var->save_result.ulonglong_value == BINLOG_FORMAT_STMT &&
((thd->variables.binlog_format == BINLOG_FORMAT_MIXED &&
thd->is_current_stmt_binlog_format_row()) ||
diff --git a/sql/table.cc b/sql/table.cc
index 6cbf2a4a917..13b6fbf9cce 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -3922,7 +3922,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush,
tdc->all_tables_refs++;
mysql_mutex_unlock(&tdc->LOCK_table_share);
- TDC_element::All_share_tables_list::Iterator tables_it(tdc->all_tables);
+ All_share_tables_list::Iterator tables_it(tdc->all_tables);
/*
In case of multiple searches running in parallel, avoid going
diff --git a/sql/table.h b/sql/table.h
index 81869f6754d..c207588a049 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -2,6 +2,7 @@
#define TABLE_INCLUDED
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
Copyright (c) 2009, 2014, SkySQL Ab.
+ Copyright (c) 2016, MariaDB Corporation
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
@@ -1012,7 +1013,7 @@ private:
One should use methods of I_P_List template instead.
*/
TABLE *share_all_next, **share_all_prev;
- friend struct TDC_element;
+ friend struct All_share_tables;
public:
@@ -1435,6 +1436,19 @@ struct TABLE_share
}
};
+struct All_share_tables
+{
+ static inline TABLE **next_ptr(TABLE *l)
+ {
+ return &l->share_all_next;
+ }
+ static inline TABLE ***prev_ptr(TABLE *l)
+ {
+ return &l->share_all_prev;
+ }
+};
+
+typedef I_P_List <TABLE, All_share_tables> All_share_tables_list;
enum enum_schema_table_state
{
@@ -2662,15 +2676,6 @@ inline bool is_infoschema_db(const char *name)
TYPELIB *typelib(MEM_ROOT *mem_root, List<String> &strings);
-/**
- return true if the table was created explicitly.
-*/
-inline bool is_user_table(TABLE * table)
-{
- const char *name= table->s->table_name.str;
- return strncmp(name, tmp_file_prefix, tmp_file_prefix_length);
-}
-
inline void mark_as_null_row(TABLE *table)
{
table->null_row=1;
diff --git a/sql/table_cache.cc b/sql/table_cache.cc
index c7e95b4df14..bfe51df5de1 100644
--- a/sql/table_cache.cc
+++ b/sql/table_cache.cc
@@ -965,7 +965,7 @@ void tdc_release_share(TABLE_SHARE *share)
static void kill_delayed_threads_for_table(TDC_element *element)
{
- TDC_element::All_share_tables_list::Iterator it(element->all_tables);
+ All_share_tables_list::Iterator it(element->all_tables);
TABLE *tab;
mysql_mutex_assert_owner(&element->LOCK_table_share);
@@ -1086,7 +1086,7 @@ bool tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
if (remove_type == TDC_RT_REMOVE_NOT_OWN ||
remove_type == TDC_RT_REMOVE_NOT_OWN_KEEP_SHARE)
{
- TDC_element::All_share_tables_list::Iterator it(element->all_tables);
+ All_share_tables_list::Iterator it(element->all_tables);
while ((table= it++))
{
my_refs++;
diff --git a/sql/table_cache.h b/sql/table_cache.h
index ceb7299b08a..c05baae1f15 100644
--- a/sql/table_cache.h
+++ b/sql/table_cache.h
@@ -27,9 +27,6 @@ struct TDC_element
TABLE_SHARE *share;
typedef I_P_List <TABLE, TABLE_share> TABLE_list;
- typedef I_P_List <TABLE, I_P_List_adapter<TABLE, &TABLE::share_all_next,
- &TABLE::share_all_prev> >
- All_share_tables_list;
/**
Protects ref_count, m_flush_tickets, all_tables, free_tables, flushed,
all_tables_refs.
diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc
new file mode 100644
index 00000000000..c23bbd4ff19
--- /dev/null
+++ b/sql/temporary_tables.cc
@@ -0,0 +1,1499 @@
+/*
+ Copyright (c) 2016 MariaDB Corporation
+
+ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+/**
+ All methods pertaining to temporary tables.
+*/
+
+#include "sql_acl.h" /* TMP_TABLE_ACLS */
+#include "sql_base.h" /* tdc_create_key */
+#include "lock.h" /* mysql_lock_remove */
+#include "log_event.h" /* Query_log_event */
+#include "sql_show.h" /* append_identifier */
+#include "sql_handler.h" /* mysql_ha_rm_temporary_tables */
+#include "rpl_rli.h" /* rpl_group_info */
+
+#define IS_USER_TABLE(A) ((A->tmp_table == TRANSACTIONAL_TMP_TABLE) || \
+ (A->tmp_table == NON_TRANSACTIONAL_TMP_TABLE))
+
+/**
+ Check whether temporary tables exist. The decision is made based on the
+ existence of TMP_TABLE_SHAREs in Open_tables_state::temporary_tables list.
+
+ @return false Temporary tables exist
+ true No temporary table exist
+*/
+bool THD::has_thd_temporary_tables()
+{
+ DBUG_ENTER("THD::has_thd_temporary_tables");
+ bool result= (temporary_tables && !temporary_tables->is_empty());
+ DBUG_RETURN(result);
+}
+
+
+/**
+ Create a temporary table, open it and return the TABLE handle.
+
+ @param hton [IN] Handlerton
+ @param frm [IN] Binary frm image
+ @param path [IN] File path (without extension)
+ @param db [IN] Schema name
+ @param table_name [IN] Table name
+ @param open_in_engine [IN] Whether open table in SE
+
+
+ @return Success A pointer to table object
+ Failure NULL
+*/
+TABLE *THD::create_and_open_tmp_table(handlerton *hton,
+ LEX_CUSTRING *frm,
+ const char *path,
+ const char *db,
+ const char *table_name,
+ bool open_in_engine)
+{
+ DBUG_ENTER("THD::create_and_open_tmp_table");
+
+ TMP_TABLE_SHARE *share;
+ TABLE *table= NULL;
+
+ if ((share= create_temporary_table(hton, frm, path, db, table_name)))
+ {
+ table= open_temporary_table(share, table_name, open_in_engine);
+
+ /*
+ Failed to open a temporary table instance. As we are not passing
+ the created TMP_TABLE_SHARE to the caller, we must remove it from
+ the list and free it here.
+ */
+ if (!table)
+ {
+ /* Remove the TABLE_SHARE from the list of temporary tables. */
+ temporary_tables->remove(share);
+
+ /* Free the TMP_TABLE_SHARE. */
+ free_tmp_table_share(share, false);
+ }
+ }
+
+ DBUG_RETURN(table);
+}
+
+
+/**
+ Check whether an open table with db/table name is in use.
+
+ @param db [IN] Database name
+ @param table_name [IN] Table name
+
+ @return Success Pointer to first used table instance.
+ Failure NULL
+*/
+TABLE *THD::find_temporary_table(const char *db,
+ const char *table_name)
+{
+ DBUG_ENTER("THD::find_temporary_table");
+
+ TABLE *table;
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length;
+ bool locked;
+
+ if (!has_temporary_tables())
+ {
+ DBUG_RETURN(NULL);
+ }
+
+ 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);
+ if (locked)
+ {
+ DBUG_ASSERT(m_tmp_tables_locked);
+ unlock_temporary_tables();
+ }
+
+ DBUG_RETURN(table);
+}
+
+
+/**
+ Check whether an open table specified in TABLE_LIST is in use.
+
+ @return tl [IN] TABLE_LIST
+
+ @return Success Pointer to first used table instance.
+ Failure NULL
+*/
+TABLE *THD::find_temporary_table(const TABLE_LIST *tl)
+{
+ 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());
+ DBUG_RETURN(table);
+}
+
+
+/**
+ Check whether a temporary table exists with the specified key.
+ The key, in this case, is not the usual key used for temporary tables.
+ It does not contain server_id & pseudo_thread_id. This function is
+ essentially used use to check whether there is any temporary table
+ which _shadows_ a base table.
+ (see: Query_cache::send_result_to_client())
+
+ @return Success A pointer to table share object
+ Failure NULL
+*/
+TMP_TABLE_SHARE *THD::find_tmp_table_share_w_base_key(const char *key,
+ uint key_length)
+{
+ DBUG_ENTER("THD::find_tmp_table_share_w_base_key");
+
+ TMP_TABLE_SHARE *share;
+ TMP_TABLE_SHARE *result= NULL;
+ bool locked;
+
+ if (!has_temporary_tables())
+ {
+ DBUG_RETURN(NULL);
+ }
+
+ locked= lock_temporary_tables();
+
+ All_tmp_tables_list::Iterator it(*temporary_tables);
+ while ((share= it++))
+ {
+ if ((share->table_cache_key.length - TMP_TABLE_KEY_EXTRA) == key_length
+ && !memcmp(share->table_cache_key.str, key, key_length))
+ {
+ result= share;
+ }
+ }
+
+ if (locked)
+ {
+ DBUG_ASSERT(m_tmp_tables_locked);
+ unlock_temporary_tables();
+ }
+
+ DBUG_RETURN(result);
+}
+
+
+/**
+ Lookup the TMP_TABLE_SHARE using the given db/table_name.The server_id and
+ pseudo_thread_id used to generate table definition key is taken from THD
+ (see create_tmp_table_def_key()). Return NULL is none found.
+
+ @return Success A pointer to table share object
+ Failure NULL
+*/
+TMP_TABLE_SHARE *THD::find_tmp_table_share(const char *db,
+ const char *table_name)
+{
+ DBUG_ENTER("THD::find_tmp_table_share");
+
+ TMP_TABLE_SHARE *share;
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length;
+
+ key_length= create_tmp_table_def_key(key, db, table_name);
+ share= find_tmp_table_share(key, key_length);
+
+ DBUG_RETURN(share);
+}
+
+
+/**
+ Lookup TMP_TABLE_SHARE using the specified TABLE_LIST element.
+ Return NULL is none found.
+
+ @param tl [IN] Table
+
+ @return Success A pointer to table share object
+ Failure NULL
+*/
+TMP_TABLE_SHARE *THD::find_tmp_table_share(const TABLE_LIST *tl)
+{
+ DBUG_ENTER("THD::find_tmp_table_share");
+ TMP_TABLE_SHARE *share= find_tmp_table_share(tl->get_db_name(),
+ tl->get_table_name());
+ DBUG_RETURN(share);
+}
+
+
+/**
+ Lookup TMP_TABLE_SHARE using the specified table definition key.
+ Return NULL is none found.
+
+ @return Success A pointer to table share object
+ Failure NULL
+*/
+TMP_TABLE_SHARE *THD::find_tmp_table_share(const char *key, uint key_length)
+{
+ DBUG_ENTER("THD::find_tmp_table_share");
+
+ TMP_TABLE_SHARE *share;
+ TMP_TABLE_SHARE *result= NULL;
+ bool locked;
+
+ if (!has_temporary_tables())
+ {
+ DBUG_RETURN(NULL);
+ }
+
+ locked= lock_temporary_tables();
+
+ All_tmp_tables_list::Iterator it(*temporary_tables);
+ while ((share= it++))
+ {
+ if (share->table_cache_key.length == key_length &&
+ !(memcmp(share->table_cache_key.str, key, key_length)))
+ {
+ result= share;
+ break;
+ }
+ }
+
+ if (locked)
+ {
+ DBUG_ASSERT(m_tmp_tables_locked);
+ unlock_temporary_tables();
+ }
+
+ DBUG_RETURN(result);
+}
+
+
+/**
+ Find a temporary table specified by TABLE_LIST instance in the open table
+ list and prepare its TABLE instance for use. If
+
+ This function tries to resolve this table in the list of temporary tables
+ of this thread. Temporary tables are thread-local and "shadow" base
+ tables with the same name.
+
+ @note In most cases one should use THD::open_tables() instead
+ of this call.
+
+ @note One should finalize process of opening temporary table for table
+ list element by calling open_and_process_table(). This function
+ is responsible for table version checking and handling of merge
+ tables.
+
+ @note We used to check global_read_lock before opening temporary tables.
+ However, that limitation was artificial and is removed now.
+
+ @param tl [IN] TABLE_LIST
+
+ @return Error status.
+ @retval false On success. If a temporary table exists
+ for the given key, tl->table is set.
+ @retval true On error. my_error() has been called.
+*/
+bool THD::open_temporary_table(TABLE_LIST *tl)
+{
+ DBUG_ENTER("THD::open_temporary_table");
+ DBUG_PRINT("enter", ("table: '%s'.'%s'", tl->db, tl->table_name));
+
+ TMP_TABLE_SHARE *share;
+ TABLE *table= NULL;
+
+ /*
+ Since temporary tables are not safe for parallel replication, lets
+ wait for the prior commits in case the table is found to be in use.
+ */
+ if (rgi_slave &&
+ rgi_slave->is_parallel_exec &&
+ find_temporary_table(tl) &&
+ wait_for_prior_commit())
+ DBUG_RETURN(true);
+
+ /*
+ Code in open_table() assumes that TABLE_LIST::table can be non-zero only
+ for pre-opened temporary tables.
+ */
+ DBUG_ASSERT(tl->table == NULL);
+
+ /*
+ This function should not be called for cases when derived or I_S
+ tables can be met since table list elements for such tables can
+ have invalid db or table name.
+ Instead THD::open_tables() should be used.
+ */
+ DBUG_ASSERT(!tl->derived && !tl->schema_table);
+
+ if (tl->open_type == OT_BASE_ONLY || !has_temporary_tables())
+ {
+ DBUG_PRINT("info", ("skip_temporary is set or no temporary tables"));
+ DBUG_RETURN(false);
+ }
+
+ /*
+ First check if there is a reusable open table available in the
+ open table list.
+ */
+ if (find_and_use_tmp_table(tl, &table))
+ {
+ DBUG_RETURN(true); /* Error */
+ }
+
+ /*
+ No reusable table was found. We will have to open a new instance.
+ */
+ if (!table && (share= find_tmp_table_share(tl)))
+ {
+ table= open_temporary_table(share, tl->get_table_name(), true);
+ }
+
+ if (!table)
+ {
+ if (tl->open_type == OT_TEMPORARY_ONLY &&
+ tl->open_strategy == TABLE_LIST::OPEN_NORMAL)
+ {
+ my_error(ER_NO_SUCH_TABLE, MYF(0), tl->db, tl->table_name);
+ DBUG_RETURN(true);
+ }
+ DBUG_RETURN(false);
+ }
+
+ /*
+ Temporary tables are not safe for parallel replication. They were
+ designed to be visible to one thread only, so have no table locking.
+ Thus there is no protection against two conflicting transactions
+ committing in parallel and things like that.
+
+ So for now, anything that uses temporary tables will be serialised
+ with anything before it, when using parallel replication.
+
+ TODO: We might be able to introduce a reference count or something
+ on temp tables, and have slave worker threads wait for it to reach
+ zero before being allowed to use the temp table. Might not be worth
+ it though, as statement-based replication using temporary tables is
+ in any case rather fragile.
+ */
+ if (rgi_slave &&
+ rgi_slave->is_parallel_exec &&
+ wait_for_prior_commit())
+ DBUG_RETURN(true);
+
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ if (tl->partition_names)
+ {
+ /* Partitioned temporary tables is not supported. */
+ DBUG_ASSERT(!table->part_info);
+ my_error(ER_PARTITION_CLAUSE_ON_NONPARTITIONED, MYF(0));
+ DBUG_RETURN(true);
+ }
+#endif
+
+ table->query_id= query_id;
+ thread_specific_used= true;
+
+ /* It is neither a derived table nor non-updatable view. */
+ tl->updatable= true;
+ tl->table= table;
+
+ table->init(this, tl);
+
+ DBUG_PRINT("info", ("Using temporary table"));
+ DBUG_RETURN(false);
+}
+
+
+/**
+ Pre-open temporary tables corresponding to table list elements.
+
+ @note One should finalize process of opening temporary tables
+ by calling open_tables(). This function is responsible
+ for table version checking and handling of merge tables.
+
+ @param tl [IN] TABLE_LIST
+
+ @return false On success. If a temporary table exists
+ for the given element, tl->table is set.
+ true On error. my_error() has been called.
+*/
+bool THD::open_temporary_tables(TABLE_LIST *tl)
+{
+ DBUG_ENTER("THD::open_temporary_tables");
+
+ TABLE_LIST *first_not_own= lex->first_not_own_table();
+
+ for (TABLE_LIST *table= tl; table && table != first_not_own;
+ table= table->next_global)
+ {
+ if (table->derived || table->schema_table)
+ {
+ /*
+ Derived and I_S tables will be handled by a later call to open_tables().
+ */
+ continue;
+ }
+
+ if (open_temporary_table(table))
+ {
+ DBUG_RETURN(true);
+ }
+ }
+
+ DBUG_RETURN(false);
+}
+
+
+/**
+ Close all temporary tables created by 'CREATE TEMPORARY TABLE' for thread
+ creates one DROP TEMPORARY TABLE binlog event for each pseudo-thread.
+
+ Temporary tables created in a sql slave is closed by
+ Relay_log_info::close_temporary_tables().
+
+ @return false Success
+ true Failure
+*/
+bool THD::close_temporary_tables()
+{
+ DBUG_ENTER("THD::close_temporary_tables");
+
+ TMP_TABLE_SHARE *share;
+ TABLE *table;
+
+ bool error= false;
+
+ if (!has_thd_temporary_tables())
+ {
+ if (temporary_tables)
+ {
+ my_free(temporary_tables);
+ temporary_tables= NULL;
+ }
+ DBUG_RETURN(false);
+ }
+
+ DBUG_ASSERT(!rgi_slave);
+
+ /*
+ Ensure we don't have open HANDLERs for tables we are about to close.
+ This is necessary when THD::close_temporary_tables() is called as
+ part of execution of BINLOG statement (e.g. for format description event).
+ */
+ mysql_ha_rm_temporary_tables(this);
+
+ /* Close all open temporary tables. */
+ All_tmp_tables_list::Iterator it(*temporary_tables);
+ while ((share= it++))
+ {
+ /* Traverse the table list. */
+ while ((table= share->all_tmp_tables.pop_front()))
+ {
+ free_temporary_table(table);
+ }
+ }
+
+ // Write DROP TEMPORARY TABLE query log events to binary log.
+ if (mysql_bin_log.is_open())
+ {
+ error= log_events_and_free_tmp_shares();
+ }
+ else
+ {
+ while ((share= temporary_tables->pop_front()))
+ {
+ free_tmp_table_share(share, true);
+ }
+ }
+
+ /* By now, there mustn't be any elements left in the list. */
+ DBUG_ASSERT(temporary_tables->is_empty());
+
+ my_free(temporary_tables);
+ temporary_tables= NULL;
+
+ DBUG_RETURN(error);
+}
+
+
+/**
+ Rename a temporary table.
+
+ @param table [IN] Table handle
+ @param db [IN] New schema name
+ @param table_name [IN] New table name
+
+ @return false Success
+ true Error
+*/
+bool THD::rename_temporary_table(TABLE *table,
+ const char *db,
+ const char *table_name)
+{
+ DBUG_ENTER("THD::rename_temporary_table");
+
+ char *key;
+ uint key_length;
+
+ TABLE_SHARE *share= table->s;
+
+ if (!(key= (char *) alloc_root(&share->mem_root, MAX_DBKEY_LENGTH)))
+ {
+ DBUG_RETURN(true);
+ }
+
+ /*
+ Temporary tables are renamed by simply changing their table definition key.
+ */
+ key_length= create_tmp_table_def_key(key, db, table_name);
+ share->set_table_cache_key(key, key_length);
+
+ DBUG_RETURN(false);
+}
+
+
+/**
+ Drop a temporary table.
+
+ Try to locate the table in the list of open temporary tables.
+ If the table is found:
+ - If the table is locked with LOCK TABLES or by prelocking,
+ unlock it and remove it from the list of locked tables
+ (THD::lock). Currently only transactional temporary tables
+ are locked.
+ - Close the temporary table, remove its .FRM.
+ - Remove the table share from the list of temporary table shares.
+
+ This function is used to drop user temporary tables, as well as
+ internal tables created in CREATE TEMPORARY TABLE ... SELECT
+ or ALTER TABLE.
+
+ @param table [IN] Temporary table to be deleted
+ @param is_trans [OUT] Is set to the type of the table:
+ transactional (e.g. innodb) as true or
+ non-transactional (e.g. myisam) as false.
+ @paral delete_table [IN] Whether to delete the table files?
+
+ @return false Table was dropped
+ true Error
+*/
+bool THD::drop_temporary_table(TABLE *table,
+ bool *is_trans,
+ bool delete_table)
+{
+ DBUG_ENTER("THD::drop_temporary_table");
+
+ TMP_TABLE_SHARE *share;
+ TABLE *tab;
+ bool result= false;
+ bool locked;
+
+ DBUG_ASSERT(table);
+ DBUG_PRINT("tmptable", ("Dropping table: '%s'.'%s'",
+ table->s->db.str, table->s->table_name.str));
+
+ locked= lock_temporary_tables();
+
+ share= tmp_table_share(table);
+
+ /* Table might be in use by some outer statement. */
+ All_share_tables_list::Iterator it(share->all_tmp_tables);
+ while ((tab= it++))
+ {
+ if (tab != table && tab->query_id != 0)
+ {
+ /* Found a table instance in use. This table cannot be be dropped. */
+ my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias.c_ptr());
+ result= true;
+ goto end;
+ }
+ }
+
+ if (is_trans)
+ *is_trans= table->file->has_transactions();
+
+ /*
+ Iterate over the list of open tables and close them.
+ */
+ while ((tab= share->all_tmp_tables.pop_front()))
+ {
+ free_temporary_table(tab);
+ }
+
+ DBUG_ASSERT(temporary_tables);
+
+ /* Remove the TABLE_SHARE from the list of temporary tables. */
+ temporary_tables->remove(share);
+
+ /* Free the TABLE_SHARE and/or delete the files. */
+ free_tmp_table_share(share, delete_table);
+
+end:
+ if (locked)
+ {
+ DBUG_ASSERT(m_tmp_tables_locked);
+ unlock_temporary_tables();
+ }
+
+ DBUG_RETURN(result);
+}
+
+
+/**
+ Delete the temporary table files.
+
+ @param base [IN] Handlerton for table to be deleted.
+ @param path [IN] Path to the table to be deleted (i.e. path
+ to its .frm without an extension).
+
+ @return false Success
+ true Error
+*/
+bool THD::rm_temporary_table(handlerton *base, const char *path)
+{
+ DBUG_ENTER("THD::rm_temporary_table");
+
+ bool error= false;
+ handler *file;
+ char frm_path[FN_REFLEN + 1];
+
+ strxnmov(frm_path, sizeof(frm_path) - 1, path, reg_ext, NullS);
+ if (mysql_file_delete(key_file_frm, frm_path, MYF(0)))
+ {
+ error= true;
+ }
+ file= get_new_handler((TABLE_SHARE*) 0, current_thd->mem_root, base);
+ if (file && file->ha_delete_table(path))
+ {
+ error= true;
+ sql_print_warning("Could not remove temporary table: '%s', error: %d",
+ path, my_errno);
+ }
+
+ delete file;
+ DBUG_RETURN(error);
+}
+
+
+/**
+ Mark all temporary tables which were used by the current statement or
+ sub-statement as free for reuse, but only if the query_id can be cleared.
+
+ @remark For temp tables associated with a open SQL HANDLER the query_id
+ is not reset until the HANDLER is closed.
+*/
+void THD::mark_tmp_tables_as_free_for_reuse()
+{
+ DBUG_ENTER("THD::mark_tmp_tables_as_free_for_reuse");
+
+ TMP_TABLE_SHARE *share;
+ TABLE *table;
+ bool locked;
+
+ if (query_id == 0)
+ {
+ /*
+ Thread has not executed any statement and has not used any
+ temporary tables.
+ */
+ DBUG_VOID_RETURN;
+ }
+
+ if (!has_temporary_tables())
+ {
+ DBUG_VOID_RETURN;
+ }
+
+ locked= lock_temporary_tables();
+
+ All_tmp_tables_list::Iterator it(*temporary_tables);
+ while ((share= it++))
+ {
+ All_share_tables_list::Iterator tables_it(share->all_tmp_tables);
+ while ((table= tables_it++))
+ {
+ if ((table->query_id == query_id) && !table->open_by_handler)
+ {
+ mark_tmp_table_as_free_for_reuse(table);
+ }
+ }
+ }
+
+ if (locked)
+ {
+ DBUG_ASSERT(m_tmp_tables_locked);
+ unlock_temporary_tables();
+ }
+
+ if (rgi_slave)
+ {
+ /*
+ Temporary tables are shared with other by sql execution threads.
+ As a safety measure, clear the pointer to the common area.
+ */
+ temporary_tables= NULL;
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Reset a single temporary table. Effectively this "closes" one temporary
+ table in a session.
+
+ @param table Temporary table
+
+ @return void
+*/
+void THD::mark_tmp_table_as_free_for_reuse(TABLE *table)
+{
+ DBUG_ENTER("THD::mark_tmp_table_as_free_for_reuse");
+
+ DBUG_ASSERT(table->s->tmp_table);
+
+ table->query_id= 0;
+ table->file->ha_reset();
+
+ /* Detach temporary MERGE children from temporary parent. */
+ DBUG_ASSERT(table->file);
+ table->file->extra(HA_EXTRA_DETACH_CHILDREN);
+
+ /*
+ Reset temporary table lock type to it's default value (TL_WRITE).
+
+ Statements such as INSERT INTO .. SELECT FROM tmp, CREATE TABLE
+ .. SELECT FROM tmp and UPDATE may under some circumstances modify
+ the lock type of the tables participating in the statement. This
+ isn't a problem for non-temporary tables since their lock type is
+ reset at every open, but the same does not occur for temporary
+ tables for historical reasons.
+
+ Furthermore, the lock type of temporary tables is not really that
+ important because they can only be used by one query at a time.
+ Nonetheless, it's safer from a maintenance point of view to reset
+ the lock type of this singleton TABLE object as to not cause problems
+ when the table is reused.
+
+ Even under LOCK TABLES mode its okay to reset the lock type as
+ LOCK TABLES is allowed (but ignored) for a temporary table.
+ */
+ table->reginfo.lock_type= TL_WRITE;
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ If its a replication slave, report whether slave temporary tables
+ exist (Relay_log_info::save_temporary_tables) or report about THD
+ temporary table (Open_tables_state::temporary_tables) otherwise.
+
+ @return false Temporary tables exist
+ true No temporary table exist
+*/
+inline bool THD::has_temporary_tables()
+{
+ DBUG_ENTER("THD::has_temporary_tables");
+ bool result= (rgi_slave
+ ? (rgi_slave->rli->save_temporary_tables &&
+ !rgi_slave->rli->save_temporary_tables->is_empty())
+ : (has_thd_temporary_tables()));
+ DBUG_RETURN(result);
+}
+
+
+/**
+ Create a table definition key.
+
+ @param key [OUT] Buffer for the key to be created (must
+ be of size MAX_DBKRY_LENGTH)
+ @param db [IN] Database name
+ @param table_name [IN] Table name
+
+ @return Key length.
+
+ @note
+ The table key is create from:
+ db + \0
+ table_name + \0
+
+ Additionally, we add the following to make each temporary table unique on
+ the slave.
+
+ 4 bytes of master thread id
+ 4 bytes of pseudo thread id
+*/
+uint THD::create_tmp_table_def_key(char *key, const char *db,
+ const char *table_name)
+{
+ DBUG_ENTER("THD::create_tmp_table_def_key");
+
+ uint key_length;
+
+ key_length= tdc_create_key(key, db, table_name);
+ int4store(key + key_length, variables.server_id);
+ int4store(key + key_length + 4, variables.pseudo_thread_id);
+ key_length += TMP_TABLE_KEY_EXTRA;
+
+ DBUG_RETURN(key_length);
+}
+
+
+/**
+ Create a temporary table.
+
+ @param hton [IN] Handlerton
+ @param frm [IN] Binary frm image
+ @param path [IN] File path (without extension)
+ @param db [IN] Schema name
+ @param table_name [IN] Table name
+
+ @return Success A pointer to table share object
+ Failure NULL
+*/
+TMP_TABLE_SHARE *THD::create_temporary_table(handlerton *hton,
+ LEX_CUSTRING *frm,
+ const char *path,
+ const char *db,
+ const char *table_name)
+{
+ DBUG_ENTER("THD::create_temporary_table");
+
+ TMP_TABLE_SHARE *share;
+ char key_cache[MAX_DBKEY_LENGTH];
+ char *saved_key_cache;
+ char *tmp_path;
+ uint key_length;
+ bool locked;
+ int res;
+
+ /* Temporary tables are not safe for parallel replication. */
+ if (rgi_slave &&
+ rgi_slave->is_parallel_exec &&
+ wait_for_prior_commit())
+ DBUG_RETURN(NULL);
+
+ /* Create the table definition key for the temporary table. */
+ key_length= create_tmp_table_def_key(key_cache, db, table_name);
+
+ if (!(share= (TMP_TABLE_SHARE *) my_malloc(sizeof(TMP_TABLE_SHARE) +
+ strlen(path) + 1 + key_length,
+ MYF(MY_WME))))
+ {
+ DBUG_RETURN(NULL); /* Out of memory */
+ }
+
+ tmp_path= (char *)(share + 1);
+ saved_key_cache= strmov(tmp_path, path) + 1;
+ memcpy(saved_key_cache, key_cache, key_length);
+
+ init_tmp_table_share(this, share, saved_key_cache, key_length,
+ strend(saved_key_cache) + 1, tmp_path);
+
+ share->db_plugin= ha_lock_engine(this, hton);
+
+ /*
+ Prefer using frm image over file. The image might not be available in
+ ALTER TABLE, when the discovering engine took over the ownership (see
+ TABLE::read_frm_image).
+ */
+ res= (frm->str)
+ ? share->init_from_binary_frm_image(this, false, frm->str, frm->length)
+ : open_table_def(this, share, GTS_TABLE | GTS_USE_DISCOVERY);
+
+ if (res)
+ {
+ /*
+ No need to lock share->mutex as this is not needed for temporary tables.
+ */
+ free_table_share(share);
+ my_free(share);
+ DBUG_RETURN(NULL);
+ }
+
+ share->m_psi= PSI_CALL_get_table_share(true, share);
+
+ locked= lock_temporary_tables();
+
+ /* Initialize the all_tmp_tables list. */
+ share->all_tmp_tables.empty();
+
+ /*
+ We need to alloc & initialize temporary_tables if this happens
+ to be the very first temporary table.
+ */
+ if (!temporary_tables)
+ {
+ if ((temporary_tables=
+ (All_tmp_tables_list *) my_malloc(sizeof(All_tmp_tables_list),
+ MYF(MY_WME))))
+ {
+ temporary_tables->empty();
+ }
+ else
+ {
+ DBUG_RETURN(NULL); /* Out of memory */
+ }
+ }
+
+ /* Add share to the head of the temporary table share list. */
+ temporary_tables->push_front(share);
+
+ if (locked)
+ {
+ DBUG_ASSERT(m_tmp_tables_locked);
+ unlock_temporary_tables();
+ }
+
+ DBUG_RETURN(share);
+}
+
+
+/**
+ Find a table with the specified key.
+
+ @param key [IN] Key
+ @param key_length [IN] Key length
+ @param state [IN] Open table state to look for
+
+ @return Success Pointer to the table instance.
+ Failure NULL
+*/
+TABLE *THD::find_temporary_table(const char *key, uint key_length,
+ Temporary_table_state state)
+{
+ DBUG_ENTER("THD::find_temporary_table");
+
+ TMP_TABLE_SHARE *share;
+ TABLE *table;
+ TABLE *result= NULL;
+ bool locked;
+
+ locked= lock_temporary_tables();
+
+ All_tmp_tables_list::Iterator it(*temporary_tables);
+ while ((share= it++))
+ {
+ if (share->table_cache_key.length == key_length &&
+ !(memcmp(share->table_cache_key.str, key, key_length)))
+ {
+ /* A matching TMP_TABLE_SHARE is found. */
+ All_share_tables_list::Iterator tables_it(share->all_tmp_tables);
+
+ while ((table= tables_it++))
+ {
+ switch (state)
+ {
+ case TMP_TABLE_IN_USE:
+ if (table->query_id > 0)
+ {
+ result= table;
+ goto done;
+ }
+ break;
+ case TMP_TABLE_NOT_IN_USE:
+ if (table->query_id == 0)
+ {
+ result= table;
+ goto done;
+ }
+ break;
+ case TMP_TABLE_ANY:
+ {
+ result= table;
+ goto done;
+ }
+ break;
+ default: /* Invalid */
+ DBUG_ASSERT(0);
+ goto done;
+ }
+ }
+ }
+ }
+
+done:
+ if (locked)
+ {
+ DBUG_ASSERT(m_tmp_tables_locked);
+ unlock_temporary_tables();
+ }
+
+ DBUG_RETURN(result);
+}
+
+
+
+/**
+ Open a table from the specified TABLE_SHARE with the given alias.
+
+ @param share [IN] Table share
+ @param alias [IN] Table alias
+ @param open_in_engine [IN] Whether open table in SE
+
+ @return Success A pointer to table object
+ Failure NULL
+*/
+TABLE *THD::open_temporary_table(TMP_TABLE_SHARE *share,
+ const char *alias,
+ bool open_in_engine)
+{
+ DBUG_ENTER("THD::open_temporary_table");
+
+ TABLE *table;
+
+ if (!(table= (TABLE *) my_malloc(sizeof(TABLE), MYF(MY_WME))))
+ {
+ DBUG_RETURN(NULL); /* Out of memory */
+ }
+
+ if (open_table_from_share(this, share, alias,
+ (open_in_engine) ?
+ (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
+ HA_GET_INDEX) : 0,
+ (uint) (READ_KEYINFO | COMPUTE_TYPES |
+ EXTRA_RECORD),
+ ha_open_options,
+ table,
+ open_in_engine ? false : true))
+ {
+ my_free(table);
+ DBUG_RETURN(NULL);
+ }
+
+ table->reginfo.lock_type= TL_WRITE; /* Simulate locked */
+ table->grant.privilege= TMP_TABLE_ACLS;
+ share->tmp_table= (table->file->has_transactions() ?
+ TRANSACTIONAL_TMP_TABLE : NON_TRANSACTIONAL_TMP_TABLE);
+
+ table->pos_in_table_list= 0;
+ table->query_id= query_id;
+
+ /* Add table to the head of table list. */
+ share->all_tmp_tables.push_front(table);
+
+ /* Increment Slave_open_temp_table_definitions status variable count. */
+ if (rgi_slave)
+ {
+ thread_safe_increment32(&slave_open_temp_tables);
+ }
+
+ DBUG_PRINT("tmptable", ("Opened table: '%s'.'%s' 0x%lx", table->s->db.str,
+ table->s->table_name.str, (long) table));
+ DBUG_RETURN(table);
+}
+
+
+/**
+ Find a reusable table in the open table list using the specified TABLE_LIST.
+
+ @param tl [IN] Table list
+ @param out_table [OUT] Pointer to the requested TABLE object
+
+ @return Success false
+ Failure true
+*/
+bool THD::find_and_use_tmp_table(const TABLE_LIST *tl,
+ TABLE **out_table)
+{
+ DBUG_ENTER("THD::find_and_use_tmp_table");
+
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length;
+ bool result;
+
+ key_length= create_tmp_table_def_key(key, tl->get_db_name(),
+ tl->get_table_name());
+ result=
+ use_temporary_table(find_temporary_table(key, key_length,
+ TMP_TABLE_NOT_IN_USE),
+ out_table);
+
+ DBUG_RETURN(result);
+}
+
+/**
+ Mark table as in-use.
+
+ @param table [IN] Table to be marked in-use
+ @param out_table [OUT] Pointer to the specified table
+
+ @return false Success
+ true Error
+*/
+bool THD::use_temporary_table(TABLE *table, TABLE **out_table)
+{
+ DBUG_ENTER("THD::use_temporary_table");
+
+ *out_table= table;
+ if (!table)
+ DBUG_RETURN(false);
+
+ /*
+ Temporary tables are not safe for parallel replication. They were
+ designed to be visible to one thread only, so have no table locking.
+ Thus there is no protection against two conflicting transactions
+ committing in parallel and things like that.
+
+ So for now, anything that uses temporary tables will be serialised
+ with anything before it, when using parallel replication.
+
+ TODO: We might be able to introduce a reference count or something
+ on temp tables, and have slave worker threads wait for it to reach
+ zero before being allowed to use the temp table. Might not be worth
+ it though, as statement-based replication using temporary tables is
+ in any case rather fragile.
+ */
+ if (rgi_slave &&
+ rgi_slave->is_parallel_exec &&
+ wait_for_prior_commit())
+ DBUG_RETURN(true);
+
+ /*
+ We need to set the THD as it may be different in case of
+ parallel replication
+ */
+ if (table->in_use != this)
+ {
+ table->in_use= this;
+ }
+
+ DBUG_RETURN(false);
+}
+
+
+/**
+ Close a temporary table.
+
+ @param table [IN] Table handle
+
+ @return void
+*/
+void THD::close_temporary_table(TABLE *table)
+{
+ DBUG_ENTER("THD::close_temporary_table");
+
+ DBUG_PRINT("tmptable", ("closing table: '%s'.'%s' 0x%lx alias: '%s'",
+ table->s->db.str, table->s->table_name.str,
+ (long) table, table->alias.c_ptr()));
+
+ closefrm(table);
+ my_free(table);
+
+ if (rgi_slave)
+ {
+ /* Natural invariant of temporary_tables */
+ DBUG_ASSERT(slave_open_temp_tables || !temporary_tables);
+ /* Decrement Slave_open_temp_table_definitions status variable count. */
+ thread_safe_decrement32(&slave_open_temp_tables);
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Write query log events with "DROP TEMPORARY TABLES .." for each pseudo
+ thread to the binary log.
+
+ @return false Success
+ true Error
+*/
+bool THD::log_events_and_free_tmp_shares()
+{
+ DBUG_ENTER("THD::log_events_and_free_tmp_shares");
+
+ DBUG_ASSERT(!rgi_slave);
+
+ TMP_TABLE_SHARE *share;
+ TMP_TABLE_SHARE *sorted;
+ TMP_TABLE_SHARE *prev_sorted;
+ // Assume thd->variables.option_bits has OPTION_QUOTE_SHOW_CREATE.
+ bool was_quote_show= true;
+ bool error= false;
+ bool found_user_tables= false;
+ // Better add "IF EXISTS" in case a RESET MASTER has been done.
+ const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ";
+ char buf[FN_REFLEN];
+
+ String s_query(buf, sizeof(buf), system_charset_info);
+ s_query.copy(stub, sizeof(stub) - 1, system_charset_info);
+
+ /*
+ Insertion sort of temporary tables by pseudo_thread_id to build ordered
+ list of sublists of equal pseudo_thread_id.
+ */
+ All_tmp_tables_list::Iterator it_sorted(*temporary_tables);
+ All_tmp_tables_list::Iterator it_unsorted(*temporary_tables);
+ uint sorted_count= 0;
+ while((share= it_unsorted++))
+ {
+ if (IS_USER_TABLE(share))
+ {
+ prev_sorted= NULL;
+
+ if (!found_user_tables) found_user_tables= true;
+
+ for (uint i= 0; i < sorted_count; i ++)
+ {
+ sorted= it_sorted ++;
+
+ if (!IS_USER_TABLE(sorted) ||
+ (tmpkeyval(sorted) > tmpkeyval(share)))
+ {
+ /*
+ Insert this share before the current element in
+ the sorted part of the list.
+ */
+ temporary_tables->remove(share);
+
+ if (prev_sorted)
+ {
+ temporary_tables->insert_after(prev_sorted, share);
+ }
+ else
+ {
+ temporary_tables->push_front(share);
+ }
+ break;
+ }
+ prev_sorted= sorted;
+ }
+ it_sorted.rewind();
+ }
+ sorted_count ++;
+ }
+
+ /*
+ We always quote db & table names.
+ */
+ if (found_user_tables &&
+ !(was_quote_show= MY_TEST(variables.option_bits &
+ OPTION_QUOTE_SHOW_CREATE)))
+ {
+ variables.option_bits |= OPTION_QUOTE_SHOW_CREATE;
+ }
+
+ /*
+ Scan sorted temporary tables to generate sequence of DROP.
+ */
+ share= temporary_tables->pop_front();
+ while (share)
+ {
+ if (IS_USER_TABLE(share))
+ {
+ bool save_thread_specific_used= thread_specific_used;
+ my_thread_id save_pseudo_thread_id= variables.pseudo_thread_id;
+ char db_buf[FN_REFLEN];
+ String db(db_buf, sizeof(db_buf), system_charset_info);
+
+ /*
+ Set pseudo_thread_id to be that of the processed table.
+ */
+ variables.pseudo_thread_id= tmpkeyval(share);
+
+ db.copy(share->db.str, share->db.length, system_charset_info);
+ /*
+ Reset s_query() if changed by previous loop.
+ */
+ s_query.length(sizeof(stub) - 1);
+
+ /*
+ Loop forward through all tables that belong to a common database
+ within the sublist of common pseudo_thread_id to create single
+ DROP query.
+ */
+ for (;
+ share && IS_USER_TABLE(share) &&
+ tmpkeyval(share) == variables.pseudo_thread_id &&
+ share->db.length == db.length() &&
+ memcmp(share->db.str, db.ptr(), db.length()) == 0;
+ /* Get the next TABLE_SHARE in the list. */
+ share= temporary_tables->pop_front())
+ {
+ /*
+ We are going to add ` around the table names and possible more
+ due to special characters.
+ */
+ append_identifier(this, &s_query, share->table_name.str,
+ share->table_name.length);
+ s_query.append(',');
+ rm_temporary_table(share->db_type(), share->path.str);
+ free_table_share(share);
+ my_free(share);
+ }
+
+ clear_error();
+ CHARSET_INFO *cs_save= variables.character_set_client;
+ variables.character_set_client= system_charset_info;
+ thread_specific_used= true;
+
+ Query_log_event qinfo(this, s_query.ptr(),
+ s_query.length() - 1 /* to remove trailing ',' */,
+ false, true, false, 0);
+ qinfo.db= db.ptr();
+ qinfo.db_len= db.length();
+ variables.character_set_client= cs_save;
+
+ get_stmt_da()->set_overwrite_status(true);
+ if ((error= (mysql_bin_log.write(&qinfo) || error)))
+ {
+ /*
+ If we're here following THD::cleanup, thence the connection
+ has been closed already. So lets print a message to the
+ error log instead of pushing yet another error into the
+ stmt_da.
+
+ Also, we keep the error flag so that we propagate the error
+ up in the stack. This way, if we're the SQL thread we notice
+ that THD::close_tables failed. (Actually, the SQL
+ thread only calls THD::close_tables while applying
+ old Start_log_event_v3 events.)
+ */
+ sql_print_error("Failed to write the DROP statement for "
+ "temporary tables to binary log");
+ }
+
+ get_stmt_da()->set_overwrite_status(false);
+ variables.pseudo_thread_id= save_pseudo_thread_id;
+ thread_specific_used= save_thread_specific_used;
+ }
+ else
+ {
+ free_tmp_table_share(share, true);
+ /* Get the next TABLE_SHARE in the list. */
+ share= temporary_tables->pop_front();
+ }
+ }
+
+ if (!was_quote_show)
+ {
+ /*
+ Restore option.
+ */
+ variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE;
+ }
+
+ DBUG_RETURN(error);
+}
+
+
+/**
+ Delete the files and free the specified table share.
+
+ @param share [IN] TABLE_SHARE to free
+ @param delete_table [IN] Whether to delete the table files?
+
+ @return void
+*/
+void THD::free_tmp_table_share(TMP_TABLE_SHARE *share,
+ bool delete_table)
+{
+ DBUG_ENTER("THD::free_tmp_table_share");
+
+ if (delete_table)
+ {
+ rm_temporary_table(share->db_type(), share->path.str);
+ }
+ free_table_share(share);
+ my_free(share);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Free the specified table object.
+
+ @param table [IN] Table object to free.
+
+ @return void
+*/
+void THD::free_temporary_table(TABLE *table)
+{
+ DBUG_ENTER("THD::free_temporary_table");
+
+ /*
+ If LOCK TABLES list is not empty and contains this table, unlock the table
+ and remove the table from this list.
+ */
+ mysql_lock_remove(this, lock, table);
+
+ close_temporary_table(table);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ On replication slave, acquire the Relay_log_info's data_lock and use slave
+ temporary tables.
+
+ @return true Lock acquired
+ false Lock wasn't acquired
+*/
+bool THD::lock_temporary_tables()
+{
+ DBUG_ENTER("THD::lock_temporary_tables");
+
+ /* Do not proceed if a lock has already been taken. */
+ if (m_tmp_tables_locked)
+ {
+ DBUG_RETURN(false);
+ }
+
+ if (rgi_slave)
+ {
+ mysql_mutex_lock(&rgi_slave->rli->data_lock);
+ temporary_tables= rgi_slave->rli->save_temporary_tables;
+ m_tmp_tables_locked= true;
+ }
+
+ DBUG_RETURN(m_tmp_tables_locked);
+}
+
+
+/**
+ On replication slave, release the Relay_log_info::data_lock previously
+ acquired to use slave temporary tables.
+
+ @return void
+*/
+void THD::unlock_temporary_tables()
+{
+ DBUG_ENTER("THD::unlock_temporary_tables");
+
+ if (!m_tmp_tables_locked)
+ {
+ DBUG_VOID_RETURN;
+ }
+
+ if (rgi_slave)
+ {
+ rgi_slave->rli->save_temporary_tables= temporary_tables;
+ temporary_tables= NULL; /* Safety */
+ mysql_mutex_unlock(&rgi_slave->rli->data_lock);
+ m_tmp_tables_locked= false;
+ }
+
+ DBUG_VOID_RETURN;
+}
+
diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc
index cf1feb49f41..6086748b6d0 100644
--- a/sql/wsrep_applier.cc
+++ b/sql/wsrep_applier.cc
@@ -62,7 +62,6 @@ err:
#include "transaction.h" // trans_commit(), trans_rollback()
#include "rpl_rli.h" // class Relay_log_info;
-#include "sql_base.h" // close_temporary_table()
void wsrep_set_apply_format(THD* thd, Format_description_log_event* ev)
{
@@ -277,14 +276,11 @@ wsrep_cb_status_t wsrep_apply_cb(void* const ctx,
wsrep_dump_rbr_buf_with_header(thd, buf, buf_len);
}
- TABLE *tmp;
- while ((tmp = thd->temporary_tables))
+ if (thd->has_thd_temporary_tables())
{
- WSREP_DEBUG("Applier %lld, has temporary tables: %s.%s",
- (longlong) thd->thread_id,
- (tmp->s) ? tmp->s->db.str : "void",
- (tmp->s) ? tmp->s->table_name.str : "void");
- close_temporary_table(thd, tmp, 1, 1);
+ WSREP_DEBUG("Applier %lld has temporary tables. Closing them now..",
+ thd->thread_id);
+ thd->close_temporary_tables();
}
return rcode;
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index 54fb484bad0..9f7c3c9baa7 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -1085,8 +1085,6 @@ static bool wsrep_prepare_keys_for_isolation(THD* thd,
ka->keys= 0;
ka->keys_len= 0;
- extern TABLE* find_temporary_table(THD*, const TABLE_LIST*);
-
if (db || table)
{
TABLE_LIST tmp_table;
@@ -1098,7 +1096,7 @@ static bool wsrep_prepare_keys_for_isolation(THD* thd,
(table) ? table : "",
MDL_INTENTION_EXCLUSIVE, MDL_STATEMENT);
- if (!table || !find_temporary_table(thd, &tmp_table))
+ if (!table || !thd->find_temporary_table(&tmp_table))
{
if (!(ka->keys= (wsrep_key_t*)my_malloc(sizeof(wsrep_key_t), MYF(0))))
{
@@ -1126,7 +1124,7 @@ static bool wsrep_prepare_keys_for_isolation(THD* thd,
for (const TABLE_LIST* table= table_list; table; table= table->next_global)
{
- if (!find_temporary_table(thd, table))
+ if (!thd->find_temporary_table(table))
{
wsrep_key_t* tmp;
tmp= (wsrep_key_t*)my_realloc(
@@ -2443,26 +2441,13 @@ bool wsrep_create_like_table(THD* thd, TABLE_LIST* table,
TABLE_LIST* src_table,
HA_CREATE_INFO *create_info)
{
- TABLE *tmp_table;
- bool is_tmp_table= FALSE;
-
- for (tmp_table= thd->temporary_tables; tmp_table; tmp_table=tmp_table->next)
- {
- if (!strcmp(src_table->db, tmp_table->s->db.str) &&
- !strcmp(src_table->table_name, tmp_table->s->table_name.str))
- {
- is_tmp_table= TRUE;
- break;
- }
- }
if (create_info->tmp_table())
{
-
/* CREATE TEMPORARY TABLE LIKE must be skipped from replication */
WSREP_DEBUG("CREATE TEMPORARY TABLE LIKE... skipped replication\n %s",
thd->query());
}
- else if (!is_tmp_table)
+ else if (!(thd->find_temporary_table(src_table)))
{
/* this is straight CREATE TABLE LIKE... eith no tmp tables */
WSREP_TO_ISOLATION_BEGIN(table->db, table->table_name, NULL);
@@ -2477,7 +2462,7 @@ bool wsrep_create_like_table(THD* thd, TABLE_LIST* table,
bzero((void*) &tbl, sizeof(tbl));
tbl.db= src_table->db;
tbl.table_name= tbl.alias= src_table->table_name;
- tbl.table= tmp_table;
+ tbl.table= src_table->table;
char buf[2048];
String query(buf, sizeof(buf), system_charset_info);
query.length(0); // Have to zero it since constructor doesn't
diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc
index 3835c925745..36768a37973 100644
--- a/sql/wsrep_thd.cc
+++ b/sql/wsrep_thd.cc
@@ -360,13 +360,10 @@ static void wsrep_replication_process(THD *thd)
mysql_cond_broadcast(&COND_thread_count);
mysql_mutex_unlock(&LOCK_thread_count);
- TABLE *tmp;
- while ((tmp = thd->temporary_tables))
+ if(thd->has_thd_temporary_tables())
{
- WSREP_WARN("Applier %lld, has temporary tables at exit: %s.%s",
- (longlong) thd->thread_id,
- (tmp->s) ? tmp->s->db.str : "void",
- (tmp->s) ? tmp->s->table_name.str : "void");
+ WSREP_WARN("Applier %lld has temporary tables at exit.",
+ thd->thread_id);
}
wsrep_return_from_bf_mode(thd, &shadow);
DBUG_VOID_RETURN;
diff --git a/storage/spider/spd_direct_sql.cc b/storage/spider/spd_direct_sql.cc
index c0eb7806bb0..ad7bd54c69f 100644
--- a/storage/spider/spd_direct_sql.cc
+++ b/storage/spider/spd_direct_sql.cc
@@ -1640,7 +1640,7 @@ long long spider_direct_sql_body(
table_list.table_name = direct_sql->table_names[roop_count];
#endif
if (!(direct_sql->tables[roop_count] =
- find_temporary_table(thd, &table_list)))
+ thd->find_temporary_table(&table_list)))
{
#if MYSQL_VERSION_ID < 50500
#else