Bug #41348 INSERT INTO tbl SELECT * FROM temp_tbl overwrites locking type of temp table
| Submitted: | 10 Dec 2008 2:38 | Modified: | 29 Jan 2009 5:00 |
|---|---|---|---|
| Reporter: | Jonathon Coombes | Email Updates: | |
| Status: | Closed | Impact on me: | |
| Category: | MySQL Server: Locking | Severity: | S2 (Serious) |
| Version: | 5.1.30 | OS: | Any |
| Assigned to: | Davi Arnaut | CPU Architecture: | Any |
| Tags: | functions, locking, prepared statements, regression | ||
[10 Dec 2008 7:37]
Valeriy Kravchuk
Thank you for a problem report. Sorry, but I can not repeat the behaviour described:
C:\Program Files\MySQL\MySQL Server 5.0\bin>mysql -uroot -proot -P3310 test
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.1.30-enterprise-gpl-advanced MySQL Enterprise Server - Advance
d Edition (GPL)
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> DROP TABLE IF EXISTS trac;
Query OK, 0 rows affected (0.11 sec)
mysql> CREATE TABLE trac (
-> NODEID VARCHAR(20),
-> PARENTID VARCHAR(20),
-> try VARCHAR(20)
-> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.13 sec)
mysql> INSERT INTO trac VALUES ('a','top',NULL),('b','a',NULL),('c','b',NULL);
Query OK, 3 rows affected (0.03 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> DELIMITER $$
mysql> drop FUNCTION if exists try$$
Query OK, 0 rows affected (0.19 sec)
mysql> CREATE FUNCTION try() RETURNS VARCHAR(250)
-> BEGIN
-> return 'hhhhhhh' ;
-> END;
-> $$
Query OK, 0 rows affected (0.03 sec)
mysql> DELIMITER ;
mysql> DROP TEMPORARY TABLE IF EXISTS TMPRESULTGRP;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> DROP TEMPORARY TABLE IF EXISTS __b;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql>
mysql> CREATE TEMPORARY TABLE __b (
-> lvl INT,
-> nodeid VARCHAR(20),
-> parentid VARCHAR(20),
-> try varchar(20)
-> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.06 sec)
mysql> CREATE TEMPORARY TABLE TMPRESULTGRP LIKE __b;
Query OK, 0 rows affected (0.13 sec)
mysql>
mysql> SET @stmt := CONCAT('insert into __b select @lvl, tnt.nodeid, tnt.parenti
d, try()',
-> ' FROM trac tnt ');
Query OK, 0 rows affected (0.00 sec)
mysql> PREPARE stmt_sp_insert_b FROM @stmt;
Query OK, 0 rows affected (0.13 sec)
Statement prepared
mysql> EXECUTE stmt_sp_insert_b;
Query OK, 3 rows affected (0.09 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from __b;
+------+--------+----------+---------+
| lvl | nodeid | parentid | try |
+------+--------+----------+---------+
| NULL | a | top | hhhhhhh |
| NULL | b | a | hhhhhhh |
| NULL | c | b | hhhhhhh |
+------+--------+----------+---------+
3 rows in set (0.00 sec)
What I am doing wrong?
[10 Dec 2008 12:20]
Valeriy Kravchuk
Correct test case is:
DROP TABLE IF EXISTS trac;
CREATE TABLE trac (
NODEID VARCHAR(20),
PARENTID VARCHAR(20),
try VARCHAR(20)
) ENGINE=INNODB;
INSERT INTO trac VALUES ('a','top',NULL),('b','a',NULL),('c','b',NULL);
DELIMITER $$
drop FUNCTION if exists try$$
CREATE FUNCTION try() RETURNS VARCHAR(250)
BEGIN
return 'hhhhhhh' ;
END;
$$
DELIMITER ;
DROP TEMPORARY TABLE IF EXISTS TMPRESULTGRP;
DROP TEMPORARY TABLE IF EXISTS __b;
CREATE TEMPORARY TABLE __b (
lvl INT,
nodeid VARCHAR(20),
parentid VARCHAR(20),
try varchar(20)
) ENGINE=INNODB;
CREATE TEMPORARY TABLE TMPRESULTGRP LIKE __b;
SET @lvl := 1;
SET @stmt := CONCAT('insert into __b select @lvl, tnt.nodeid, tnt.parentid, try()',
' FROM trac tnt ');
PREPARE stmt_sp_insert_b FROM @stmt;
SET @stmt := CONCAT('INSERT INTO TMPRESULTGRP', ' SELECT * FROM __b');
PREPARE stmt_sp_insert_res_tbl FROM @stmt;
EXECUTE stmt_sp_insert_res_tbl;
DEALLOCATE PREPARE stmt_sp_insert_res_tbl;
EXECUTE stmt_sp_insert_b;
In 5.1.30 I've got:
C:\Program Files\MySQL\MySQL Server 5.0\bin>mysql -uroot -proot -P3310 test
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 15
Server version: 5.1.30-enterprise-gpl-advanced MySQL Enterprise Server - Advance
d Edition (GPL)
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> DROP TABLE IF EXISTS trac;
Query OK, 0 rows affected (0.05 sec)
mysql>
mysql> CREATE TABLE trac (
-> NODEID VARCHAR(20),
-> PARENTID VARCHAR(20),
-> try VARCHAR(20)
-> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.08 sec)
mysql>
mysql> INSERT INTO trac VALUES ('a','top',NULL),('b','a',NULL),('c','b',NULL);
Query OK, 3 rows affected (0.02 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql>
mysql> DELIMITER $$
mysql> drop FUNCTION if exists try$$
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE FUNCTION try() RETURNS VARCHAR(250)
-> BEGIN
-> return 'hhhhhhh' ;
-> END;
-> $$
Query OK, 0 rows affected (0.03 sec)
mysql>
mysql> DELIMITER ;
mysql>
mysql> DROP TEMPORARY TABLE IF EXISTS TMPRESULTGRP;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> DROP TEMPORARY TABLE IF EXISTS __b;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql>
mysql> CREATE TEMPORARY TABLE __b (
-> lvl INT,
-> nodeid VARCHAR(20),
-> parentid VARCHAR(20),
-> try varchar(20)
-> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.03 sec)
mysql> CREATE TEMPORARY TABLE TMPRESULTGRP LIKE __b;
Query OK, 0 rows affected (0.06 sec)
mysql>
mysql> SET @lvl := 1;
Query OK, 0 rows affected (0.00 sec)
mysql>
mysql> SET @stmt := CONCAT('insert into __b select @lvl, tnt.nodeid, tnt.parenti
d, try()',
-> ' FROM trac tnt ');
Query OK, 0 rows affected (0.00 sec)
mysql> PREPARE stmt_sp_insert_b FROM @stmt;
Query OK, 0 rows affected (0.00 sec)
Statement prepared
mysql>
mysql> SET @stmt := CONCAT('INSERT INTO TMPRESULTGRP', ' SELECT * FROM __b');
Query OK, 0 rows affected (0.00 sec)
mysql> PREPARE stmt_sp_insert_res_tbl FROM @stmt;
Query OK, 0 rows affected (0.00 sec)
Statement prepared
mysql> EXECUTE stmt_sp_insert_res_tbl;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> DEALLOCATE PREPARE stmt_sp_insert_res_tbl;
Query OK, 0 rows affected (0.00 sec)
mysql>
mysql> EXECUTE stmt_sp_insert_b;
ERROR 1099 (HY000): Table '__b' was locked with a READ lock and can't be updated
In 5.0.72 it works as expected. This is a regression bug.
[15 Dec 2008 19:55]
Davi Arnaut
Reduced test case:
DELIMITER |;
CREATE FUNCTION f1() RETURNS VARCHAR(250)
BEGIN
return 'hhhhhhh' ;
END|
DELIMITER ;|
CREATE TEMPORARY TABLE t1 (a VARCHAR(20));
CREATE TEMPORARY TABLE t2 LIKE t1;
PREPARE ps1 FROM "INSERT INTO t2 SELECT * FROM t1";
INSERT INTO t1 SELECT f1();
Initial analysis:
A statement prepare (ps1) can inadvertently overwrite the locking type of a temporary table to a read lock.
[16 Dec 2008 13:05]
Davi Arnaut
DELIMITER |;
CREATE FUNCTION f1() RETURNS VARCHAR(250)
BEGIN
return 'hhhhhhh' ;
END|
DELIMITER ;|
CREATE TEMPORARY TABLE t1 (a VARCHAR(20));
CREATE TABLE t2 LIKE t1;
INSERT INTO t2 SELECT * FROM t1;
INSERT INTO t1 SELECT f1();
[16 Dec 2008 16:34]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/61787 2739 Davi Arnaut 2008-12-16 Bug#41348: INSERT INTO tbl SELECT * FROM temp_tbl overwrites locking type of temp table The problem is that INSERT INTO .. SELECT FROM .. and CREATE TABLE .. SELECT FROM a temporary table could inadvertently overwrite the locking type of the temporary table. The lock type of temporary tables must always be a write lock. The solution is to ensure that the lock type of temporary tables is never overwritten and that its always a write lock.
[17 Dec 2008 11:29]
Davi Arnaut
Another manifestation of this problem can be triggered with a UPDATE statement:
CREATE FUNCTION f1() RETURNS INT
BEGIN
return 1 ;
END|
DELIMITER ;|
CREATE TEMPORARY TABLE t1 (a INT);
CREATE TEMPORARY TABLE t2 (a INT);
UPDATE t1,t2 SET t1.a = t2.a;
INSERT INTO t2 SELECT f1();
The general problem also affects MySQL 5.0.
[17 Dec 2008 11:38]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/61853 2739 Davi Arnaut 2008-12-17 Bug#41348: INSERT INTO tbl SELECT * FROM temp_tbl overwrites locking type of temp table The problem is that INSERT INTO .. SELECT FROM .. and CREATE TABLE .. SELECT FROM a temporary table could inadvertently overwrite the locking type of the temporary table. The lock type of temporary tables should be a write lock by default. The solution is to reset the lock type of temporary tables back to its default value after they are used in a statement.
[7 Jan 2009 12:12]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/62588 2728 Davi Arnaut 2009-01-07 Bug#41348: INSERT INTO tbl SELECT * FROM temp_tbl overwrites locking type of temp table The problem is that INSERT INTO .. SELECT FROM .. and CREATE TABLE .. SELECT FROM a temporary table could inadvertently overwrite the locking type of the temporary table. The lock type of temporary tables should be a write lock by default. The solution is to reset the lock type of temporary tables back to its default value after they are used in a statement.
[8 Jan 2009 18:30]
Davi Arnaut
Queued to 5.1-bugteam
[14 Jan 2009 9:33]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/63197 2748 He Zhenxing 2009-01-14 [merge] Auto merge
[15 Jan 2009 6:32]
Bugs System
Pushed into 5.1.31 (revid:joro@sun.com-20090115053147-tx1oapthnzgvs1ro) (version source revid:davi.arnaut@sun.com-20090113150631-y84w12o2zmh7j3qd) (merge vers: 5.1.31) (pib:6)
[19 Jan 2009 11:26]
Bugs System
Pushed into 5.1.31-ndb-6.2.17 (revid:tomas.ulin@sun.com-20090119095303-uwwvxiibtr38djii) (version source revid:tomas.ulin@sun.com-20090115073240-1wanl85vlvw2she1) (merge vers: 5.1.31-ndb-6.2.17) (pib:6)
[19 Jan 2009 13:04]
Bugs System
Pushed into 5.1.31-ndb-6.3.21 (revid:tomas.ulin@sun.com-20090119104956-guxz190n2kh31fxl) (version source revid:tomas.ulin@sun.com-20090119104956-guxz190n2kh31fxl) (merge vers: 5.1.31-ndb-6.3.21) (pib:6)
[19 Jan 2009 16:10]
Bugs System
Pushed into 5.1.31-ndb-6.4.1 (revid:tomas.ulin@sun.com-20090119144033-4aylstx5czzz88i5) (version source revid:tomas.ulin@sun.com-20090119144033-4aylstx5czzz88i5) (merge vers: 5.1.31-ndb-6.4.1) (pib:6)
[20 Jan 2009 18:56]
Bugs System
Pushed into 6.0.10-alpha (revid:joro@sun.com-20090119171328-2hemf2ndc1dxl0et) (version source revid:davi.arnaut@sun.com-20090108185343-ccylwxgk2rm6plku) (merge vers: 6.0.10-alpha) (pib:6)
[29 Jan 2009 5:00]
Paul DuBois
Noted in 5.1.31, 6.0.10 changelogs. INSERT INTO .. SELECT ... FROM and CREATE TABLE ... SELECT ... FROM a TEMPORARY table could inadvertently change the locking type of the temporary table from a write lock to a read lock, causing statement failure.
Portions of this website are copyright © 2001, 2002 The PHP Group
Page generated in 0.052 sec. using MySQL 8.4.7-u6-cloud
Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the
respective copyright holders.
It is not reviewed in advance
by Oracle and does not necessarily represent the opinion of
Oracle or any other party.
Description: Using certain prepared statements that have a function call have a READ lock that is causing problems. The prepared statement tested was INSERT INTO .. SELECT .. and the function can be as simple as a returning a string constant. The error shows as: mysql> EXECUTE stmt_sp_insert_b; ERROR 1099 (HY000): Table '__b' was locked with a READ lock and can't be updated Note that this has changed between 5.1.28 and 5.1.30.The statements work without the function, but otherwise you get the lock error. How to repeat: DROP TABLE IF EXISTS trac; CREATE TABLE trac ( NODEID VARCHAR(20), PARENTID VARCHAR(20), try VARCHAR(20) ) ENGINE=INNODB; INSERT INTO trac VALUES ('a','top',NULL),('b','a',NULL),('c','b',NULL); DELIMITER $$ drop FUNCTION if exists try; CREATE FUNCTION try() RETURNS VARCHAR(250) BEGIN return 'hhhhhhh' ; END;$$ DROP TEMPORARY TABLE IF EXISTS TMPRESULTGRP; DROP TEMPORARY TABLE IF EXISTS __b; CREATE TEMPORARY TABLE __b (lvl INT, nodeid VARCHAR(20), parentid VARCHAR(20),try varchar(20)) ENGINE=INNODB; CREATE TEMPORARY TABLE TMPRESULTGRP LIKE __b; -- Problem statement with function call SET @stmt := CONCAT('insert into __b select @lvl, tnt.nodeid, tnt.parentid, try()',' FROM trac tnt '); -- Working statement without function call -- SET @stmt := CONCAT('insert into __b select @lvl, tnt.nodeid, tnt.parentid, NULL',' FROM trac tnt '); PREPARE stmt_sp_insert_b FROM @stmt; SET @stmt := CONCAT('INSERT INTO TMPRESULTGRP', ' SELECT * FROM __b'); PREPARE stmt_sp_insert_res_tbl FROM @stmt; EXECUTE stmt_sp_insert_b; DEALLOCATE PREPARE stmt_sp_insert_b; DROP TEMPORARY TABLE __b;