-
Bug
-
Resolution: Unresolved
-
Major
-
4.4 regressions, 4.4.6, 4.5 regressions
Forums have an overview page that shows the author and date of the first / last post in each discussion. We noticed that the last post author and date is often incorrect for discussions with multiple posts.
We tracked the issue to commit https://github.com/moodle/moodle/commit/0f5a96ff3e3aa1ab44b43b8b9a001e520acda764, which was part of https://tracker.moodle.org/browse/MDL-80848
Steps to reproduce:
1. Create a course
2. Enrol two users to the course: A and B
3. Create a regular forum in this course
4. Create multiple discussions in this forum
5. Add multiple replies to these discussions as users A and B
6. Observe the forum overview page. At some point you might notice that the "Last post" (or sometimes even the "Started by") user is incorrect.
Unfortunately, this problem is tricky to reproduce, as it relies on the DB returning records in non-deterministic order. This is why you need multiple discussions in the same forum, the problem doesn't seem to appear with only one discussion. But again, this depends heavily on how the DB engine decides to execute the query. We use PostgreSQL.
But conceptually the issue is simple. This was the query in the get_latest_posts_for_discussion_ids method in mod/forum/classes/local/vaults/post.php:
SELECT posts.* |
FROM mdl_forum_posts posts |
JOIN ( |
SELECT p.discussion, MAX(p.id) as latestpostid |
FROM mdl_forum_posts p |
JOIN ( |
SELECT mp.discussion, MAX(mp.created) AS created |
FROM mdl_forum_posts mp |
WHERE mp.discussion IN :discussionids |
GROUP BY mp.discussion |
) lp ON lp.discussion = p.discussion AND lp.created = p.created |
GROUP BY p.discussion |
) plp on plp.discussion = posts.discussion AND plp.latestpostid = posts.id; |
Which got replaced by this:
SELECT p.* |
FROM mdl_forum_posts p |
JOIN ( |
SELECT mp.discussion, mp.created, MAX(mp.id) AS latestpostid |
FROM mdl_forum_posts mp |
WHERE mp.discussion IN :discussionids |
GROUP BY mp.discussion, mp.created |
HAVING mp.created = MAX(mp.created) |
) lp on lp.discussion = p.discussion AND lp.latestpostid = p.id; |
(Code formatted and simplified for readability.)
The second version tried to simplify the logic into one subselect instead of doubly nested subselects, but misunderstands how HAVING works. (The aggregating functions like MAX are computed per group, so HAVING column = MAX(column) is always satisfied if the column is part of the GROUP BY.)
So, while the original query returned one post per discussion (the latest), the new query basically returns all the posts in the discussions (it only filters out posts if there are multiple posts in a discussion with exactly the same created), and now it matters in which orders the records are returned.
- has been marked as being related by
-
MDLSITE-7967 Last post date/poster wrong in community forums
-
- Closed
-
- is a regression caused by
-
MDL-80848 Forum code does not handle things happening at the same time well
-
- Closed
-
- is duplicated by
-
MDL-85522 Random failure on "test_get_first_post_for_discussion_ids"
-
- Closed
-