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:
None 
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 2:38] Jonathon Coombes
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;
[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.