/**
  * Creates the mail queue and runs query to obtain list of posts that should
  * be mailed.
  * @param bool $tracetimes True if it should call mtrace to display
  *   performance information
  */
 function __construct($tracetimes)
 {
     global $CFG;
     $this->time = time();
     $this->forum = null;
     $this->discussion = null;
     $this->storedrecord = null;
     $this->postcount = 0;
     // Check if an earlier run got aborted. In that case we mark all
     // messages as mailed anyway because it's better to skip some than
     // to send out double-posts.
     if ($pending = get_config('forumng', $this->get_pending_flag_name())) {
         $this->mark_mailed($pending);
     }
     // Note that we are mid-run
     set_config($this->get_pending_flag_name(), $this->time, 'forumng');
     $querychunk = $this->get_query_chunk($this->time);
     if (!($this->rs = get_recordset_sql($sql = "\nSELECT\n    " . forum_utils::select_forum_fields('f') . ",\n    " . forum_utils::select_discussion_fields('fd') . ",\n    " . forum_utils::select_post_fields('discussionpost') . ",\n    " . forum_utils::select_post_fields('fp') . ",\n    " . forum_utils::select_post_fields('reply') . ",\n    " . forum_utils::select_course_module_fields('cm') . ",\n    " . forum_utils::select_context_fields('x') . ",\n    " . forum_utils::select_username_fields('u', true) . ",\n    " . forum_utils::select_username_fields('eu') . ",\n    " . forum_utils::select_username_fields('replyu') . ",\n    " . forum_utils::select_username_fields('replyeu') . ",\n    " . forum_utils::select_course_fields('c') . ",\n    clonecm.id AS cloneid\n{$querychunk}\nORDER BY\n    clonecm.course, f.id, fd.id, fp.id"))) {
         throw new forum_exception("Mail queue query failed");
     }
 }
 /**
  * Internal function. Queries for posts.
  * @param string $where Where clause (fp is alias for post table)
  * @param string $order Sort order; the default is fp.id - note this is preferable
  *   to fp.timecreated because it works correctly if there are two posts in
  *   the same second
  * @param bool $ratings True if ratings should be included in the query
  * @param bool $flags True if flags should be included in the query
  * @param bool $effectivesubjects True if the query should include the
  *   (complicated!) logic to obtain the 'effective subject'. This may result
  *   in additional queries afterward for posts which are very deeply nested.
  * @param int $userid 0 = current user (at present this is only used for
  *   flags)
  * @return array Resulting posts as array of Moodle records, empty array
  *   if none
  */
 static function query_posts($where, $order = 'fp.id', $ratings = true, $flags = false, $effectivesubjects = false, $userid = 0, $joindiscussion = false, $discussionsubject = false, $limitfrom = '', $limitnum = '')
 {
     global $CFG, $USER;
     $userid = forum_utils::get_real_userid($userid);
     // We include ratings if these are enabled, otherwise save the database
     // some effort and don't bother
     if ($ratings) {
         $ratingsquery = ",\n(SELECT AVG(rating) FROM {$CFG->prefix}forumng_ratings\n    WHERE postid=fp.id) AS averagerating,\n(SELECT COUNT(1) FROM {$CFG->prefix}forumng_ratings\n    WHERE postid=fp.id) AS numratings,\n(SELECT rating FROM {$CFG->prefix}forumng_ratings\n    WHERE postid=fp.id AND userid={$USER->id}) AS ownrating";
     } else {
         $ratingsquery = '';
     }
     if ($flags) {
         $flagsjoin = "\n    LEFT JOIN {$CFG->prefix}forumng_flags ff ON ff.postid = fp.id AND ff.userid = {$userid}";
         $flagsquery = ",ff.flagged";
     } else {
         $flagsjoin = '';
         $flagsquery = '';
     }
     if ($joindiscussion) {
         $discussionjoin = "\n    INNER JOIN {$CFG->prefix}forumng_discussions fd ON fp.discussionid = fd.id";
         $discussionquery = ',' . forum_utils::select_discussion_fields('fd');
         if ($discussionsubject) {
             $discussionjoin .= "\n    INNER JOIN {$CFG->prefix}forumng_posts fdfp ON fd.postid = fdfp.id";
             $discussionquery .= ', fdfp.subject AS fd_subject';
         }
     } else {
         $discussionjoin = '';
         $discussionquery = '';
     }
     if ($effectivesubjects) {
         $maxdepth = self::PARENTPOST_DEPTH_PER_QUERY;
         $subjectsjoin = '';
         $subjectsquery = ", p{$maxdepth}.parentpostid AS nextparent ";
         for ($depth = 2; $depth <= $maxdepth; $depth++) {
             $subjectsquery .= ", p{$depth}.subject AS s{$depth}, p{$depth}.deleted AS d{$depth}";
             $prev = 'p' . ($depth - 1);
             if ($prev == 'p1') {
                 $prev = 'fp';
             }
             $subjectsjoin .= "LEFT JOIN {$CFG->prefix}forumng_posts p{$depth}\n                    ON p{$depth}.id = {$prev}.parentpostid ";
         }
     } else {
         $subjectsjoin = '';
         $subjectsquery = '';
     }
     // Retrieve posts from discussion with incorporated user information
     // and ratings info if specified
     $results = forum_utils::get_records_sql("\nSELECT\n    fp.*,\n    " . forum_utils::select_username_fields('u') . ",\n    " . forum_utils::select_username_fields('eu') . ",\n    " . forum_utils::select_username_fields('du') . "\n    {$ratingsquery}\n    {$flagsquery}\n    {$subjectsquery}\n    {$discussionquery}\nFROM\n    {$CFG->prefix}forumng_posts fp\n    INNER JOIN {$CFG->prefix}user u ON fp.userid=u.id\n    LEFT JOIN {$CFG->prefix}user eu ON fp.edituserid=eu.id\n    LEFT JOIN {$CFG->prefix}user du ON fp.deleteuserid=du.id    \n    {$discussionjoin}\n    {$flagsjoin}\n    {$subjectsjoin}\nWHERE\n    {$where}\nORDER BY\n    {$order}\n", $limitfrom, $limitnum);
     if ($effectivesubjects) {
         // Figure out the effective subject for each result
         foreach ($results as $result) {
             $got = false;
             if ($result->subject !== null) {
                 $result->effectivesubject = $result->subject;
                 $got = true;
                 continue;
             }
             for ($depth = 2; $depth <= $maxdepth; $depth++) {
                 $var = "s{$depth}";
                 $var2 = "d{$depth}";
                 if (!$got && $result->{$var} !== null && $result->{$var2} == 0) {
                     $result->effectivesubject = get_string('re', 'forumng', $result->{$var});
                     $got = true;
                 }
                 unset($result->{$var});
                 unset($result->{$var2});
             }
             if (!$got) {
                 // Do extra queries to pick up subjects for posts where it
                 // was unknown within the default depth. We can use the
                 // 'nextparent' to get the ID of the parent post of the last
                 // one that we checked already
                 $result->effectivesubject = self::inner_get_recursive_subject($result->nextparent);
             }
         }
     }
     return $results;
 }