PHP
MySQL
PDO
mariadb

PDOでLOBを入れようとしてMySQL server has gone away.

PDOExceptionが出た

  1. SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
  2. PHP側のエラーはError while sending QUERY packet.
  3. 場所は比較的大きなサイズのLOBを突っ込むクエリのexecute()の場所
  4. でもPHPのmemory_limit(=128MB)に収まる程度だし、max_execution_time(=30秒)に収まる程度
  5. MySQLのログには何も出てない

調べたこと

  • wait_timeoutの値が小さい?

    • 設定もいじってないし、mysql -uhoge -p -e "show variables like '%timeout%'"してもデフォルトの28800秒になっている。
    • execute()の直前に$pdo->query("SELECT 1")とか実行してみたら普通に実行できた。
  • max_allowed_packetの値が小さい?

    • 設定を変更して大きくしてある。mysql -uhoge -p -e "show variables like '%allowed%'"しても設定通りになっている。
  • クエリの前に接続を閉じてる?

    • 上でも書いたとおり直前に実行したクエリは通る。
  • LOBが大きいから?

    • 小さなLOBにするとエラーが出ない

:thinking: :thinking: :thinking: :thinking:

原因

setAttribute(PDO::ATTR_EMULATE_PREPARES, true);としていたことっぽい???
エミュレーションをオフにしたら治った。

クエリをダンプしてみた

$pdo = new PDO();
$pdo->beginTransaction();

$pdo->query("SELECT 1");
$stmt = $pdo->prepare("INSERT INTO foo(file) values (?)");
$stmt->bindValue(1,LOB,PDO::PARAM_LOB);
$stmt->execute();

$pdo->commit();
  • エミュレーションON、大きなLOB(25MB)
Connect   hoge@localhost as anonymous on po
Query     START TRANSACTION
Query     SELECT 1
Prepare   INSERT INTO foo (file) VALUES (?)
Execute   INSERT INTO foo (file) VALUES (LOB)

エミュレーションONなのに静的プレースホルダのような動きをしている。
QuitもCOMMITもしていない。Connectが消えているので、本当にserver has gone awayなことがわかる。

  • エミュレーションON、小さなLOB(1文字)
Connect   hoge@localhost as anonymous on po
Query     START TRANSACTION
Query     SELECT 1
Query     INSERT INTO foo (file) VALUES (LOB)
Query     COMMIT
Quit

正常な動作

  • エミュレーションOFF、大きなLOB(25MB)
Connect   hoge@localhost as anonymous on po
Query     START TRANSACTION
Prepare   INSERT INTO foo (file) VALUES (?)
Prepare   SELECT 1
Execute   SELECT 1
Execute   INSERT INTO foo (file) VALUES (LOB)
Query     COMMIT
Quit

正常な動作

まとめると

PDO::ATTR_EMULATE_PREPARESTRUEのときにLOBをinsertしようとするとconnectionが消える

:thinking: :thinking: :thinking: :thinking:

そんなこと聞いたこともないし、調べても出てこないし、原因はこれ以外のところ……?でもfalseにしたら治ったし……謎

環境

  • CentOS Linux release 7.4.1708 (Core)
  • PHP 7.1.15
  • mysql Ver 15.1 Distrib 10.2.13-MariaDB, for Linux (x86_64) using readline 5.1

結論

:angel:よくわからない:angel: