13
12

More than 5 years have passed since last update.

MySQL の PDO::exec で select すると以降のクエリがすべて失敗する

Last updated at Posted at 2014-09-10

PHP のバージョンなど。

PHP 5.6.0 / mysqlnd 5.0.11-dev

実行したコード。

<?php
$dsn = 'mysql:host=127.0.0.1;dbname=test;charset=utf8';
$pdo = new PDO($dsn, "test", "pass", array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
));

$pdo->exec("select 1 from dual");
$pdo->exec("select 2 from dual");

発生した例外。

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.'

このエラーには見覚えがあります、PDO::MYSQL_ATTR_USE_BUFFERED_QUERY = 0 なときに複数の結果セットを開くと発生します。

が、PDO::MYSQL_ATTR_USE_BUFFERED_QUERY = 1 などとしても解決しません。

<?php
$dsn = 'mysql:host=127.0.0.1;dbname=test;charset=utf8';
$pdo = new PDO($dsn, "test", "pass", array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => 1,
));

$pdo->exec("select 1 from dual");
$pdo->exec("select 2 from dual");

おそらく PDO::exec() した後に mysql_store_result()mysql_use_result() も呼ばれていないために結果セットが閉じられておらず、後続の SQL が実行できないのだと思います。

なお、このとき MySQL のエラーログには次が出力されていました。

[Warning] Aborted connection 36 to db: 'test' user: 'test' host: '127.0.0.1' (Got an error reading communication packets)

これは mysql_close せずにクライアントプロセスを殺すと発生します。つまり接続が正しく閉じられていないので mod_php や fpm だとリークしてそうです。 MySQL への接続はリークしていませんでした。

下記のように PDO の中身が libmysql の場合は MySQL のエラーログにはなにも記録されませんでした。

PHP 5.6.0 / libmysql 5.6.20

PDO::exec()select したのが間違いだと思うので、PDO_MySQL のバグなのかどうかは微妙。。。

13
12
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
12