20
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

突然のUnbuffered Query…PDO+MySQLで入り込んだ迷宮

Posted at

CodeIgniterをバージョンアップしたところ、思わぬ形でPHPのバグを踏んでしまいました。

MySQLのバッファモード

トラブルに見舞われるまで知らなかったのですが、PHPからMySQLを使う場合には、「バッファモード」と「非バッファモード」があります(リファレンス)。

  • バッファモード…SQLを発行すると、自動的にPHP側へ全データを取ってくる。デフォルト設定
  • 非バッファモード…SQLを発行した段階ではまだデータを取ってこない。

一見すると、非バッファモードのほうが便利そうに見えるのですが、1つ大きな問題があります。非バッファモードの場合、一度投げたクエリを始末し切るまで次のクエリが投げられないのです。もちろん、それを意識した上でPDOなりMySQLiなりを直接叩くのであればまだ使いでもあるのですが、(非バッファモードに対応しない)フレームワーク経由でDB接続するとなると、どこでクエリを手仕舞いにするかなどユーザー側で制御できるものではありません。ということで、実質使い物になりません。

突然のエラー

CodeIgniter3で開発をしていたところ、ちょくちょくバージョンアップしていたところに置いていかれそうになったので、Composer経由でアップデートを行いました。ところが、アップデートしただけで、画面は白地のエラー画面となって、Cannot execute queries while other unbuffered queries are active.というエラーを食らってしまいました。

仮想マシンごと再起動してもエラーが続くので、さらに追いかけてみたところ、CodeIgniter 3.0.4から、MySQL 5.7のデフォルトモード変更に対応するために、接続時に自動実行するPDO::MYSQL_ATTR_INIT_COMMANDへ値を足すようになったことが判明しました。

さらに、自分の環境ではAWS RDS接続でもJSTで扱うために1PDO::MYSQL_ATTR_INIT_COMMANDSET SESSION time_zone = 'Asia/Tokyo';というような命令を入れていたのですが、ここで最後のセミコロンがトラブルのもととなりました。

なんと、PDO::MYSQL_ATTR_INIT_COMMANDにセミコロン区切りで複数のSQL文を渡してしまうと、勝手に非バッファモードに切り替わってしまうというバグがPDOライブラリにあって、見事にそれを踏んでしまったのでした。

とりあえずセミコロンを外したことで一見落着はしたのですが、思わぬところでいくつも連鎖してトラブルになるものだなと感じました。

  1. これを書くために調べていたら、公式にタイムゾーン切り替えが可能となっていたとのことです。

20
22
0

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
20
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?