Moodle
dml_read_exception
Stack frames (8)
7
dml_read_exception
…/public/lib/dml/moodle_database.php:496
6
moodle_database
query_end
…/public/lib/dml/moodle_read_replica_trait.php:377
5
mysqli_native_moodle_database
query_end
…/public/lib/dml/mysqli_native_moodle_database.php:1364
4
mysqli_native_moodle_database
get_records_sql
…/public/course/classes/category.php:1190
3
core_course_category
get_course_records
…/public/course/classes/category.php:1874
2
core_course_category
get_courses
…/public/course/renderer.php:1349
1
core_course_renderer
frontpage_available_courses
…/public/course/renderer.php:1618
0
core_course_renderer
frontpage
…/public/index.php:168
/mnt/drive/sites/moodlemain/public/lib/dml/moodle_database.php
// free memory
$this->last_sql = null;
$this->last_params = null;
$this->print_debug_time();
return;
}
// remember current info, log queries may alter it
$type = $this->last_type;
$sql = $this->last_sql;
$params = $this->last_params;
$error = $this->get_last_error();
$this->query_log($error);
switch ($type) {
case SQL_QUERY_SELECT:
case SQL_QUERY_AUX:
case SQL_QUERY_AUX_READONLY:
throw new dml_read_exception($error, $sql, $params);
case SQL_QUERY_INSERT:
case SQL_QUERY_UPDATE:
throw new dml_write_exception($error, $sql, $params);
case SQL_QUERY_STRUCTURE:
$this->get_manager(); // includes ddl exceptions classes ;-)
throw new ddl_change_structure_exception($error, $sql);
}
}
/**
* This logs the last query based on 'logall', 'logslow' and 'logerrors' options configured via $CFG->dboptions .
* @param string|bool $error or false if not error
* @return void
*/
public function query_log($error=false) {
// Logging disabled by the driver.
if ($this->skiplogging) {
return;
}
More info
https://docs.moodle.org/503/en/error/moodle/dmlreadexception
/mnt/drive/sites/moodlemain/public/lib/dml/moodle_read_replica_trait.php
parent::query_start($sql, $params, $type, $extrainfo);
$this->select_db_handle($type, $sql);
}
/**
* This should be called immediately after each db query. It does a clean up of resources.
*
* @param mixed $result The db specific result obtained from running a query.
*/
protected function query_end($result) {
if ($this->written) {
// Adjust the written time.
array_walk($this->written, function (&$val) {
if ($val === true) {
$val = microtime(true);
}
});
}
parent::query_end($result);
}
/**
* Select appropriate db handle - readwrite or readonly.
*
* @param int $type Type of query.
* @param string $sql The sql to use.
*/
protected function select_db_handle(int $type, string $sql): void {
if ($this->dbhreadonly && $this->can_use_readonly($type, $sql)) {
$this->readsreplica++;
$this->set_db_handle($this->dbhreadonly);
return;
}
$this->set_dbhwrite();
}
/**
* Check if The query qualifies for readonly connection execution.
*
/mnt/drive/sites/moodlemain/public/lib/dml/mysqli_native_moodle_database.php
* @return array of objects, or empty array if no records were found
* @throws dml_exception A DML specific exception is thrown for any errors.
*/
public function get_records_sql($sql, ?array $params=null, $limitfrom=0, $limitnum=0) {
list($limitfrom, $limitnum) = $this->normalise_limit_from_num($limitfrom, $limitnum);
if ($limitfrom or $limitnum) {
if ($limitnum < 1) {
$limitnum = "18446744073709551615";
}
$sql .= " LIMIT $limitfrom, $limitnum";
}
list($sql, $params, $type) = $this->fix_sql_params($sql, $params);
$rawsql = $this->emulate_bound_params($sql, $params);
$this->query_start($sql, $params, SQL_QUERY_SELECT);
$result = $this->mysqli->query($rawsql, MYSQLI_STORE_RESULT);
$this->query_end($result);
$return = array();
while($row = $result->fetch_assoc()) {
$row = array_change_key_case($row, CASE_LOWER);
$id = reset($row);
if (isset($return[$id])) {
$colname = key($row);
debugging("Did you remember to make the first column something unique in your call to get_records? Duplicate value '$id' found in column '$colname'.", DEBUG_DEVELOPER);
}
$return[$id] = (object)$row;
}
$result->close();
return $return;
}
/**
* Selects records and return values (first field) as an array using a SQL statement.
*
/mnt/drive/sites/moodlemain/public/course/classes/category.php
* on not visible courses and 'moodle/category:viewcourselist' on all courses
* @return array array of stdClass objects
*/
protected static function get_course_records($whereclause, $params, $options, $checkvisibility = false) {
global $DB;
$ctxselect = context_helper::get_preload_record_columns_sql('ctx');
$fields = array('c.id', 'c.category', 'c.sortorder',
'c.shortname', 'c.fullname', 'c.idnumber',
'c.startdate', 'c.enddate', 'c.visible', 'c.cacherev', 'c.deletioninprogress');
if (!empty($options['summary'])) {
$fields[] = 'c.summary';
$fields[] = 'c.summaryformat';
} else {
$fields[] = $DB->sql_substr('c.summary', 1, 1). ' as hassummary';
}
$sql = "SELECT ". join(',', $fields). ", $ctxselect
FROM {course} c
JOIN {context} ctx ON c.id = ctx.instanceid AND ctx.contextlevel = :contextcourse
WHERE ". $whereclause." ORDER BY c.sortorder";
$list = $DB->get_records_sql($sql,
array('contextcourse' => CONTEXT_COURSE) + $params);
if ($checkvisibility) {
$mycourses = enrol_get_my_courses();
// Loop through all records and make sure we only return the courses accessible by user.
foreach ($list as $course) {
if (isset($list[$course->id]->hassummary)) {
$list[$course->id]->hassummary = strlen($list[$course->id]->hassummary) > 0;
}
context_helper::preload_from_record($course);
$context = context_course::instance($course->id);
// Check that course is accessible by user.
if (!array_key_exists($course->id, $mycourses) && !self::can_view_course_info($course)) {
unset($list[$course->id]);
}
}
}
return $list;
}
/mnt/drive/sites/moodlemain/public/course/classes/category.php
}
}
return $courses;
}
// Retrieve list of courses in category.
$where = 'c.id <> :siteid';
$params = array('siteid' => SITEID);
if ($recursive) {
if ($this->id) {
$context = context_coursecat::instance($this->id);
$where .= ' AND ctx.path like :path';
$params['path'] = $context->path. '/%';
}
} else {
$where .= ' AND c.category = :categoryid';
$params['categoryid'] = $this->id;
}
// Get list of courses without preloaded coursecontacts because we don't need them for every course.
$list = $this->get_course_records($where, $params, array_diff_key($options, array('coursecontacts' => 1)), true);
// Sort and cache list.
self::sort_records($list, $sortfields);
$coursecatcache->set($cachekey, array_keys($list));
$coursecatcache->set($cntcachekey, count($list));
// Apply offset/limit, convert to core_course_list_element and return.
$courses = array();
if (isset($list)) {
if ($offset || $limit) {
$list = array_slice($list, $offset, $limit, true);
}
// Preload course contacts if necessary - saves DB queries later to do it for each course separately.
if (!empty($options['coursecontacts'])) {
self::preload_course_contacts($list);
}
// Preload custom fields if necessary - saves DB queries later to do it for each course separately.
if (!empty($options['customfields'])) {
self::preload_custom_fields($list);
}
/mnt/drive/sites/moodlemain/public/course/renderer.php
}
/**
* Returns HTML to print list of available courses for the frontpage
*
* @return string
*/
public function frontpage_available_courses() {
global $CFG;
$chelper = new coursecat_helper();
$chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED)->
set_courses_display_options(array(
'recursive' => true,
'limit' => $CFG->frontpagecourselimit,
'viewmoreurl' => new moodle_url('/course/index.php'),
'viewmoretext' => new lang_string('fulllistofcourses')));
$chelper->set_attributes(array('class' => 'frontpage-course-list-all'));
$courses = core_course_category::top()->get_courses($chelper->get_courses_display_options());
$totalcount = core_course_category::top()->get_courses_count($chelper->get_courses_display_options());
if (!$totalcount && !$this->page->user_is_editing() && has_capability('moodle/course:create', context_system::instance())) {
// Print link to create a new course, for the 1st available category.
return $this->add_new_course_button();
}
return $this->coursecat_courses($chelper, $courses, $totalcount);
}
/**
* Returns HTML to the "add new course" button for the page
*
* @return string
*/
public function add_new_course_button() {
global $CFG;
// Print link to create a new course, for the 1st available category.
$output = $this->container_start('buttons');
$url = new moodle_url('/course/edit.php', array('category' => $CFG->defaultrequestcategory, 'returnto' => 'topcat'));
$output .= $this->single_button($url, get_string('addnewcourse'), 'get');
$output .= $this->container_end('buttons');
/mnt/drive/sites/moodlemain/public/course/renderer.php
require_once($CFG->dirroot .'/mod/forum/lib.php');
if (($newsforum = forum_get_course_forum($SITE->id, 'news')) &&
($forumcontents = $this->frontpage_news($newsforum))) {
$newsforumcm = get_fast_modinfo($SITE)->instances['forum'][$newsforum->id];
$output .= $this->frontpage_part('skipsitenews', 'site-news-forum',
$newsforumcm->get_formatted_name(), $forumcontents);
}
}
break;
case FRONTPAGEENROLLEDCOURSELIST:
$mycourseshtml = $this->frontpage_my_courses();
if (!empty($mycourseshtml)) {
$output .= $this->frontpage_part('skipmycourses', 'frontpage-course-list',
get_string('mycourses'), $mycourseshtml);
}
break;
case FRONTPAGEALLCOURSELIST:
$availablecourseshtml = $this->frontpage_available_courses();
$output .= $this->frontpage_part('skipavailablecourses', 'frontpage-available-course-list',
get_string('availablecourses'), $availablecourseshtml);
break;
case FRONTPAGECATEGORYNAMES:
$output .= $this->frontpage_part('skipcategories', 'frontpage-category-names',
get_string('categories'), $this->frontpage_categories_list());
break;
case FRONTPAGECATEGORYCOMBO:
$output .= $this->frontpage_part('skipcourses', 'frontpage-category-combo',
get_string('courses'), $this->frontpage_combo_list());
break;
case FRONTPAGECOURSESEARCH:
$output .= $this->box($this->course_search_form(''), 'd-flex justify-content-center');
break;
}
$output .= '<br />';
/mnt/drive/sites/moodlemain/public/index.php
$editbutton = $OUTPUT->edit_button($editurl);
$PAGE->set_button($editbutton);
}
echo $OUTPUT->header();
// Print Section or custom info.
if (!empty($CFG->customfrontpageinclude)) {
// Pre-fill some variables that custom front page might use.
$modnames = get_module_types_names();
$modnamesplural = get_module_types_names(true);
$mods = $modinfo->get_cms();
include($CFG->customfrontpageinclude);
} else if ($siteformatoptions['numsections'] > 0) {
echo $courserenderer->frontpage_section1();
}
echo $courserenderer->frontpage();
if ($editing && has_capability('moodle/course:create', context_system::instance())) {
echo $courserenderer->add_new_course_button();
}
echo $OUTPUT->footer();
Environment & details:
empty
empty
empty
empty
| Key | Value |
| USER | stdClass Object ( [id] => 0 [mnethostid] => 1 [sesskey] => xxOaIBLQyl [access] => Array ( [ra] => Array ( [/1] => Array ( [6] => 6 ) ) [time] => 1789808704 [rsw] => Array ( ) ) [enrol] => Array ( [enrolled] => Array ( ) [tempguest] => Array ( ) ) [preference] => Array ( ) ) |
| SESSION | stdClass Object ( [isnewsessioncookie] => 1 [cachestore_session] => Array ( [default_session-core/navigation_cache] => Array ( [__lastaccess__u0_6b8207372ea3882cbefd594f698f6bfd] => Array ( [0] => 1789808704 [1] => 1789808704 ) ) [default_session-core/coursecat] => Array ( [__lastaccess__u0_6b8207372ea3882cbefd594f698f6bfd] => Array ( [0] => 1789808704 [1] => 1789808704 ) [u0_6b8207372ea3882cbefd594f698f6bfd_b6402f52910e737d01e269d2e0c76e5edbe22a7b] => Array ( [0] => 1789808704.6409-6aae50409c78a9.31672544 [1] => 1789808704 ) [u0_6b8207372ea3882cbefd594f698f6bfd_e4c5232a522e1e84d57a96195a9e6a0ee4d7af21] => Array ( [0] => Array ( ) [1] => 1789808704 ) [u0_6b8207372ea3882cbefd594f698f6bfd_c87ed668297b046343bbf5c6bb2aefba0c0e98d2] => Array ( [0] => Array ( [0] => 1 ) [1] => 1789808704 ) ) ) ) |
| Key | Value |
| USER | www-data |
| HOME | /var/www |
| SCRIPT_NAME | /moodlemain/index.php |
| REQUEST_URI | /moodlemain/ |
| QUERY_STRING | |
| REQUEST_METHOD | GET |
| SERVER_PROTOCOL | HTTP/1.1 |
| GATEWAY_INTERFACE | CGI/1.1 |
| REMOTE_PORT | 56118 |
| SCRIPT_FILENAME | /mnt/drive/sites/moodlemain/public/index.php |
| SERVER_ADMIN | [no address given] |
| CONTEXT_DOCUMENT_ROOT | /mnt/drive/sites/moodlemain/public |
| CONTEXT_PREFIX | /moodlemain |
| REQUEST_SCHEME | https |
| DOCUMENT_ROOT | /mnt/drive/sites/ |
| REMOTE_ADDR | 216.73.216.246 |
| SERVER_PORT | 443 |
| SERVER_ADDR | 57.129.32.129 |
| SERVER_NAME | test.blabs.ie |
| SERVER_SOFTWARE | Apache/2.4.58 (Ubuntu) |
| SERVER_SIGNATURE | <address>Apache/2.4.58 (Ubuntu) Server at test.blabs.ie Port 443</address> |
| PATH | /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/snap/bin |
| HTTP_HOST | test.blabs.ie |
| HTTP_ACCEPT_ENCODING | gzip, br, zstd, deflate |
| HTTP_USER_AGENT | Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com) |
| HTTP_ACCEPT | */* |
| proxy-nokeepalive | 1 |
| SSL_TLS_SNI | test.blabs.ie |
| HTTPS | on |
| FCGI_ROLE | RESPONDER |
| PHP_SELF | /moodlemain/index.php |
| REQUEST_TIME_FLOAT | 1789808704.5709 |
| REQUEST_TIME | 1789808704 |
empty
0. Whoops\Handler\PrettyPageHandler
1. Whoops\Handler\CallbackHandler