diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 075b4f84f2d..a1116a78bda 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -1767,4 +1767,25 @@ ref NULL rows 6 Extra Using where; Using index DROP TABLE foo, bar, foo2; +DROP TABLE IF EXISTS t1,t3,t2; +DROP FUNCTION IF EXISTS f1; +CREATE FUNCTION f1() RETURNS VARCHAR(250) +BEGIN +return 'hhhhhhh' ; +END| +CREATE TABLE t1 (a VARCHAR(20), b VARCHAR(20), c VARCHAR(20)) ENGINE=INNODB; +BEGIN WORK; +CREATE TEMPORARY TABLE t2 (a VARCHAR(20), b VARCHAR(20), c varchar(20)) ENGINE=INNODB; +CREATE TEMPORARY TABLE t3 LIKE t2; +INSERT INTO t1 VALUES ('a','b',NULL),('c','d',NULL),('e','f',NULL); +SET @stmt := CONCAT('INSERT INTO t2 SELECT tbl.a, tbl.b, f1()',' FROM t1 tbl'); +PREPARE stmt1 FROM @stmt; +SET @stmt := CONCAT('INSERT INTO t3', ' SELECT * FROM t2'); +PREPARE stmt3 FROM @stmt; +EXECUTE stmt1; +COMMIT; +DEALLOCATE PREPARE stmt1; +DEALLOCATE PREPARE stmt3; +DROP TABLE t1,t3,t2; +DROP FUNCTION f1; End of 5.1 tests diff --git a/mysql-test/r/temp_table.result b/mysql-test/r/temp_table.result index 6df09463d02..ba6b9f81a2d 100644 --- a/mysql-test/r/temp_table.result +++ b/mysql-test/r/temp_table.result @@ -194,4 +194,20 @@ DELETE FROM t1; SELECT * FROM t1; a b DROP TABLE t1; +DROP TABLE IF EXISTS t1,t2; +DROP FUNCTION IF EXISTS f1; +CREATE TEMPORARY TABLE t1 (a INT); +CREATE TEMPORARY TABLE t2 LIKE t1; +CREATE FUNCTION f1() RETURNS INT +BEGIN +return 1; +END| +INSERT INTO t2 SELECT * FROM t1; +INSERT INTO t1 SELECT f1(); +CREATE TABLE t3 SELECT * FROM t1; +INSERT INTO t1 SELECT f1(); +UPDATE t1,t2 SET t1.a = t2.a; +INSERT INTO t2 SELECT f1(); +DROP TABLE t1,t2,t3; +DROP FUNCTION f1; End of 5.1 tests diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index 1f9c08ac43b..5a2e115a98d 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -91,4 +91,45 @@ INSERT INTO foo2 SELECT * FROM foo; DROP TABLE foo, bar, foo2; +# +# Bug#41348: INSERT INTO tbl SELECT * FROM temp_tbl overwrites locking type of temp table +# + +--disable_warnings +DROP TABLE IF EXISTS t1,t3,t2; +DROP FUNCTION IF EXISTS f1; +--enable_warnings + +DELIMITER |; +CREATE FUNCTION f1() RETURNS VARCHAR(250) + BEGIN + return 'hhhhhhh' ; + END| +DELIMITER ;| + +CREATE TABLE t1 (a VARCHAR(20), b VARCHAR(20), c VARCHAR(20)) ENGINE=INNODB; + +BEGIN WORK; + +CREATE TEMPORARY TABLE t2 (a VARCHAR(20), b VARCHAR(20), c varchar(20)) ENGINE=INNODB; +CREATE TEMPORARY TABLE t3 LIKE t2; + +INSERT INTO t1 VALUES ('a','b',NULL),('c','d',NULL),('e','f',NULL); + +SET @stmt := CONCAT('INSERT INTO t2 SELECT tbl.a, tbl.b, f1()',' FROM t1 tbl'); +PREPARE stmt1 FROM @stmt; + +SET @stmt := CONCAT('INSERT INTO t3', ' SELECT * FROM t2'); +PREPARE stmt3 FROM @stmt; + +EXECUTE stmt1; + +COMMIT; + +DEALLOCATE PREPARE stmt1; +DEALLOCATE PREPARE stmt3; + +DROP TABLE t1,t3,t2; +DROP FUNCTION f1; + --echo End of 5.1 tests diff --git a/mysql-test/t/temp_table.test b/mysql-test/t/temp_table.test index 4ab8a982e63..2bfa4936c91 100644 --- a/mysql-test/t/temp_table.test +++ b/mysql-test/t/temp_table.test @@ -204,4 +204,35 @@ DELETE FROM t1; SELECT * FROM t1; DROP TABLE t1; +# +# Bug#41348: INSERT INTO tbl SELECT * FROM temp_tbl overwrites locking type of temp table +# + +--disable_warnings +DROP TABLE IF EXISTS t1,t2; +DROP FUNCTION IF EXISTS f1; +--enable_warnings + +CREATE TEMPORARY TABLE t1 (a INT); +CREATE TEMPORARY TABLE t2 LIKE t1; + +DELIMITER |; +CREATE FUNCTION f1() RETURNS INT + BEGIN + return 1; + END| +DELIMITER ;| + +INSERT INTO t2 SELECT * FROM t1; +INSERT INTO t1 SELECT f1(); + +CREATE TABLE t3 SELECT * FROM t1; +INSERT INTO t1 SELECT f1(); + +UPDATE t1,t2 SET t1.a = t2.a; +INSERT INTO t2 SELECT f1(); + +DROP TABLE t1,t2,t3; +DROP FUNCTION f1; + --echo End of 5.1 tests diff --git a/sql/sql_base.cc b/sql/sql_base.cc index ea664cd5091..6db9f1df0f2 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1111,6 +1111,27 @@ static void mark_temp_tables_as_free_for_reuse(THD *thd) */ if (table->child_l || table->parent) detach_merge_children(table, TRUE); + /* + 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; } } } @@ -4681,7 +4702,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) else if (tables->lock_type == TL_READ_DEFAULT) tables->table->reginfo.lock_type= read_lock_type_for_table(thd, tables->table); - else if (tables->table->s->tmp_table == NO_TMP_TABLE) + else tables->table->reginfo.lock_type= tables->lock_type; } tables->table->grant= tables->grant;