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に今回の問題を持ちかけて,一緒に議論しながら解決した。その際のやりとりを掲載する。

[22:09:36] <senooken> Hi. I am sorry. Now I post some messages for my 2.0-dev error.
[22:09:48] <senooken> I failed to trying GNU social v2.0-dev for
using ActivityPub (AP) on February. But recently I found colegota use
2.0-dev in #123 issue (I am watching giogo/gnu-social).
[22:10:05] <senooken> So I try 2.0-dev again
(https://social.senooken.jp/senooken) (at 4/7 latest commit
e58188d13640721d2da866bfbab9c036df7acb5d). I think nearly OK. But I have
following DB error in accessing home timeline
(https://social.senooken.jp/senooken/all).
[22:10:22] <senooken> [Notice] DB_DataObject error []: DB Error: syntax error
[22:10:29] *** diogo has left the room
[22:10:34] *** diogo has joined the room as a participant
[22:10:35] <senooken> I investigated this error for a these days. Following SQL has syntax error.

[22:10:44] <senooken> 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

[22:10:57] <senooken> 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 1
[22:11:08] <senooken> I found 2.0-dev needs MariaDB 10.3+ in
INSTALL.md (f67a93eddce8120a26ed15a5559bdf08d190a04c). My rental server
has MySQL 5.7!
[22:11:16] <senooken> I like GNU social for using rental server
like WordPress. MariaDB 10.3 is compatible MySQL 8.0. But many rental
servers do not support MySQL 8.0. Almost rental server support MySQL
5.6/MariaDB 10.1 for WordPress requirements
(https://wordpress.org/about/requirements/).

[22:11:26] <senooken> How do I resolve this problem? Can anyone
familier with latest SQL? Can I use latest ActivityPub plugin on
v1.20.9? Or revert commit (f67a93eddce8120a26ed15a5559bdf08d190a04c)?
[22:11:32] <senooken> Why 2.0-dev requires MariaDB 10.3? Would you
like to use MySQL 5.6/MariaDB 10.1 same as WordPress for many rental
servers?

[22:11:54] <senooken> Thats’s all. Sorry for my long post.

最初の投稿

[22:40:52] <diogo> just checked the changelog from mariadb 10.1 to 10.3
[22:41:15] <diogo> I honestly don’t think we use anything that’s only available in 10.3
[22:41:26] <diogo> Reading the error you caught now…
[22:49:45] <senooken> >diogo. Thanks reply. I am trying investigate this error also. I will let you know.
[22:49:58] <irc> [includeals] okay, it clearly works in my mariadb – weird
[22:50:09] <irc> [includeals] changelog for 10.2: https://mariadb.com/kb/en/changes-improvements-in-mariadb-102/
[22:50:15] <irc> [includeals] changelog for 10.3: https://mariadb.com/kb/en/changes-improvements-in-mariadb-103/

互換性の確認

[23:02:09] <senooken> I am try this SQL in phpMyAdmin.
‘NATURAL’ keyword was invalid. MySQL 5.7 does not allow NATURAL in this
context (https://dev.mysql.com/doc/refman/5.7/en/select.html). And
query has some errors in INNER JOIN yet.
[23:12:25] <senooken> Hi. I found. Fix `NATURAL INNER JOIN` to
`NATURAL LEFT JOIN` (https://dev.mysql.com/doc/refman/5.7/en/join.html).
This query is OK in phpMyAdmin. I try to fix my gnusocial code.
[23:18:51] <senooken> lib/notices/inboxnoticestream.php
getNoticeIds() has this query. Fix query, then work done!
(https://social.senooken.jp/senooken/all). Sorry for bother. Afterwards,
I check when `NATURAL INNER JOIN` is committed.

[23:23:42] <XRevan86> LEFT JOIN != INNER JOIN
[23:27:29] <senooken> From MySQL 8.0, `NATURAL INNER` is allowed
(https://dev.mysql.com/doc/refman/8.0/en/join.html). I am continuing to
check MariaDB reference.
[23:28:55] <XRevan86> Okay, fine, I pushed the thing %)
[23:29:23] <XRevan86> senooken: https://notabug.org/diogo/gnu-social/commit/42aa2551
[23:29:32] *** diogo has left the room
[23:29:37] *** diogo has joined the room as a participant
[23:31:28] <senooken> XRevan86. Thanks. I will check it my server.
It seemes MariaDB also does not allow NATURAL INNER (https://mariadb.com/kb/en/join-syntax/)?
[23:31:29] <XRevan86> senooken: A NATURAL JOIN isn’t really necessary here. And I no longer even like the idea.
[23:31:51] <XRevan86> senooken: It obviously worked 🙂
[23:33:12] <XRevan86> senooken: I’ve checked ISO SQL, NATURAL INNER JOIN is legal.
[23:33:19] <XRevan86> > NATURAL [{LEFT|RIGHT} [OUTER]] JOIN table_factor
[23:33:35] <XRevan86> But indeed in the docs it doesn’t look like they’ve thought of accepting INNER here.
[23:33:42] *** argentux has joined the room as a participant
[23:34:02] <XRevan86> senooken: An unprefixed JOIN is an INNER JOIN, by the way.
[23:34:32] <XRevan86> Implicitly
[23:34:53] <XRevan86> senooken: So you could’ve made it work by changing it to “NATURAL JOIN”
[23:35:11] <XRevan86> But no matter, I changed it to INNER JOIN USING
[23:41:45] <senooken> Xrevan86. I applied your commit in my server. It seems work done. Thanks!

解決

結論

GNU social v2.0-devでのバグへの対応過程を掲載した。XMPPのチャット上のやり取りはどこにも記録されず,今回はissueやPull Requestに入る前に担当者のコミットで解決したため,経緯が一切残らない。

自分の頑張りもなかったようになってしまう。問題が解決したので,まあいいのだけど,もったいないので,過程を記すことにした。

なんだかんだで解決に2-3日かかったのだが,解決してよかった。調査の過程でGNU socialの作りの理解も深まったので,また問題を解決していきたい。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です