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で扱うために1、PDO::MYSQL_ATTR_INIT_COMMAND
にSET SESSION time_zone = 'Asia/Tokyo';
というような命令を入れていたのですが、ここで最後のセミコロンがトラブルのもととなりました。
なんと、PDO::MYSQL_ATTR_INIT_COMMAND
にセミコロン区切りで複数のSQL文を渡してしまうと、勝手に非バッファモードに切り替わってしまうというバグがPDOライブラリにあって、見事にそれを踏んでしまったのでした。
とりあえずセミコロンを外したことで一見落着はしたのですが、思わぬところでいくつも連鎖してトラブルになるものだなと感じました。
-
これを書くために調べていたら、公式にタイムゾーン切り替えが可能となっていたとのことです。 ↩