本来はWordPressのデータベースにSQL Serverを使うことはできませんが、
WP Db Abstractionというプラグインを導入することで使えるようになります。Windows統合認証でシングルサインオンできるプラグインなどがあるのでWindows環境でWordPressを使うのはなかなか便利です。
問題発生
が、WP Statisticsというアクセス解析のプラグインを追加したところ、アクセス解析の結果表示部分に「Fatal error: Cannot access empty property」というエラーが表示されてうまく動きませんでした。
このエラーは以下の場所で発生しているのでWP Db Abstractionが原因ということで間違いないようです。
$this->last_result = $this->result->fetchAll(PDO::FETCH_OBJ);
エラーはPDOのfetchAllメソッドの中で発生しています。PDO::FETCH_OBJを指定した場合、fetchAllメソッドは戻り値としてカラム名をプロパティ名としたオブジェクトが返ってくるのですが、どうやらそのプロパティ名がおかしいため(おそらく空?)エラーになっているようです。
エラーになるときに実行されたSQLは以下のものでした。
SELECT SUM(visit) FROM wp_statistics_visit WHERE last_counter = '2014-12-02'
どうやら「SUM(visit)」という名前のプロパティを作ろうとして失敗しているようです。エラーはempty propertyなので、あるいはプロパティに使えない名前として明示的に空文字列にした挙句に失敗しているのかもしれません。
原因
WP Db Abstractionはなかなかきわどいことをしているプラグインで、WordPressのデータベース接続オブジェクトが入っている$wpdb変数を独自のオブジェクトに入れ替えて、そのオブジェクトでSQLをSQL Serverで実行できる形に変換するということを行っています。
MySQLとSQL ServerではSQLの記述方法が異なる場合があり、たとえば最後に挿入した行のIDを取得する方法はMySQLではLAST_INSERT_ID()ですが、SQL Serverでは@@IDENTITYです。その他LIMITがTOPだったりと色々と差があるのですが、これらを逐一変換するという実に面倒なことを行っています。
それらの変換が必要なパターンのうちSUM(visit)のようなSELECT文に計算式が指定されるパターンが漏れているようです。
とはいえWordPress本体には記事の件数表示があるのでCOUNT(*)などにも対応していないとは考えずらいので該当する処理を探したところ、以下のようにCOUNT()にだけ対応したコードがありました。
// Computed
// This is done as the SQLSRV driver doesn't seem to set a property value for computed
// selected columns, thus WP doesn't have anything to work with.
if (!preg_match('/COUNT\((.*?)\) as/i', $query)) {
$query = preg_replace('/COUNT\((.*?)\)/i', 'COUNT(\1) as Computed', $query);
}
この処理からすると、MySQL用のPDOドライバが計算式にComputedという別名を自動的に付けるという挙動にWordPressが依存しているということなのでしょうか。
解決方法
以下のようにSUM関数も置換対象になるように修正すれば動作するようになります。
// Computed
// This is done as the SQLSRV driver doesn't seem to set a property value for computed
// selected columns, thus WP doesn't have anything to work with.
if (!preg_match('/(COUNT|SUM)\((.*?)\) as/i', $query)) {
$query = preg_replace('/(COUNT|SUM)\((.*?)\)/i', '\1(\2) as Computed', $query);
}