Bug #13688 Lost connection with SELECT queries and DELETE in SP (WITH QUERY CACHE)
Submitted: 2 Oct 2005 11:43 Modified: 13 Nov 2005 8:27
Reporter: Valeriy Kravchuk Email Updates:
Status: Can't repeat Impact on me:
None 
Category:MySQL Server: Stored Routines Severity:S3 (Non-critical)
Version:5.0.13-rc, 5.0.14-BK OS:Linux (Linux, Windows)
Assigned to: Oleksandr Byelkin CPU Architecture:Any

[2 Oct 2005 11:43] Valeriy Kravchuk
Description:
This report is based on message http://lists.mysql.com/bugs/15639 posted by 	Giuseppe Maxia.

Without the query cache enabled, the following sequence of actions gives the expected results:

mysql> set global query_cache_size=0;
Query OK, 0 rows affected (0,01 sec)

mysql> create table t1 (
    ->       id1 int not null primary key,
    ->      c1 char(10)
    -> ) ENGINE = INNODB DEFAULT CHARSET = LATIN1;

Query OK, 0 rows affected (0,05 sec)

mysql> create table t2 (
    ->      id2 int not null primary key,
    ->       c2 char(10),
    ->      id1 int not null,
    ->      key (id1),
    ->      FOREIGN KEY (id1) REFERENCES t1 (id1)
    -> ) ENGINE = INNODB DEFAULT CHARSET = LATIN1;

Query OK, 0 rows affected (0,06 sec)

mysql> INSERT INTO t1 (id1, c1) values
    -> (1, 'aaa'), (2, 'bbb'), (3, 'ccc'),
    -> (4, 'ddd'), (5, 'eee');

