GNU social v2.0-devでのホーム画面へのアクセス時のDBエラーの対処
自分のGNU socialをGNU social v2.0-devにバージョンアップしてホーム画面にアクセスするとDBエラーが発生した。既にこちらのコミットで解決済みだが,このコミットがなされるまでの経緯がどこにも残らないのが悲しいので,今後のために記録する。
導入
2020-04-07 TueにコミットされたGNU social v2.0-dev (e58188d13640721d2da866bfbab9c036df7acb5d) をインストールして,ホーム画面を開くと以下のエラーが出た。
[Notice] DB_DataObject error []: DB Error: syntax error
ホーム画面という基本機能に関する問題で,重要なため調査した。
DBテーブルの確認
必要なモジュールが不足している可能性はないか?わからない。
ローカルにインストールしたものと,git diffの差分同士を比較してみると,同一だった。やはりDB関係の問題の可能性が高い。
昔インストールした古いActivityPubのデータが悪さしているのかも。
Activityと大文字で始まるテーブルは今は使っていないので削除した。
その他,ローカルでのインストール時と比べると以下のテーブルが多かった。
- notice_to_status
- ostatus_source
- searchsub
- twitter_synch_status
notice_to_statusとtwitter_synch_statusはTwitterBridgePlugin由来なので大丈夫。
searchsubはそういうプラグインがあった。ostatus_sourceだけ不明。
ostatus_sourceもsearch_subも空なので削除した。
エラー内容の確認
情報が少なくて原因を特定できないので,エラーを出している箇所を特定する。
画面に表示されたメッセージ内容から,DB Errorで検索すると,extlib/DB.phpがヒット。
function __construct($code = DB_ERROR, $mode = PEAR_ERROR_RETURN,
$level = E_USER_NOTICE, $debuginfo = null)
{
if (is_int($code)) {
parent::__construct('DB Error: ' . DB::errorMessage($code), $code,
$mode, $level, $debuginfo);
} else {
parent::__construct("DB Error: $code", DB_ERROR,
$mode, $level, $debuginfo);
}
}
ifの最初でヒットしている。強調したコードの直前に以下のコードを仕込んでスタックトレースを出力させる。
xdebug_print_function_stack( 'Your own message' );
さらに,php.iniに以下の設定もして,スタックトレースの関数の引数も表示させる。
xdebug.collect_params = 4
これを仕込んで情報が出た。
extlib/DB/mysqli.php:simpleQueryのqueryでエラーが出ていた。
DB_mysqli->raiseError(
$code = -2, $mode = NULL, $options = NULL, $userinfo = NULL, $nativecode = '1064
** You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version
for the right syntax to use near
\'INNER JOIN ((SELECT id FROM notice WHERE profile_id IN (SELECT subscribed FROM s\' at line 4',
$dummy1 = ???, $dummy2 = ??? )
INNER JOINのあたりでSQLの構文エラーになっているらしい。
クエリーの内容は以下のとおりだった。
SELECT id FROM `notice` NATURAL INNER JOIN ((SELECT id FROM notice WHERE profile_id IN (SELECT subscribed FROM subscription WHERE subscriber = 1)) UNION (SELECT notice_id AS id FROM reply WHERE profile_id = 1) UNION (SELECT notice_id AS id FROM attention WHERE profile_id = 1) UNION (SELECT notice_id AS id FROM group_inbox WHERE group_id IN (SELECT group_id FROM group_member WHERE profile_id = 1))) AS t1 WHERE ( notice.created > TIMESTAMP '2018-05-04 03:13:59' ) AND ( scope <> 16 ) ORDER BY id DESC LIMIT 0, 200
見やすく整形すると以下の通りだ。
'
SELECT id FROM `notice` NATURAL INNER JOIN (
(SELECT id FROM notice WHERE profile_id IN
(SELECT subscribed FROM subscription WHERE subscriber = 1)
)
UNION (SELECT notice_id AS id FROM reply WHERE profile_id = 1)
UNION (SELECT notice_id AS id FROM attention WHERE profile_id = 1)
UNION (SELECT notice_id AS id FROM group_inbox WHERE group_id IN
(SELECT group_id FROM group_member WHERE profile_id = 1)
)
) AS t1 WHERE ( notice.created > TIMESTAMP '2018-05-04 03:13:59' ) AND ( scope <> 16 ) ORDER BY id DESC LIMIT 0, 200
' (length=537)
対応
MySQLのバージョンの問題とか。使用しているCORESERVERはMySQL 5.7だ。
GNU social v2.0-devはMariaDB 10.3+がDBの要件になっている。これが原因か。
[f67a93eddce8120a26ed15a5559bdf08d190a04c] このコミットでMariaDB 10.3+の機能が必要になった。
MySQLは5.7が2023年までサポート。5.7互換にしてくれないかな。
MariaDB 10.2相当だと思うのだけど。WordPressがMySQL 5.6/MariaDB 10.1をサポートしている (Requirements | WordPress.org)。GNU socialも同じにしてくれないかな?
phpMyAdminで問題の発生したSQLを範囲を絞りながら試してみる。
SELECT id FROM `notice`
NATURAL INNER JOIN (
(SELECT id FROM notice WHERE profile_id IN
(SELECT subscribed FROM subscription WHERE subscriber = 1)
)
UNION (SELECT notice_id AS id FROM reply WHERE profile_id = 1)
UNION (SELECT notice_id AS id FROM attention WHERE profile_id = 1)
UNION (SELECT notice_id AS id FROM group_inbox WHERE group_id IN
(SELECT group_id FROM group_member WHERE profile_id = 1)
)
) AS t1
WHERE ( notice.created > TIMESTAMP '2018-05-04 03:13:59' ) AND ( scope <> 16 )
ORDER BY id DESC LIMIT 0, 200
以下のSQLは問題なかった。
SELECT id FROM `notice`
ORDER BY id DESC LIMIT 0, 200
以下を実行しようとすると問題。
SELECT id FROM `notice`
NATURAL INNER JOIN (
(SELECT id FROM notice WHERE profile_id IN
(SELECT subscribed FROM subscription WHERE subscriber = 1)
)
UNION (SELECT notice_id AS id FROM reply WHERE profile_id = 1)
UNION (SELECT notice_id AS id FROM attention WHERE profile_id = 1)
UNION (SELECT notice_id AS id FROM group_inbox WHERE group_id IN
(SELECT group_id FROM group_member WHERE profile_id = 1)
)
) AS t1
WHERE ( notice.created > TIMESTAMP '2018-05-04 03:13:59' ) AND ( scope <> 16 )
ORDER BY id DESC LIMIT 0, 200
MySQL 5.7ではNATURALがこの位置では使えない。「MySQL :: MySQL 5.7 Reference Manual :: 13.2.9 SELECT Statement」にあるとおり,公式リファレンスでも許可されていない。
NATURALを外してみる。
SELECT id FROM `notice`
INNER JOIN (
(SELECT id FROM notice WHERE profile_id IN
(SELECT subscribed FROM subscription WHERE subscriber = 1)
)
UNION (SELECT notice_id AS id FROM reply WHERE profile_id = 1)
UNION (SELECT notice_id AS id FROM attention WHERE profile_id = 1)
UNION (SELECT notice_id AS id FROM group_inbox WHERE group_id IN
(SELECT group_id FROM group_member WHERE profile_id = 1)
)
) AS t1
WHERE ( notice.created > TIMESTAMP '2018-05-04 03:13:59' ) AND ( scope <> 16 )
ORDER BY id DESC LIMIT 0, 200
#1052 - Column 'id' in field list is ambiguous
エラーが出た。やはり,NATURALがないのは問題あるのではないか。
NATURAL INNER JOINではなく,NATURAL LEFT JOINにしたら動作した (https://dev.mysql.com/doc/refman/5.7/en/join.html)。
ただ,ここのNATURALは本質的にはいらないので,最終的に,「[CORE] Re-format the inboxnoticestream query · 42aa255152 – NotABug.org: Free code hosting」のコミットで解決した。
XMPPでのやりとり
GNU social開発メンバーが参加しているチャット (xmpp:gnusocial@conference.bka.li) に,2020-04-13 Monに今回の問題を持ちかけて,一緒に議論しながら解決した。その際のやりとりを掲載する。
結論
GNU social v2.0-devでのバグへの対応過程を掲載した。XMPPのチャット上のやり取りはどこにも記録されず,今回はissueやPull Requestに入る前に担当者のコミットで解決したため,経緯が一切残らない。
自分の頑張りもなかったようになってしまう。問題が解決したので,まあいいのだけど,もったいないので,過程を記すことにした。
なんだかんだで解決に2-3日かかったのだが,解決してよかった。調査の過程でGNU socialの作りの理解も深まったので,また問題を解決していきたい。