Query OK, 5 rows affected (0,01 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> INSERT INTO t2 (id2,c2, id1) VALUES
    -> ((1001, 'nnnn', 1), (1002, 'oooo', 1),
    -> (1003, 'pppp', 2), (1004, 'qqqq', 2), (1005, 'rrrr', 2),
    -> (1006, 'ssss', 3), (1007, 'tttt', 3),
    -> (1008, 'uuuu', 4);

Query OK, 8 rows affected (0,01 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql> delimiter //

mysql>  create procedure delete_t1(which_id int)
    -> DETERMINISTIC MODIFIES SQL DATA
    -> BEGIN
    ->      SELECT 't2' AS 'table', COUNT(*) FROM t2;
    ->      DELETE FROM t2 WHERE id1 = which_id;
    ->      SELECT 't2' AS 'table', COUNT(*) FROM t2;
    ->       SELECT 't1' AS 'table', COUNT(*) FROM t1;
    ->      DELETE FROM t1 WHERE id1 = which_id;
    ->       SELECT 't1' AS 'table', COUNT(*) FROM t1;
    -> END //
Query OK, 0 rows affected (0,03 sec)

mysql> delimiter ;
mysql> call delete_t1(1);
+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t2    |        8 |
+-------+----------+
1 row in set (0,00 sec)

+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t2    |        6 |
+-------+----------+
1 row in set (0,04 sec)

+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t1    |        5 |
+-------+----------+
1 row in set (0,04 sec)

+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t1    |        4 |
+-------+----------+
1 row in set (0,09 sec)

Query OK, 0 rows affected (0,09 sec)

mysql> commit;
Query OK, 0 rows affected (0,00 sec)

mysql> call delete_t1(2);
+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t2    |        6 |
+-------+----------+
1 row in set (0,00 sec)

+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t2    |        3 |
+-------+----------+
1 row in set (0,00 sec)

+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t1    |        4 |
+-------+----------+
1 row in set (0,01 sec)

+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t1    |        3 |
+-------+----------+
1 row in set (0,04 sec)

Query OK, 0 rows affected (0,04 sec)

mysql> exit
Bye

But if query cache is enabled:

[openxs@Fedora 5.0]$ bin/mysql -uroot
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2 to server version: 5.0.14-rc

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> SET GLOBAL query_cache_size=16*1024*1024;
Query OK, 0 rows affected (0,00 sec)

mysql> drop table if exists t2;

Query OK, 0 rows affected (0,04 sec)

mysql> drop table if exists t1;

Query OK, 0 rows affected (0,02 sec)

mysql> create table t1 (
    ->       id1 int not null primary key,
    ->      c1 char(10)
    -> ) ENGINE = INNODB DEFAULT CHARSET = LATIN1;

Query OK, 0 rows affected (0,05 sec)

mysql> create table t2 (
    ->      id2 int not null primary key,
    ->       c2 char(10),
    ->      id1 int not null,
    ->      key (id1),
    ->      FOREIGN KEY (id1) REFERENCES t1 (id1)
    -> ) ENGINE = INNODB DEFAULT CHARSET = LATIN1;

Query OK, 0 rows affected (0,06 sec)

mysql> INSERT INTO t1 (id1, c1) values
    -> (1, 'aaa'), (2, 'bbb'), (3, 'ccc'),
    -> (4, 'ddd'), (5, 'eee');

Query OK, 5 rows affected (0,01 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> INSERT INTO t2 (id2,c2, id1) VALUES
    -> ((1001, 'nnnn', 1), (1002, 'oooo', 1),
    -> (1003, 'pppp', 2), (1004, 'qqqq', 2), (1005, 'rrrr', 2),
    -> (1006, 'ssss', 3), (1007, 'tttt', 3),
    -> (1008, 'uuuu', 4);

Query OK, 8 rows affected (0,01 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql> call delete_t1(1);
+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t2    |        8 |
+-------+----------+
1 row in set (0,01 sec)

+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t2    |        6 |
+-------+----------+
1 row in set (0,01 sec)

+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t1    |        5 |
+-------+----------+
1 row in set (0,01 sec)

+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t1    |        4 |
+-------+----------+
1 row in set (0,05 sec)

Query OK, 0 rows affected (0,05 sec)

mysql> commit;
Query OK, 0 rows affected (0,00 sec)

mysql> select * from t2;
+------+------+-----+
| id2  | c2   | id1 |
+------+------+-----+
| 1003 | pppp |   2 |
| 1004 | qqqq |   2 |
| 1005 | rrrr |   2 |
| 1006 | ssss |   3 |
| 1007 | tttt |   3 |
| 1008 | uuuu |   4 |
+------+------+-----+
6 rows in set (0,00 sec)

mysql> call delete_t1(2);
ERROR 2013 (HY000): Lost connection to MySQL server during query
mysql> connect;
Connection id:    3
Current database: test

mysql> call delete_t1(2);
+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t2    |        3 |
+-------+----------+
1 row in set (0,01 sec)

+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t2    |        3 |
+-------+----------+
1 row in set (0,01 sec)

ERROR 2013 (HY000): Lost connection to MySQL server during query

So, there is still some problem... ("Transactional InnoDB tables that have been changed are invalidated when a COMMIT is performed.")

mysql> connect;
Connection id:    4
Current database: test

mysql> set autocommit=0;
Query OK, 0 rows affected (0,00 sec)

mysql> call delete_t1(2);
+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t2    |        3 |
+-------+----------+
1 row in set (0,01 sec)

+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t2    |        3 |
+-------+----------+
1 row in set (0,01 sec)

+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t1    |        3 |
+-------+----------+
1 row in set (0,01 sec)

+-------+----------+
| table | COUNT(*) |
+-------+----------+
| t1    |        3 |
+-------+----------+
1 row in set (0,01 sec)

Query OK, 0 rows affected (0,01 sec)

The following BK changeset was used:

ChangeSet@1.2030, 2005-09-30 15:56:01+03:00, marko@hundin.mysql.fi

How to repeat:
create database if not exists test;
use test;

SET GLOBAL query_cache_size=16*1024*1024; ## <---

drop table if exists t2;
drop table if exists t1;

create table t1 (
     id1 int not null primary key,
     c1 char(10)
) ENGINE = INNODB DEFAULT CHARSET = LATIN1;

create table t2 (
     id2 int not null primary key,
     c2 char(10),
     id1 int not null,
     key (id1),
     FOREIGN KEY (id1) REFERENCES t1 (id1)
) ENGINE = INNODB DEFAULT CHARSET = LATIN1;

INSERT INTO t1 (id1, c1) values
(1, 'aaa'), (2, 'bbb'), (3, 'ccc'),
(4, 'ddd'), (5, 'eee');

INSERT INTO t2 (id2,c2, id1) VALUES
(1001, 'nnnn', 1), (1002, 'oooo', 1),
(1003, 'pppp', 2), (1004, 'qqqq', 2), (1005, 'rrrr', 2),
(1006, 'ssss', 3), (1007, 'tttt', 3),
(1008, 'uuuu', 4);

select * from t1;
select * from t2;

SELECT "TABLES READY -- CREATING STORED PROCEDURE" AS DIAGNOSTICS;

delimiter //

drop procedure if exists delete_t1 //

create procedure delete_t1(which_id int)
DETERMINISTIC MODIFIES SQL DATA
BEGIN
     SELECT 't2' AS 'table', COUNT(*) FROM t2;
     DELETE FROM t2 WHERE id1 = which_id;
     SELECT 't2' AS 'table', COUNT(*) FROM t2;
     SELECT 't1' AS 'table', COUNT(*) FROM t1;
     DELETE FROM t1 WHERE id1 = which_id;
     SELECT 't1' AS 'table', COUNT(*) FROM t1;
END //
delimiter ;

SELECT "STORED PROCEDURE READY -- NOW TESTING" AS DIAGNOSTICS;

select "following call (1) should succeed" AS DIAGNOSTICS;
call delete_t1(1);  -- this one will succeed
COMMIT;
select "previous call (1) should have succeeded" AS DIAGNOSTICS;
select "following call (2a) should fail" AS DIAGNOSTICS;
call delete_t1(2);  -- this one will fail
connect ; -- reconnect after failure
select "previous call (2a) should have failed" AS DIAGNOSTICS;
select "following call (2b) should succeed" AS DIAGNOSTICS;
set autocommit = 0;
call delete_t1(2);  -- this one will succeed
COMMIT;
select "previous call (2b) should have succeeded" AS DIAGNOSTICS;
# ---- CUT HERE

(2) run the script as
mysql --force -t < test.mysql

Suggested fix:
Something should be changed in query cache algorithms for SPs to work properly.
[2 Oct 2005 13:52] Heikki Tuuri
Valeriy,

does mysqld crash or print something to the .err log?

If yes, please post the gdb stack trace, as well as the .err log. This is something you should always add to a bug report if mysqld crashes. It will speed up the bug analysis.

Regards,

Heikki
[3 Oct 2005 6:42] jocelyn fournier
Hi,

FYI, I can reproduce the "lost connection" problem, but there is no info/error reported in the .err file.

  Jocelyn
[13 Nov 2005 8:27] Oleksandr Byelkin
Thank you for bugreport! I can't repeat it. I think it was packet number issue and it was fixed.
+ SET GLOBAL query_cache_size=16*1024*1024;
+ drop table if exists t2;
+ Warnings:
+ Note  1051    Unknown table 't2'
+ drop table if exists t1;
+ Warnings:
+ Note  1051    Unknown table 't1'
+ create table t1 (
+ id1 int not null primary key,
+ c1 char(10)
+ ) ENGINE = INNODB DEFAULT CHARSET = LATIN1;
+ create table t2 (
+ id2 int not null primary key,
+ c2 char(10),
+ id1 int not null,
+ key (id1),
+ FOREIGN KEY (id1) REFERENCES t1 (id1)
+ ) ENGINE = INNODB DEFAULT CHARSET = LATIN1;
+ INSERT INTO t1 (id1, c1) values
+ (1, 'aaa'), (2, 'bbb'), (3, 'ccc'),
+ (4, 'ddd'), (5, 'eee');
+ INSERT INTO t2 (id2,c2, id1) VALUES
+ (1001, 'nnnn', 1), (1002, 'oooo', 1),
+ (1003, 'pppp', 2), (1004, 'qqqq', 2), (1005, 'rrrr', 2),
+ (1006, 'ssss', 3), (1007, 'tttt', 3),
+ (1008, 'uuuu', 4);
+ select * from t1;
+ id1   c1
+ 1     aaa
+ 2     bbb
+ 3     ccc
+ 4     ddd
+ 5     eee
+ select * from t2;
+ id2   c2      id1
+ 1001  nnnn    1
+ 1002  oooo    1
+ 1003  pppp    2
+ 1004  qqqq    2
+ 1005  rrrr    2
+ 1006  ssss    3
+ 1007  tttt    3
+ 1008  uuuu    4
+ SELECT "TABLES READY -- CREATING STORED PROCEDURE" AS DIAGNOSTICS;
+ DIAGNOSTICS
+ TABLES READY -- CREATING STORED PROCEDURE
+ drop procedure if exists delete_t1 //
+ Warnings:
+ Note  1305    PROCEDURE delete_t1 does not exist
+ create procedure delete_t1(which_id int)
+ DETERMINISTIC MODIFIES SQL DATA
+ BEGIN
+ SELECT 't2' AS 'table', COUNT(*) FROM t2;
+ DELETE FROM t2 WHERE id1 = which_id;
+ SELECT 't2' AS 'table', COUNT(*) FROM t2;
+ SELECT 't1' AS 'table', COUNT(*) FROM t1;
+ DELETE FROM t1 WHERE id1 = which_id;
+ SELECT 't1' AS 'table', COUNT(*) FROM t1;
+ END //
+ SELECT "STORED PROCEDURE READY -- NOW TESTING" AS DIAGNOSTICS;
+ DIAGNOSTICS
+ STORED PROCEDURE READY -- NOW TESTING
+ select "following call (1) should succeed" AS DIAGNOSTICS;
+ DIAGNOSTICS
+ following call (1) should succeed
+ call delete_t1(1);
+ table COUNT(*)
+ t2    8
+ table COUNT(*)
+ t2    6
+ table COUNT(*)
+ t1    5
+ table COUNT(*)
+ t1    4
+ COMMIT;
+ select "previous call (1) should have succeeded" AS DIAGNOSTICS;
+ DIAGNOSTICS
+ previous call (1) should have succeeded
+ select "following call (2a) should fail" AS DIAGNOSTICS;
+ DIAGNOSTICS
+ following call (2a) should fail
+ call delete_t1(2);
+ table COUNT(*)
+ t2    6
+ table COUNT(*)
+ t2    3
+ table COUNT(*)
+ t1    4
+ table COUNT(*)
+ t1    3
+ select "previous call (2a) should have failed" AS DIAGNOSTICS;
+ DIAGNOSTICS
+ previous call (2a) should have failed
+ select "following call (2b) should succeed" AS DIAGNOSTICS;
+ DIAGNOSTICS
+ following call (2b) should succeed
+ set autocommit = 0;
+ call delete_t1(2);
+ table COUNT(*)
+ t2    3
+ table COUNT(*)
+ t2    3
+ table COUNT(*)
+ t1    3
+ table COUNT(*)
+ t1    3
+ COMMIT;
+ select "previous call (2b) should have succeeded" AS DIAGNOSTICS;
+ DIAGNOSTICS
+ previous call (2b) should have succeeded